任何事情的成功都須要掐準時間
上一節mongo EOF
中,關於容器的配置,只是粗略的使用了Docker-Compose-MongoDB-Replica-Set
項目提供好的docker-compose.yml
文件。在使用過程當中,我發現這個文件自己一些不如意的地方。首先,services
中的creator
服務,entrypoint
指令太長了,不美;其次,全部的service
都沒有給容器外部暴露端口,致使外部沒法訪問容器;再次,直接使用mongo repliSet
的鏈接串進行訪問,沒法正常訪問mongo
服務。 git
在上一篇文章的基礎上,這篇文章對docker-compse.yml
作了一些調整,而且也包含了docker
使用的入門介紹。更新後的docker-compose.yml
請訪問githubsi。github
However, for startup Compose does not wait until a container is 「ready」 (whatever that means for your particular application) - only until it’s running. There’s a good reason for this.
在creator service
中使用了該指令, 可是,實際中creator
不會等到mongo1
、mongo2
、mongo3
容器ready
後再啓動,而是等到它們啓動就開始啓動。這也是我在setup
腳本中執行sleep
操做的緣由。mongodb
creator: build: context: . dockerfile: dockerfile entrypoint: ["/data/conf/setup.sh"] depends_on: - mongo1 - mongo2 - mongo3
Entrypoint sets the command and parameters that will be executed first when a container is run.
entrypoint設置了容器啓動時執行的命令和參數,傳遞給docker run <image>
的參數都將追加到entrypoint
命令以後,而且會覆蓋CMD
命令。好比,docker run <image> bash
將會追加bash
到entrypoint
命令末尾。docker
命令的語法格式:shell
ENTRYPOINT ["executable" "param1" "param2"]
在修改後的docker-compose.yml
中,entrypoint
指令用於執行shell
腳本。按照規範來講,可執行文件名稱中須要包含entrypoint
字段,也就是將下列指令中的setup.sh
重命名爲setup-entrypoint.sh
。可是,重命名以後的文件,容器執行會報錯,因此,這裏也並無使用這個規範。bash
entrypoint: ["/data/conf/setup.sh"]
creator
中的entrypoint
指令原始的文件以下所示,entrypoint
指令的參數很是難看:app
creator: build: creator entrypoint: ["mongo","--host","mongo1","--port","27017","--eval", 'rs.initiate( { _id : "rs0",members: [{ _id: 0, host: "mongo1:27017" },{ _id: 1, host: "mongo2:27017" },{ _id: 2, host: "mongo3:27017" } ]})'] depends_on: - mongo1 - mongo2 - mongo3
若是將entrypoint
的執行命令提取到一個單獨的的腳本中,會讓整個頁面看起來更加簡潔。因此,新建一個setup.sh
文件。其中的replicaSet.js
用於執行rs.initiate
操做,詳情能夠查看github
項目。其中的sleep
指令只是爲了保證:在執行initiate
時mongo
的3個服務都啓動了。less
#! /bin/bash echo "******************************" echo Start the replica set echo `date` echo "******************************" sleep 20 | echo Sleeping echo `date` mongo mongodb://mongo1:37017 replicaSet.js
相應的,咱們須要調整creator
的dockerfile
文件,由於此時的容器內,並無咱們須要的相關文件。咱們須要在建立鏡像的時候,拷貝本地文件到容器。調整後的文件以下:測試
FROM mongo:4.0.4 MAINTAINER Yowko Tsai <yowko@yowko.com> WORKDIR /data/conf COPY ./setup.sh /data/conf/setup.sh COPY ./replicaSet.js /data/conf/replicaSet.js CMD ["./setup.sh"]
在項目的目錄下,咱們單獨編譯creator
的dockerfile
文件,已保證調整是有效的。ui
docker build . docker run <image>
以mongo1
爲例,在原始的文件中,docker-compose.yml
以下:
mongo1: container_name: mongo1 image: mongo:4-xenial expose: - 27017 restart: always entrypoint: [ "mongod", "--bind_ip_all", "--replSet", "rs0" ]
上面的配置,本地主機是沒法訪問容器的,咱們至少須要暴露出一個端口。下面經過添加ports
來指定容器外到容器內的端口映射。在上一篇中已經介紹過ports
和expose
的相關內容,感興趣的能夠去查看。以後,咱們就能夠經過37017端口來訪問容器內的mongo1
服務了。
mongo1: container_name: mongo1 image: mongo:4.0.4 expose: - 37017 ports: - "37017:37017" restart: always entrypoint: [ "mongod", "--port", "37017", "--bind_ip_all", "--replSet", "rs0" ]
查看Default MongoDB Port,mongod
的默認端口實際上是27017,而這裏寫成37017也是有緣由的。未修改以前mongod
的端口映射,以下所示。每一個容器中的mongo
服務都使用默認的27017端口,經過暴露不通的宿主主機端口來達到區分容器服務的目的。
mongo1: container_name: mongo1 image: mongo:4.0.4 expose: - 27017 ports: - "27017:27017" restart: always entrypoint: [ "mongod", "--bind_ip_all", "--replSet", "rs0" ] mongo2: container_name: mongo2 image: mongo:4.0.4 expose: - 27017 ports: - "27018:27017" restart: always entrypoint: [ "mongod", "--bind_ip_all", "--replSet", "rs0" ] mongo3: container_name: mongo3 image: mongo:4.0.4 expose: - 27017 ports: - "27019:27017" restart: always entrypoint: [ "mongod", "--bind_ip_all", "--replSet", "rs0" ]
在單獨鏈接mongo
服務的時候,這樣的配置是沒有任何問題的。咱們在命令行輸入mongo
,也會鏈接到其中任意一個mongo
服務。若是剛好鏈接的不是PRIMARY
節點,能夠執行rs.slaveOk()
來執行查詢。
但當使用replicaSet
鏈接串來訪問mongo
服務時,鏈接卻會失敗。看看這個鏈接串,感受不出任何問題。
mongo mongodb://127.0.0.1:27017,127.0.0.1:27018,127.0.0.1:27019/admin?replicaSet=rs0
看了報錯信息,才明白:當執行鏈接的時候,mongo
會拉取replica set
的配置信息,而經過host
去訪問的時候失敗了。很明顯:docker-compose
容器內能夠將server name
看成host
來相互訪問,但在容器外經過server name
是訪問不通的。
changing hosts to rs0/mongo1:27017,mongo2:27017,mongo3:27017 from rs0/127.0.0.1:27017,127.0.0.1:27018,127.0.0.1:27019
另外,你還能夠在容器內部打開/etc/hosts
文件,查看容器內映射的ip地址,容器外也是ping不通的。咱們能夠經過下面的指令進入容器查看:
docker exec -it <container-id> bash less /etc/hosts
解決的辦法是,咱們在本地主機上追加host
。但這樣的話,rs0
其實只有一個節點,由於都映射到了127.0.0.1:27017
這個容器上。
# file: /etc/hosts 127.0.0.1 mongo1, mongo2, mongo3
基於這個緣由,咱們修改了容器內外暴露的端口。同時,修改各個服務mongod
啓動時的默認端口以及replica set
的配置信息:
mongo1: container_name: mongo1 image: mongo:4.0.4 expose: - 37017 ports: - "37017:37017" restart: always entrypoint: [ "mongod", "--port", "37017", "--bind_ip_all", "--replSet", "rs0" ] mongo2: container_name: mongo2 image: mongo:4.0.4 expose: - 37018 ports: - "37018:37018" restart: always entrypoint: [ "mongod", "--port", "37018", "--bind_ip_all", "--replSet", "rs0" ] mongo3: container_name: mongo3 image: mongo:4.0.4 expose: - 37019 ports: - "37019:37019" restart: always entrypoint: [ "mongod", "--port", "37019", "--bind_ip_all", "--replSet", "rs0" ]
// file :replicaSet.js rsconf = { _id: "rs0", members: [ {_id: 0, host: "mongo1:37017"}, {_id: 1, host: "mongo2:37018"}, {_id: 2, host: "mongo3:37019"} ] } rs.initiate(rsconf); rs.conf();
作了這些修改,咱們就能夠正常訪問mongo
服務了:
mongo mongodb://mongo1:37017,mongo2:37018,mongo3:37019/admin?replicaSet=rs0
首先,咱們看看鏡像能不能順利編譯過去:
docker-compose -f docker-compose.yml build
其次,咱們啓動容器服務:
docker-compose -f docker-compose.yml up
最後,關閉容器服務。這個命令至關於依次執行docker container stop
、docker-compose down
,很方便。
docker-compose -f docker-compose.yml down
執行上一篇的測試用例,而後中途關閉一個節點,來查看執行效果。
啓動容器:
docker-compose -f docker-compose.yml down
查看容器的運行狀況:
docker ps
關閉其中一個容器:
docker container stop <container-id>
服務短暫的輸出.no reachable servers
錯誤信息後,由恢復正常了!
看到這裏的人,必須關注公衆號了