简体   繁体   中英

Mongo container with a replica set with only one node in docker-compose

I want to create a Docker container with an instance of Mongo. In particular, I would like to create a replica set with only one node (since I'm interested in transactions and they are only available for replica sets).

Dockerfile

FROM mongo
RUN echo "rs.initiate();" > /docker-entrypoint-initdb.d/replica-init.js
CMD ["--replSet", "rs0"]

docker-compose.yml

version: "3"
services:
  db:
    build:
      dockerfile: Dockerfile
      context: .
    ports:
      - "27017:27017"

If I use the Dockerfile alone everything is fine, while if I use docker-compose it does not work: in fact if I then log to the container I got prompted as rs0:OTHER> instead of rs0:PRIMARY> .

I consulted these links but the solutions proposed are not working:

https://github.com/docker-library/mongo/issues/246#issuecomment-382072843 https://github.com/docker-library/mongo/issues/249#issuecomment-381786889

You still need to issue replSetInitiate even if there's only one node in the RS.

See also here .

This is the compose file I have used for a while now for local development. You can remove the keyfile pieces if you don't need to connect via SSL.

version: "3.8"
services:
  mongodb:
    image : mongo:4
    container_name: mongodb
    hostname: mongodb
    restart: on-failure
    environment:
      - PUID=1000
      - PGID=1000
      - MONGO_INITDB_ROOT_USERNAME=mongo
      - MONGO_INITDB_ROOT_PASSWORD=mongo
      - MONGO_INITDB_DATABASE=my-service
      - MONGO_REPLICA_SET_NAME=rs0
    volumes:
      - mongodb4_data:/data/db
      - ./:/opt/keyfile/
    ports:
      - 27017:27017
    healthcheck:
      test: test $$(echo "rs.initiate().ok || rs.status().ok" | mongo -u $${MONGO_INITDB_ROOT_USERNAME} -p $${MONGO_INITDB_ROOT_PASSWORD} --quiet) -eq 1
      interval: 10s
      start_period: 30s
    command: "--bind_ip_all --keyFile /opt/keyfile/keyfile --replSet rs0"
volumes:
  mongodb4_data:

It uses Docker's health check (with a startup delay) to sneak in the rs.initiate() if it actually needs it after it's already running.

To create a keyfile.

Mac:

openssl rand -base64 741 > keyfile
chmod 600 keyfile

Linux:

openssl rand -base64 756 > keyfile
chmod 600 keyfile
sudo chown 999 keyfile
sudo chgrp 999 keyfile

I had to do something similar to build tests around ChangeStreams which are only available when running mongo as a replica set. I don't remember where I pulled this from, so I can't explain it in detail but it does work for me. Here is my setup:

Dockerfile

FROM mongo:5.0.3
RUN echo "rs.initiate({'_id':'rs0', members: [{'_id':1, 'host':'127.0.0.1:27017'}]});" > "/docker-entrypoint-initdb.d/init_replicaset.js"
RUN echo "12345678" > "/tmp/key.file"
RUN chmod 600 /tmp/key.file
RUN chown 999:999 /tmp/key.file

CMD ["mongod", "--replSet", "rs0", "--bind_ip_all", "--keyFile", "/tmp/key.file"]

docker-compose.yml

version: '3.7'

services:
  mongo:
    build: .
    restart: always
    ports: 
      - 27017:27017
    healthcheck:
      test: test $$(echo "rs.initiate().ok || rs.status().ok" | mongo -u admin -p pass --quiet) -eq 1
      interval: 10s
      start_period: 30s
    environment:
      MONGO_INITDB_ROOT_USERNAME: admin
      MONGO_INITDB_ROOT_PASSWORD: pass
      MONGO_INITDB_DATABASE: test

Run docker-compose up and you should be good.

Connection String: mongodb://admin:pass@localhost:27017/test

Note: You shouldn't use this in production obviously, adjust the key "12345678" in the Dockerfile if security is a concern.

If you just need single node replica set of MongoDB via docker-compose.yml you can simply use this:

mongodb:
  image: mongo:5
  restart: always
  command: ["--replSet", "rs0", "--bind_ip_all"]
  ports:
    - 27018:27017
  healthcheck:
    test: mongo --eval "rs.initiate()"
    start_period: 5s

The top answer stopped working for me in later MongoDB and Docker versions. Particularly because rs.initiate().ok would throw an error if the replica set was already initiated, causing the whole command to fail. In addition, connecting from another container was failing because the replica set's sole member had some random host, which wouldn't allow the connection. Here's my new docker-compose.yml :

services:
  web:
    # ...
    environment:
      DATABASE_URL: mongodb://root:root@db/?authSource=admin&tls=false
  db:
    build:
      context: ./mongo/
    environment:
      MONGO_INITDB_ROOT_USERNAME: root
      MONGO_INITDB_ROOT_PASSWORD: root
    ports:
      - '27017:27017'
    volumes:
      - data:/data/db
    healthcheck:
      test: |
        test $$(mongosh --quiet -u root -p root --eval "try { rs.initiate({ _id: 'rs0', members: [{ _id: 0, host: 'db' }] }).ok } catch (_) { rs.status().ok }") -eq 1
      interval: 10s
      start_period: 30s
volumes:
  data:

Inside ./mongo/ , I have a custom Dockerfile that looks like:

FROM mongo:6
RUN echo "password" > /keyfile \
  && chmod 600 /keyfile \
  && chown 999 /keyfile \
  && chgrp 999 /keyfile
CMD ["--bind_ip_all", "--keyFile", "/keyfile", "--replSet", "rs0"]

This Dockerfile is suitable for development, but you'd definitely want a securely generated and persistent keyfile to be mounted in production (and therefore strike the entire RUN command).

This one works fine for me:

version: '3.4'

services:
  ludustack-db:
      container_name: ludustack-db
      command: mongod --auth
      image: mongo:latest
      hostname: mongodb
      ports:
      - '27017:27017'
      env_file:
      - .env
      environment:
      - MONGO_INITDB_ROOT_USERNAME=${MONGO_INITDB_ROOT_USERNAME}
      - MONGO_INITDB_ROOT_PASSWORD=${MONGO_INITDB_ROOT_PASSWORD}
      - MONGO_INITDB_DATABASE=${MONGO_INITDB_DATABASE}
      - MONGO_REPLICA_SET_NAME=${MONGO_REPLICA_SET_NAME}
      healthcheck:
        test: test $$(echo "rs.initiate().ok || rs.status().ok" | mongo -u $${MONGO_INITDB_ROOT_USERNAME} -p $${MONGO_INITDB_ROOT_PASSWORD} --quiet) -eq 1
        interval: 60s
        start_period: 60s

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM