Skip to content

Instantly share code, notes, and snippets.

@zhangyoufu
Created June 10, 2019 11:07
Show Gist options
  • Save zhangyoufu/d1d43ac0fa268cda4dd2dfe55a8c834e to your computer and use it in GitHub Desktop.
Save zhangyoufu/d1d43ac0fa268cda4dd2dfe55a8c834e to your computer and use it in GitHub Desktop.
ugly hack to initialize replica set for MongoDB docker container, put under /docker-entrypoint-initdb.d/
#!/bin/bash
: "${FORKED:=}"
if [ -z "${FORKED}" ]; then
echo >&2 'mongod for initdb is going to shutdown'
mongod --pidfilepath /tmp/docker-entrypoint-temp-mongod.pid --shutdown
echo >&2 'replica set will be initialized later'
FORKED=1 "${BASH_SOURCE[0]}" &
unset FORKED
mongodHackedArgs=(:) # bypass mongod --shutdown in docker-entrypoint.sh
return
fi
# FIXME: assume mongod listens on 127.0.0.1:27017
mongo=( mongo --host 127.0.0.1 --port 27017 --quiet )
tries=30
while true; do
sleep 1
if "${mongo[@]}" --eval 'quit(0)' &> /dev/null; then
# success!
break
fi
(( tries-- ))
if [ "$tries" -le 0 ]; then
echo >&2
echo >&2 'error: unable to initialize replica set'
echo >&2
kill -STOP 1 # initdb won't be executed twice, so fail loudly
exit 1
fi
done
echo 'about to initialize replica set'
# FIXME: hard-coded replica set name & member host
"${mongo[@]}" <<-EOF
rs.initiate({
_id: "rs0",
version: 1,
members: [
{ _id: 0, host : "mongo" },
]
});
EOF
@ldeluigi
Copy link

ldeluigi commented Dec 8, 2020

If anyone stumbles upon this script it may be helpful to see an even simpler, uglier version, that adds admin/user configuration too:

#!/bin/bash

mongo -- "$MONGO_INITDB_DATABASE" <<-EOJS
    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_USERNAME';
    var passwd = '$MONGO_INITDB_PASSWORD';
    db.createUser({user: user, pwd: passwd, roles: ["readWrite"]});
EOJS

{
sleep 3 &&
mongo -- "$MONGO_INITDB_DATABASE" <<-EOJS
    var rootUser = '$MONGO_INITDB_ROOT_USERNAME';
    var rootPassword = '$MONGO_INITDB_ROOT_PASSWORD';
    var admin = db.getSiblingDB('admin');
    admin.auth(rootUser, rootPassword);
    rs.initiate()
EOJS
} &

@ericwooley
Copy link

ericwooley commented Jan 4, 2022

I had similar issues, and found this gist from here: docker-library/mongo#339

Additionally I wanted mongo to run on a different port. Here was my final setup:

mongo.dockerfile

FROM mongo:4.4.10
COPY keyfile.pem /data/keyfile.pem
RUN mkdir -p /data/logs && chmod 777 -R /data/logs
RUN chmod 400 /data/keyfile.pem
RUN chown 999:999 /data/keyfile.pem
RUN apt-get update && apt-get install netcat -y
COPY init.sh /docker-entrypoint-initdb.d/init.sh

init.sh

#!/bin/bash

# https://gist.github.com/zhangyoufu/d1d43ac0fa268cda4dd2dfe55a8c834e
{
while ! nc -z localhost $MONGO_PORT; do
  sleep 0.1 # wait for 1/10 of the second before check again
done &&
mongo --port $MONGO_PORT -- "$MONGO_INITDB_DATABASE" 2>&1 > /data/logs/mongo-init.log <<-EOJS
  var rootUser = '$MONGO_INITDB_ROOT_USERNAME';
  var rootPassword = '$MONGO_INITDB_ROOT_PASSWORD';
  var admin = db.getSiblingDB('admin');
  admin.auth(rootUser, rootPassword);
EOJS && sleep 3 &&
mongo --port $MONGO_PORT -- "$MONGO_INITDB_DATABASE" 2>&1 > /data/logs/mongo-rs-init.log <<-EOJS
    var rootUser = '$MONGO_INITDB_ROOT_USERNAME';
    var rootPassword = '$MONGO_INITDB_ROOT_PASSWORD';
    var admin = db.getSiblingDB('admin');
    admin.auth(rootUser, rootPassword);
    rs.initiate({_id: 'rs0', members: [{_id: 0, host: "localhost:$MONGO_PORT"}]})
EOJS
} &
version: '3.8'
services:
  mongodb-primary:
    build:
      dockerfile: mongo.dockerfile
      context: ./docker/mongo/
    ports:
      - 27027:27027
    restart: always
    command: --keyFile /data/keyfile.pem --replSet rs0 --port 27027
    environment:
      - MONGO_PORT=27027
      - MONGO_INITDB_ROOT_USERNAME=blah
      - MONGO_INITDB_ROOT_PASSWORD=blah
    volumes:
      - mongo_test:/data/db

and I generated the keyfile with

openssl rand -base64 756 >  .docker/mongo/keyfile.pem

Make sure you delete volumes when you recreate your mongo docker image, because the config persists with the db (i think). I'm still pretty new to mongo, so this bit me pretty hard.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment