【问题标题】:replica Set mongo docker-compose副本集 mongo docker-compose
【发布时间】:2017-02-12 16:38:48
【问题描述】:

我正在尝试使用 docker-compose 配置 mongodb replicaSet,但是当我停止主容器时,它似乎没有传递给辅助容器。

redis:
 image: redis
 ports:
  - "6379:6379"

mongo3:
 hostname: mongo3
 image: mongo
 entrypoint: [ "/usr/bin/mongod", "--replSet", "rs", "--journal","--dbpath","/data/db","--smallfiles", "--rest" ]
 volumes:
  - ./data/mongo3:/data/db
 ports:
  - "27018:27017"
  - "28018:28017"
 restart: always

mongo2:
 hostname: mongo2
 image: mongo
 entrypoint: [ "/usr/bin/mongod", "--replSet", "rs", "--journal","--dbpath","/data/db","--smallfiles", "--rest" ]
 volumes:
  - ./data/mongo2:/data/db
 ports:
  - "27019:27017"
  - "28019:28017"
 restart: always

mongo1:
 hostname: mongo1
 image: mongo
 entrypoint: [ "/usr/bin/mongod", "--replSet", "rs", "--journal","--dbpath","/data/db","--smallfiles", "--rest" ]
 volumes:
  - ./data/mongo1:/data/db
ports:
  - "27017:27017"
  - "28017:28017"
links:
 - mongo2:mongo2
 - mongo3:mongo3
restart: always

web:
 build: .
 ports:
  - "2000:2000"
 volumes:
  - .:/vip
 links:
  - redis
  - mongo1
  - mongo2
  - mongo3

nginx:
 restart: always
 build: ./nginx/
 ports:
  - "80:80"
 links:
  - web:web

mongosetup:
 image: mongo
 links:
  - mongo1:mongo1
  - mongo2:mongo2
  - mongo3:mongo3
 volumes:
  - ./scripts:/scripts
 entrypoint: [ "/scripts/setup.sh" ]

setup.sh:

#!/bin/bash

MONGODB1=`ping -c 1 mongo1 | head -1  | cut -d "(" -f 2 | cut -d ")" -f 1`
MONGODB2=`ping -c 1 mongo2 | head -1  | cut -d "(" -f 2 | cut -d ")" -f 1`
MONGODB3=`ping -c 1 mongo3 | head -1  | cut -d "(" -f 2 | cut -d ")" -f 1`

echo "**********************************************" ${MONGODB1}
echo "Waiting for startup.."
until curl http://${MONGODB1}:28017/serverStatus\?text\=1 2>&1 | grep uptime | head -1; do
  printf '.'
  sleep 1
done

echo curl http://${MONGODB1}:28017/serverStatus\?text\=1 2>&1 | grep uptime | head -1
echo "Started.."


echo SETUP.sh time now: `date +"%T" `
mongo --host ${MONGODB1}:27017 <<EOF
var cfg = {
    "_id": "rs",
    "version": 1,
    "members": [
        {
            "_id": 0,
            "host": "${MONGODB1}:27017",
            "priority": 2
        },
        {
            "_id": 1,
            "host": "${MONGODB2}:27017",
            "priority": 0
        },
        {
            "_id": 2,
            "host": "${MONGODB3}:27017",
            "priority": 0
        }
    ],settings: {chainingAllowed: true}
};
rs.initiate(cfg, { force: true });
rs.reconfig(cfg, { force: true });
rs.slaveOk();
db.getMongo().setReadPref('nearest');
db.getMongo().setSlaveOk(); 
EOF

【问题讨论】:

    标签: mongodb docker docker-compose


    【解决方案1】:

    我遇到了类似的问题,并使用以下撰写文件解决了它:

    version: "3.8"
    
    services:
      mongo1:
        image: mongo:4.2
        container_name: mongo1
        command: ["--replSet", "my-replica-set", "--bind_ip_all", "--port", "30001"]
        volumes:
          - ./data/mongo-1:/data/db
        ports:
          - 30001:30001
        healthcheck:
          test: test $$(echo "rs.initiate({_id:'my-replica-set',members:[{_id:0,host:\"mongo1:30001\"},{_id:1,host:\"mongo2:30002\"},{_id:2,host:\"mongo3:30003\"}]}).ok || rs.status().ok" | mongo --port 30001 --quiet) -eq 1
          interval: 10s
          start_period: 30s
    
      mongo2:
        image: mongo:4.2
        container_name: mongo2
        command: ["--replSet", "my-replica-set", "--bind_ip_all", "--port", "30002"]
        volumes:
          - ./data/mongo-2:/data/db
        ports:
          - 30002:30002
    
      mongo3:
        image: mongo:4.2
        container_name: mongo3
        command: ["--replSet", "my-replica-set", "--bind_ip_all", "--port", "30003"]
        volumes:
          - ./data/mongo-3:/data/db
        ports:
          - 30003:30003
    

    在我的/etc/hosts 文件中包含以下内容:

    127.0.0.1       mongo1
    127.0.0.1       mongo2
    127.0.0.1       mongo3
    

    我在 GitHub 存储库中记录了它,并在此处发表了一篇小博文:

    https://github.com/UpSync-Dev/docker-compose-mongo-replica-set

    https://www.upsync.dev/2021/02/02/run-mongo-replica-set.html

    【讨论】:

    • 我试过了,效果很好!我希望这将是公认的答案
    • 看起来像这样每 10 秒运行一次 rs.initiate() ?你为什么要这么做?
    【解决方案2】:

    更新:这不起作用!你确实需要运行rs.initiate()

    使用 MongoDB 4.0,您不需要第 4 个容器来运行设置脚本。调出一个包含 3 个容器的副本集真的很简单:

    version: "3"
    services:
      mongo1:
        hostname: mongo1
        container_name: localmongo1
        image: mongo:4.0-xenial
        expose:
          - 27017
        restart: always
        entrypoint: [ "/usr/bin/mongod", "--bind_ip_all", "--replSet", "rs0" ]
      mongo2:
        hostname: mongo2
        container_name: localmongo2
        image: mongo:4.0-xenial
        expose:
          - 27017
        restart: always
        entrypoint: [ "/usr/bin/mongod", "--bind_ip_all", "--replSet", "rs0" ]
      mongo3:
        hostname: mongo3
        container_name: localmongo3
        image: mongo:4.0-xenial
        expose:
          - 27017
        restart: always
        entrypoint: [ "/usr/bin/mongod", "--bind_ip_all", "--replSet", "rs0" ]
    

    更多信息在这里:https://github.com/msound/localmongo/tree/4.0

    【讨论】:

    • 您不需要在其中一个节点上手动运行 rs.initiate(...) 和可能的 rs.add(...) 吗?如果没有,您发布的 docker-compose yaml 的哪一部分负责处理这个问题?
    • 另外,别忘了:rs.slaveOk()
    • mongodb2 | 2019-06-28T02:04:15.218+0000 I STORAGE [initandlisten] initAndListen 中的异常:DBPathInUse:无法锁定锁定文件:/data/db/mongod.lock(未知错误)。另一个 mongod 实例已经在 /data/db 目录上运行,终止 mongodb2
    • 对于那些希望在 docker compose 中包含 rs.initiate() 调用的人,您需要使用 healthcheck 属性来执行此操作。在相关线程上查看此答案:stackoverflow.com/a/66755872/3493695
    【解决方案3】:

    我一直在寻找如何使用一个数据库实例启动 MongoDB 副本集以进行本地开发,结果到了这里。我发现这里的答案太复杂了,所以我想出了以下解决方案:

    docker-compose.yml

    version: "3"
    services: 
      mongo:
        hostname: mongodb
        container_name: mongodb
        image: mongo:latest
        restart: always
        ports:
          - "27017:27017"
        volumes:
          - ./scripts:/docker-entrypoint-initdb.d/
        command: ["--replSet", "rs0", "--bind_ip_all"]
    

    在当前目录中有一个名为“scripts”的文件夹,其中有一个名为“init.js”的文件(名称不重要)。此文件夹作为卷安装到“/docker-entrypoint-initdb.d/”,这是一个特殊文件夹。当 MongoDB 启动时,该目录下的所有文件都会被执行。文件内容为:

    init.js

    rs.initiate();
    

    【讨论】:

    • 通过这种方式,我无法访问我收藏中的数据。我收到以下错误:Error: error: { "ok" : 0, "errmsg" : "node is not in primary or recovering state", "code" : 13436, "codeName" : "NotMasterOrSecondary" }
    • @gustavz 确保您的文件结构正确。否则,从 mongo CLI 客户端运行“rs.initiate()”。
    • 在 mongodb 5.0 中,是工作,并且卷是必需的。在 mongodb 4.x 中卷不需要。
    • 这是否只使用一个容器,但代表客户端的副本集?需要副本集(如事务)的代码是否仍然有效?
    【解决方案4】:

    我建议你看看khezen/mongo

    您可以通过以下方式在 3 个节点的 docker swarm 上部署 mongo 副本集:

    version: '3'
    
    services:
    
      replica1:
        image: khezen/mongo:slim
        deploy:
          mode: replicated
          replicas: 1
          update_config:
            parallelism: 1
            delay: 10s
          restart_policy:
            condition: on-failure
          palcement:
            node.hostname: node-1
        environment:
          RS_NAME: shard1
          SHARD_SVR: 'y'
          AUTH: 'y'
        volumes:
          - /data/mongo/replica1:/data/db
        networks:
          - mongo_cluster
    
      replica2:
        image: khezen/mongo:slim
        deploy:
          mode: replicated
          replicas: 1
          update_config:
            parallelism: 1
            delay: 10s
          restart_policy:
            condition: on-failure
          palcement:
            node.hostname: node-2
        environment:
          RS_NAME: shard1
          SHARD_SVR: 'y'
          AUTH: 'y'
        volumes:
          - /data/mongo/replica2:/data/db
        networks:
          - mongo_cluster
    
      replica3:
        image: khezen/mongo:slim
        deploy:
          mode: replicated
          replicas: 1
          update_config:
            parallelism: 1
            delay: 10s
          restart_policy:
            condition: on-failure
          palcement:
            node.hostname: node-3
        environment:
          RS_NAME: shard1
          SHARD_SVR: 'y'
          MASTER: replica3
          SLAVES: replica1 replica2
          AUTH: 'y'
        volumes:
          - /data/mongo/replica3:/data/db
        networks:
          - mongo_cluster
    
    networks:
      mongo_cluster:
        driver: overlay
    

    免责声明:我是这张图片的维护者。

    【讨论】:

    • 嘿,你将如何连接到这些?我目前正在尝试通过我的 docker-compose 自动化我的整个部署,但在这里我看到您没有将任何端口暴露给世界其他地方?
    • @EvanBurbidge 您需要通过某些服务来定位副本集并定位适当的 pod/容器 - 只需打开端口或通过 L4 负载均衡器不会做 b/c 你'不保证连接到 RS 领导者。
    【解决方案5】:

    我设置了一个要点,其中包含有关如何使用 docker-compose 文件和 mongoose 进行设置的指南。 https://gist.github.com/harveyconnor/518e088bad23a273cae6ba7fc4643549

    【讨论】:

      【解决方案6】:

      我在使用身份验证的独立 mongodb 服务中设置 replica set 时遇到了类似的问题,这就是我最终得到的结果。

      docker-compose.yml:

      version: '3.7'
      
      services:
        
        ...
      
        db:
          image: mongo
          restart: always
          expose:
            - 27017
          environment:
            MONGO_INITDB_DATABASE: ${DATABASE_NAME}
            MONGO_INITDB_ROOT_USERNAME: ${DATABASE_USER}
            MONGO_INITDB_ROOT_PASSWORD: ${DATABASE_PASSWORD}
            MONGO_REPLICA_SET_NAME: ${MONGO_REPLICA_SET_NAME}
          command: ["--replSet", "${MONGO_REPLICA_SET_NAME}", "--bind_ip_all"]
          healthcheck:
            test: test $$(echo "rs.status().ok" | mongo -u $${MONGO_INITDB_ROOT_USERNAME} -p $${MONGO_INITDB_ROOT_PASSWORD} --quiet) -eq 1
            interval: 10s
            start_period: 30s
          volumes:
            - ./db:/data/db
            - ./scripts/set-credentials.sh:/docker-entrypoint-initdb.d/set-credentials.sh
      
        replica-setup:
          image: mongo
          restart: on-failure
          networks:
            default:
          volumes:
            - ./scripts/setup-replica.sh:/scripts/setup-replica.sh
          entrypoint: [ "bash", "/scripts/setup-replica.sh" ]
          depends_on:
            - db
          environment:
            MONGO_INITDB_ROOT_USERNAME: ${DATABASE_USER}
            MONGO_INITDB_ROOT_PASSWORD: ${DATABASE_PASSWORD}
      

      ./scripts/setup-replica.sh:

      #!/bin/bash
      
      MONGODB1=db
      
      echo "Waiting for MongoDB startup..."
      until curl http://${MONGODB1}:27017/serverStatus\?text\=1 2>&1 | grep uptime | head -1; do
        printf '.'
        sleep 1
      done
      
      # check if replica set is already initiated
      RS_STATUS=$( mongo --quiet --host ${MONGODB1}:27017 -u $MONGO_INITDB_ROOT_USERNAME -p $MONGO_INITDB_ROOT_PASSWORD --eval "rs.status().ok" )
      if [[ $RS_STATUS != 1 ]]
      then
        echo "[INFO] Replication set config invalid. Reconfiguring now."
        RS_CONFIG_STATUS=$( mongo --quiet --host ${MONGODB1}:27017 -u $MONGO_INITDB_ROOT_USERNAME -p $MONGO_INITDB_ROOT_PASSWORD --eval "rs.status().codeName" )
        if [[ $RS_CONFIG_STATUS == 'InvalidReplicaSetConfig' ]]
        then
          mongo --quiet --host ${MONGODB1}:27017 -u $MONGO_INITDB_ROOT_USERNAME -p $MONGO_INITDB_ROOT_PASSWORD <<EOF
      config = rs.config()
      config.members[0].host = db # Here is important to set the host name of the db instance
      rs.reconfig(config, {force: true})
      EOF
        else
          echo "[INFO] MongoDB setup finished. Initiating replicata set."
          mongo --quiet --host ${MONGODB1}:27017 -u $MONGO_INITDB_ROOT_USERNAME -p $MONGO_INITDB_ROOT_PASSWORD --eval "rs.initiate()" > /dev/null
        fi
      else
        echo "[INFO] Replication set already initiated."
      fi
      

      ./scripts/set-credentials.sh:

      #!/bin/bash
      set -e
      
      mongo -- "$MONGO_INITDB_DATABASE" <<EOF
          var rootUser = '$MONGO_INITDB_ROOT_USERNAME';
          var rootPassword = '$MONGO_INITDB_ROOT_PASSWORD';
          var admin = db.getSiblingDB('admin');
          admin.auth(rootUser, rootPassword);
      
          var user = '$MONGO_INITDB_ROOT_USERNAME';
          var password = '$MONGO_INITDB_ROOT_PASSWORD';
          db.createUser({user: user, pwd: password, roles: ["readWrite"]});
      EOF
      

      我实现的是:

      • 设置mongodb 服务,使用默认集合的用户名/密码身份验证
      • 第一次运行服务时初始化replica set
      • 当有以前的数据库数据时重新配置replica set 成员
      • 通过检查replica set 状态检查mongodb 服务的运行状况

      【讨论】:

      • 在启动mongod的时候不需要传入--auth标志吗?
      【解决方案7】:

      此设置对我有用。我还在https://github.com/nguyenduyhust/docker-mongodb-replica-set 中设置了所有内容。

      如果这就是您想要的,那就太好了。

      Dockerfile

      FROM mongo
      RUN mkdir /config
      WORKDIR /config
      COPY wait-for-it.sh .
      COPY mongo-setup.js .
      COPY mongo-setup.sh .
      RUN chmod +x /config/wait-for-it.sh
      RUN chmod +x /config/mongo-setup.sh
      CMD [ "bash", "-c", "/config/wait-for-it.sh mongodb1:27011 -- /config/mongo-setup.sh"]
      

      docker-compose.yml

      version: "3"
      
      services:
        mongodb1:
          container_name: mongo1
          image: mongo
          restart: always
          volumes:
            - ./volumes/mongodb1:/data/db
          ports:
            - "27011:27011"
          expose:
            - "27011"
          entrypoint:
            [
              "/usr/bin/mongod",
              "--port", "27011",
              "--replSet", "rs0",
              "--bind_ip_all",
            ]
      
        mongodb2:
          container_name: mongo2
          image: mongo
          restart: always
          volumes:
            - ./volumes/mongodb2:/data/db
          ports:
            - "27012:27012"
          expose:
            - "27012"
          entrypoint:
            [
              "/usr/bin/mongod",
              "--port", "27012",
              "--replSet", "rs0",
              "--bind_ip_all",
            ]
      
        mongodb3:
          container_name: mongo3
          image: mongo
          restart: always
          volumes:
            - ./volumes/mongodb3:/data/db
          ports:
            - "27013:27013"
          expose:
            - "27013"
          entrypoint:
            [
              "/usr/bin/mongod",
              "--port", "27013",
              "--replSet", "rs0",
              "--bind_ip_all",
            ]
      
        mongosetup:
          container_name: mongosetup
          image: "mongo-setup"
          build: "./mongo-setup"
          depends_on:
            - mongodb1
      
        mongo-express:
          container_name: mongo-express
          image: mongo-express
          environment:
            ME_CONFIG_MONGODB_URL: mongodb://mongodb1:27011,mongodb2:27012,mongodb3:27013/?replicaSet=rs0
          ports:
            - 8081:8081
          restart: always
          depends_on:
            - mongodb1
            - mongosetup
      

      mongo-setup.js

      rsconf = {
        _id : "rs0",
        members: [
            {
                "_id": 0,
                "host": "mongodb1:27011",
                "priority": 3
            },
            {
                "_id": 1,
                "host": "mongodb2:27012",
                "priority": 2
            },
            {
                "_id": 2,
                "host": "mongodb3:27013",
                "priority": 1
            }
        ]
      }
      
      rs.initiate(rsconf);
      

      mongo-setup.sh

      #!/usr/bin/env bash
      
      if [ ! -f /data/mongo-init.flag ]; then
          echo "Init replicaset"
          mongo mongodb://mongodb1:27011 mongo-setup.js
          touch /data/mongo-init.flag
      else
          echo "Replicaset already initialized"
      fi
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2018-03-18
        • 2015-09-17
        • 2018-05-20
        • 1970-01-01
        • 2020-08-12
        • 1970-01-01
        • 1970-01-01
        • 2016-06-05
        相关资源
        最近更新 更多