mongo EOF(二)

任何事情的成功都須要掐準時間

上一節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請訪問githubsigithub

depends_on

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不會等到mongo1mongo2mongo3容器ready後再啓動,而是等到它們啓動就開始啓動。這也是我在setup腳本中執行sleep操做的緣由。mongodb

creator:
    build:
      context: .
      dockerfile: dockerfile
    entrypoint: ["/data/conf/setup.sh"]
    depends_on:
      - mongo1
      - mongo2
      - mongo3

entrypoint

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 將會追加bashentrypoint命令末尾。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指令只是爲了保證:在執行initiatemongo的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

相應的,咱們須要調整creatordockerfile文件,由於此時的容器內,並無咱們須要的相關文件。咱們須要在建立鏡像的時候,拷貝本地文件到容器。調整後的文件以下:測試

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"]

在項目的目錄下,咱們單獨編譯creatordockerfile文件,已保證調整是有效的。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來指定容器外到容器內的端口映射。在上一篇中已經介紹過portsexpose的相關內容,感興趣的能夠去查看。以後,咱們就能夠經過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 Portmongod的默認端口實際上是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 stopdocker-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錯誤信息後,由恢復正常了!

備註

看到這裏的人,必須關注公衆號了
圖片描述

相關文章
相關標籤/搜索