Dockerize Mongo to get consistent data across your development environments

Author

Jonathan Gluck

August 25, 2021

We have all lamented, with great chagrin, the proverbial "works on my machine" problem because data is different across different development environments.

Wouldn't it be ideal if we could deploy our MongoDB database state from a single repository on all development environments?

In this tutorial, we will be dockerizing a Mongo database with some seed data so we can do just that!

Prerequisites

  1. Install Docker Desktop
  2. Install MongoDB Compass (for testing)

Step-by-Step How-To

Step 1: Download and unzip the file TonicMongoDockerTutorial_start.zip

  • The structure should look as follows:
TonicMongoDockerTutorial_start
│ docker-compose.yml
│ Dockerfile
 start.sh
└───collections
│ │
│ │ Restaurants.json
│ │ Users.json
  • The purposes of each of these files are as follows:
    • docker-compose.yml will orchestrate our two containers; one holding the actual database, the other acting as a client 'seeder' to seed our data.
    • Dockerfile will be the Docker file for our custom Mongo client 'seeder'.
    • start.sh will contain the majority of the work we will have our 'seeder' execute as part of its CMD instruction.
    • collections contains the JSON files representing the seed data we want in our Mongo container.

Step 2: We will start with docker-compose.yml. Edit it so that it has the following:

version: '3'
services:
my_mongo:
image: mongo
ports:
 27019:27017
environment:
MONGO_INITDB_ROOT_USERNAME: root
MONGO_INITDB_ROOT_PASSWORD: rootpassword
  • This creates our main container, my_mongo, where our Mongo database will live:

  • image: mongo pulls the Mongo image from Docker Hub.

    • ports: maps local port 27019 to port 27017 (Mongo's default port) in the container.
    • environment: sets environment variables for Mongo to configure the root user credentials.
  • (optional) To test this:

    • Run docker-compose up -d in the TonicMongoDockerTutorial_start directory.
    • Connect to it using MongoDB Compass. Start a new connection. Click Fill in connection fields individually, select authentication: username/password, and fill in the following parameters:
      • hostname: localhost
      • port: 27019
      • username: root
      • password: rootpassword

Step 3: Let's create the Docker image for our seeder container. Edit Dockerfile so that it looks like:

FROM mongo
COPY collections/Restaurants.json /collections/Restaurants.json
COPY collections/Users.json /collections/Users.json
ADD start.sh /start.sh
RUN chmod +x /start.sh
CMD ["/start.sh"]
  • This creates our seeder container:
    • FROM mongo pulls the Mongo image from Docker Hub.
    • COPY collections/Restaurants.json /collections/Restaurants.json copies the collection JSON into the seeder container.
    • ADD start.sh /start.sh adds the shell script into the container.
    • RUN chmod +x /start.sh makes the script executable in the container.
    • CMD ["/start.sh"] runs the script when the container starts.

Step 4: Let's put the logic to seed the database in start.sh:

#!/bin/bash
sleep 10
mongoimport --drop --host my_mongo --username root --password rootpassword --authenticationDatabase admin --db tutorial_db --collection Restaurants --type json --jsonArray --file /collections/Restaurants.json
mongoimport --drop --host my_mongo --username root --password rootpassword --authenticationDatabase admin --db tutorial_db --collection Users --type json --jsonArray --file /collections/Users.json
  • This uses mongoimport to import the collection data into the my_mongo container.

Step 5: Now let's tie it all together and add our seeder image to docker-compose.yml.

version: '3'
services:
my_mongo:
image: mongo
ports:
 27019:27017
environment:
MONGO_INITDB_ROOT_USERNAME: root
MONGO_INITDB_ROOT_PASSWORD: rootpassword
mongo_seeder:
image: mongo_seeder
depends_on:
 my_mongo
  • We'll add the additional service entry for our seeder container:
    • mongo_seeder is our container name.
    • image: mongo_seeder will be the image name for when we build our Dockerfile.
    • depends_on makes it so we can access my_mongo as a host name in start.sh.

Step 6: Testing it all out from the TonicMongoDockerTutorial_start directory.

  • Build the Dockerfile docker build -f Dockerfile -t mongo_seeder .
  • Run docker-compose docker-compose up -d
  • Wait for the seeder to complete, and your restaurant collection should be accessible via MongoDB Compass!

Step 7 (Bonus): Configuring users and their permissions.

  • Create a file in TonicMongoDockerTutorial_start directory with the following contents called setupUsers.js:
conn=new Mongo("mongo_source");
db=conn.getDB("admin");
db.auth("root","rootpassword");
db.dropUser("lowAccessUser");
db.dropRole("lowAccessRole");
db.createRole({role: "lowAccessRole",
roles: [],
privileges: [
{resource: {db: "tutorial_db",collection: "Restaurants"},actions: ["listCollections"]}
]
});
db.createUser({user: "lowAccessUser",pwd: "lowaccessuserpassword",roles: [{role: "lowAccessRole",db: "admin"}]});
  • Make sure setupUsers.js is copied into the container in Dockerfile:
FROM mongo
COPY collections/Restaurants.json /collections/Restaurants.json
COPY collections/Users.json /collections/Users.json
COPY setupUsers.js setupUsers.js
ADD start.sh /start.sh
RUN chmod +x /start.sh
CMD ["/start.sh"]
  • Invoke setupUsers.js in start.sh:
#!/bin/bash
sleep 10
mongoimport --drop --host my_mongo --username root --password rootpassword --authenticationDatabase admin --db tutorial_db --collection Restaurants --type json --jsonArray --file /collections/Restaurants.json
mongoimport --drop --host my_mongo --username root --password rootpassword --authenticationDatabase admin --db tutorial_db --collection Users --type json --jsonArray --file /collections/Users.json
mongo --host my_mongo --username root --password rootpassword --authenticationDatabase admin setupUsers.js

Conclusion

There we have it! Now all you have to do to reproduce your Mongo state anywhere is pull something like this from a repo onto a machine with Docker and run the commands.