Roman Pietrzak aka Yosh
Mongo in Docker(compose) - installation in few steps 2020
Last update: 2020-08-19


Intro - what and why ?

I needed to quickly setup MongoDB on my local Linux machine. I wanted:
  • Do it quick
    I needed Mongo as a dependency to Node.js application. I didn't really need to work seriously on Mongo itself for anything - only quick fill the dependency for node app.
  • Containerize it
    I didn't want to instal it "globally on the machine". I had to start MongoDB now, use it for development for a while and then stop it and have no trace of that instance of Mongo if no longer needed.
  • Peristency between runs
    The DB content should be persistent between runs.

TL;DR

TL;DR: As of 2020, it's very simple to get there - just use Docker, download Mongo image, configure it, run the image. Done!
If you know how to do it without digging too much in external resources, then stop reading this now.
This article explains how to do just that: use Docker Compose to run Mongo locally with minimal useful set of configurations.

Docker Compose vs pure Docker

I don't like the imperative "command line Docker" approach to starting/configuring docker images if they are needed for anything more serious than 2 minutes work. When you do that, you end up with colosal commands, where editing is hard and it's also hard to keep trace of changes in them when testing.
I like using nice YAML config for Docker Compose and then just running "docker-compose up" to run it.

Prerequisites

  • Make sure you know what Docker is and what Docker compose is for.
  • Install docker and docker compose on your machine.
  • I'm using Ubuntu 18.04 LTS as a host for testing the content of this article.

Level 1: Basic config

Simplest config file

docker-compose.yml should look like this:
db-mongo:
  image: mongo
  container_name: mongodb
  ports:
    - 27017:27017

Add authentication requirement

This forces clients to authenticate:
db-mongo:
  image: mongo
  container_name: mongodb
  ports:
    - 27017:27017
  environment:
    MONGO_INITDB_ROOT_USERNAME: root
    MONGO_INITDB_ROOT_PASSWORD: example

Next steps

This should be enough to start basic mongo.
From here:
- go to "Level 2" for more advanced configuration
- go to "Run, stop, observe the docker container" if you want to run it

Level 2: More advanced config

Image

Look for Mongo images on Docker Hub.
Let's get the newest image available at the moment: mongo:3.6.19-xenial
  • Why not just :latest ?
    As a general rule, I don't do :latest (like in mongo:latest) in those "persistent" configs.
    • You don't know what you're installing: what exact underlying platform ?
    • You don't have a control over time: when you wrote the config everything was fine. 2 days later you start work again, you start your dockerized Mongo and everything crashes. After debugging for a while, you find that ":latest" was changed in a meanwhile, so your setup is not working anymore (API changed ? migration failed ? configs changed ? etc.)
    • You can't really share that config with your team and be sure what's gonna happen for somebody else. When they use your config - another version may be downloaded. It's like ignoring "package-lock" in Node.js projects.
  • How to find what versions are available ?
    On Docker Hub. Go to Docker Hub and search for Mongo.

Volumes

Let's expose 3 different volumes:
  • /etc/mongod.conf
    So we can easily configure mongo from outside of the container
  • /var/log/mongodb/
    So we monitor the logs of the Mongo itself if stuff goes wrong
  • /var/lib/mongodb
    The persistency: here mongoDB will keep the DB data.
    If you don't do that, mongo would keep data inside of the container itself. But when you stop/restart the container the data will dissapear.

Exposed ports

Expose port 27017 - the default mongo server port

Full config file

docker-compose.yml should look like this:
db-mongo:
  image: mongo:3.6.19-xenial
  container_name: mongodb
  volumes:
    - ./mongod.conf:/etc/mongod.conf
    - ./logs:/var/log/mongodb/
    - ./db:/var/lib/mongodb
  command: mongod --config /etc/mongod.conf
  ports:
    - 27017:27017

Level 2: Config for Mongo

Find a default Mongod config, either by extracting it from Docker image (use "docker save") or by looking at Mongo website.
Then edit:
  • paths for database and logs
    those obviously should match paths in "volumes" section in "docker-compose.yml"
  • network binding to 0.0.0.0
    starting from MongoDB 3.6 the default bindIp is localhost (127.0.0.1), so we change it to 0.0.0.0
    • Important security warning:
      bindIp configured to localhost will not allow connections from outside of you docker image, so we change this to 0.0.0.0, however think twice about what you doing here in context of security.
      This config *MAY* be good for a local dev environment, but setting bindIp to 0.0.0.0 without further steps is insecure. Exposing your mongo to public network or cloud env without making connections secure is a big no no.
      Read Security section in mongo doc and find some additional advice if needed.
Example mongod.conf:
# mongod.conf

# for documentation of all options, see:
#   http://docs.mongodb.org/manual/reference/configuration-options/

# Where and how to store data.
storage:
  dbPath: /var/lib/mongodb
  journal:
    enabled: true

# where to write logging data.
systemLog:
  destination: file
  logAppend: true
  path: /var/log/mongodb/mongod.log

# network interfaces
net:
  port: 27017
  bindIp: 0.0.0.0

# how the process runs
processManagement:
  timeZoneInfo: /usr/share/zoneinfo

Run, stop, observe, play with

Run, stop, see logs on docker container

All the commands below, should be invoked in the directory of your docker-compose.yml file.
Start it:
$ sudo docker-compose up
When you start it for the first time, docker will pull all the layers of Mongo image.
Also when you start it for the first time, docker will create all volume directories. However, mongo will complain about access rights to those directories - this is covered below in separate section.

Start it in detached mode:
$ sudo docker-compose up -d

Observe the containter logs:
$ sudo docker-compose logs -f
Note that "docker logs" are not the same as "Mongo logs". To see the mongo logs, observe your local ./logs/mongod.log file - you have mounted the ./logs directory as logs volume for a container:
$ tail -f ./logs/mongod.log

Stop it (when running in detached mode):
$ sudo docker-compose down

Shell as client

Go to mongodb container shell, then go to mongo shell manually:
$ sudo docker exec -it mongodb sh
$ mongo
Or go to mongo shell directly:
$ sudo docker exec -it mongodb mongo

Last few bits - file permissions

When you do
$ sudo docker-compose up
for the first time, probably you'll see something like:
Failed global initialization: FileNotOpen: Failed to open "/var/log/mongodb/mongod.log"
You have to change the permissions, the easiest way:
$ sudo chmod 777 logs

Then, you may see container exiting (failing) right after initialization with something like that:
$ sudo docker-compose up
Starting db-mongo ... done
Attaching to db-mongo
db-mongo exited with code 14
You can take a look to mongo logs to see what's happening:
$ tail -f -n 100 ./logs/mongod.log
If there is something like:
exception in initAndListen: IllegalOperation: Attempted to create a lock file on a read-only directory: /var/lib/mongodb, terminating
in the middle of the log, then you have to change permissions on you data directory:
$ sudo chmod 777 db

Hopefully, that's it, all done... you have your MongoDB running by now. Your application code can now connect to Mongo on port 27017.

Troubleshooting, questions, updates etc.


Please let me know if you have some updates to this article - I'm happy to include them here.
Feel free to contact me if you have any questions or need help.
If you need commercial help - I provide consultancy services as Kemu Studio, contact me please.

Thanks to

Big thanks to jeanlucpikachu for comments about mongo binding to 0.0.0.0 in context of security.
Big thanks to Dzik for testing this on Windows (although, the test was mostly proving that Windows is not the easiest environment to work with docker, so still Linux is recommended).
JavaScript failed !
So this is static version of this website.
This website works a lot better in JavaScript enabled browser.
Please enable JavaScript.