How to create a DB for MongoDB container on start up?
Here another cleaner solution by using docker-compose
and a js
script.
This example assumes that both files (docker-compose.yml and mongo-init.js) lay in the same folder.
docker-compose.yml
version: '3.7'services: mongodb: image: mongo:latest container_name: mongodb restart: always environment: MONGO_INITDB_ROOT_USERNAME: <admin-user> MONGO_INITDB_ROOT_PASSWORD: <admin-password> MONGO_INITDB_DATABASE: <database to create> ports: - 27017:27017 volumes: - ./mongo-init.js:/docker-entrypoint-initdb.d/mongo-init.js:ro
mongo-init.js
db.createUser( { user: "<user for database which shall be created>", pwd: "<password of user>", roles: [ { role: "readWrite", db: "<database to create>" } ] });
Then simply start the service by running the following docker-compose command
docker-compose up --build -d mongodb
Note: The code in the docker-entrypoint-init.d folder is only executed if the database has never been initialized before.
The official mongo
image has merged a PR to include the functionality to create databases and admin users at startup.
The database initialisation will run any scripts in /docker-entrypoint-initdb.d/
when there is nothing populated in the /data/db
directory.
Database Initialisation
The mongo
container image provides the /docker-entrypoint-initdb.d/
path to deploy custom .js
or .sh
setup scripts that will be run once on database initialisation. .js
scripts will be run against test
by default or MONGO_INITDB_DATABASE
if defined in the environment.
COPY mysetup.sh /docker-entrypoint-initdb.d/
or
COPY mysetup.js /docker-entrypoint-initdb.d/
A simple initialisation mongo shell javascript file that demonstrates setting up the container
collection with data, logging and how to exit with an error (for result checking).
let error = truelet res = [ db.container.drop(), db.container.createIndex({ myfield: 1 }, { unique: true }), db.container.createIndex({ thatfield: 1 }), db.container.createIndex({ thatfield: 1 }), db.container.insert({ myfield: 'hello', thatfield: 'testing' }), db.container.insert({ myfield: 'hello2', thatfield: 'testing' }), db.container.insert({ myfield: 'hello3', thatfield: 'testing' }), db.container.insert({ myfield: 'hello3', thatfield: 'testing' })]printjson(res)if (error) { print('Error, exiting') quit(1)}
Admin User Setup
The environment variables to control "root" user setup are
MONGO_INITDB_ROOT_USERNAME
MONGO_INITDB_ROOT_PASSWORD
Example
docker run -d \ -e MONGO_INITDB_ROOT_USERNAME=admin \ -e MONGO_INITDB_ROOT_PASSWORD=password \ mongod
or Dockerfile
FROM docker.io/mongoENV MONGO_INITDB_ROOT_USERNAME adminENV MONGO_INITDB_ROOT_PASSWORD password
You don't need to use --auth
on the command line as the docker entrypoint.sh
script adds this in when it detects the environment variables exist.
UPD Today I avoid Docker Swarm, secrets, and configs. I'd run it with docker-compose
and the .env
file. As long as I don't need autoscaling. If I do, I'd probably choose k8s. And database passwords, root account or not... Do they really matter when you're running a single database in a container not connected to the outside world?.. I'd like to know what you think about it, but Stack Overflow is probably not well suited for this sort of communication.
Mongo image can be affected by MONGO_INITDB_DATABASE
variable, but it won't create the database. This variable determines current database when running /docker-entrypoint-initdb.d/*
scripts. Since you can't use environment variables in scripts executed by Mongo, I went with a shell script:
docker-swarm.yml
:
version: '3.1'secrets: mongo-root-passwd: file: mongo-root-passwd mongo-user-passwd: file: mongo-user-passwdservices: mongo: image: mongo:3.2 environment: MONGO_INITDB_ROOT_USERNAME: $MONGO_ROOT_USER MONGO_INITDB_ROOT_PASSWORD_FILE: /run/secrets/mongo-root-passwd MONGO_INITDB_USERNAME: $MONGO_USER MONGO_INITDB_PASSWORD_FILE: /run/secrets/mongo-user-passwd MONGO_INITDB_DATABASE: $MONGO_DB volumes: - ./init-mongo.sh:/docker-entrypoint-initdb.d/init-mongo.sh secrets: - mongo-root-passwd - mongo-user-passwd
init-mongo.sh
:
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_USERNAME'; var passwd = '$(cat "$MONGO_INITDB_PASSWORD_FILE")'; db.createUser({user: user, pwd: passwd, roles: ["readWrite"]});EOF
Alternatively, you can store init-mongo.sh
in configs (docker config create
) and mount it with:
configs: init-mongo.sh: external: true...services: mongo: ... configs: - source: init-mongo.sh target: /docker-entrypoint-initdb.d/init-mongo.sh
And secrets can be not stored in a file.