; Date: March 4, 2018
Tags: Docker »»»» Docker MAMP
MongoDB, as one of the popular NoSQL databases, is part of many software development projects. Hence, one must know how to configure and setup MongoDB in a Docker environment.

Quick start
Docker's MongoDB image (
https://hub.docker.com/_/mongo/) is fairly easy to setup and deploy.
For a quick win, let's start up a MongoDB container, run a mongo client, and generally poke around to see what's there.
$ docker pull mongo
Unable to find image 'mongo:latest' locally
latest: Pulling from library/mongo
d2ca7eff5948: Pull complete
ebb958661291: Pull complete
cdfa71d101a9: Pull complete
88a286579fc2: Pull complete
9441b8e1ae36: Pull complete
0e6fe40bb4bd: Pull complete
fca9be9954eb: Pull complete
9d3de1a5bb82: Pull complete
2e423513a19e: Pull complete
2fcd12f78f7c: Pull complete
Digest: sha256:05fd4fd3710a84dcf12e5880a5fc225a245792d2d9b6156722c5f4c0fab74d86
Status: Downloaded newer image for mongo:latest
$ docker run --name some-mongo mongo
2018-03-05T06:23:52.002+0000 I CONTROL [initandlisten] MongoDB starting : pid=1 port=27017 dbpath=/data/db 64-bit host=84e5705ac41f
2018-03-05T06:23:52.002+0000 I CONTROL [initandlisten] db version v3.6.3
...
This starts the MongoDB container, which you can see here
$ docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
84e5705ac41f mongo "docker-entrypoint.s…" 4 minutes ago Up 4 minutes 27017/tcp some-mongo
A TCP port, 27017, is exposed but is not publicly visible. The Docker Hub page says this allows for easy linking between containers as that's the standard MongoDB port.
It's not recommended, but if you did want to publicly expose this port add -p 27017:27017
to the docker run
command.
$ docker exec -it some-mongo bash
root@84e5705ac41f:/# mongo
MongoDB shell version v3.6.3
connecting to: mongodb://127.0.0.1:27017
MongoDB server version: 3.6.3
Welcome to the MongoDB shell.
For interactive help, type "help".
We can get into the container, and run the Mongo client as so. Notice the client connects to that TCP port on localhost
.
> db.foo.find()
> db.foo.save({ a: 1});
WriteResult({ "nInserted" : 1 })
> db.foo.find()
{ "_id" : ObjectId("5a9ce2ec3f7f33d53a61b357"), "a" : 1 }
And we can run a couple MongoDB commands.
Connecting to MongoDB container from another
The MongoDB container would be installed alongside another container (or three) running an application that uses the MongoDB container. Therefore we need to see how to get one container to talk with the MongoDB container. To do that we'll run a second MongoDB container, but use only the MongoDB client program to connect to the MongoDB instance in the other container.
$ docker network create mnet
d7d0c678626407eb2b9de733d1ec7ef4243833cc8f64f59a77218e5bd1be3b8f
First, we need a Docker bridge network. Bridge networks are used to connect containers together. In the Docker universe you'll find old documentation suggesting to use the --link
option to connect two containers together. In the Docker documentation today, you'll see --link
described as a deprecated feature and that we're supposed to use bridge networks instead.
A Docker bridge network is a virtual subnet you create within your computer.
$ docker network inspect mnet
...
"Config": [
{
"Subnet": "172.18.0.0/16",
"Gateway": "172.18.0.1"
}
]
...
"Containers": {
"b142745a2ba9f91fbbbcde6531505baa1e0cb98c5f7a6192fb6255e910f38aca": {
"Name": "some-mongo",
"EndpointID": "09071f4634dca571eb737f72a1413d757d97680b49bccd906999d231a82afcc5",
"MacAddress": "02:42:ac:12:00:02",
"IPv4Address": "172.18.0.2/16",
"IPv6Address": ""
},
"ddc3ebc4cf9e7d735ed6c8cd8611f441723639c37bdaf556f7a04abff69ca0f2": {
"Name": "sharp_bohr",
"EndpointID": "af496257345b0a1724bc9082bded48b09cf4d2e3c4cf331dcc0270b747a1a93c",
"MacAddress": "02:42:ac:12:00:03",
"IPv4Address": "172.18.0.3/16",
"IPv6Address": ""
}
},
You can inspect a bridge network as so. First we see the subnet is assigned the 172.18.0.0
network, and second we see that two containers are connected to the network. I haven't shown you that connection yet, but you see that each container has its own IP address.
Docker has a built-in DNS server, and each container has a host name determined by its container name. Meaning that from a container on a given subnet, your software can attach to software in another container on that bridge network using the container name as the host name.
$ docker rm some-mongo
$ docker run --name some-mongo --net mnet mongo
2018-03-05T06:33:59.202+0000 I CONTROL [initandlisten] MongoDB starting : pid=1 port=27017 dbpath=/data/db 64-bit host=b142745a2ba9
2018-03-05T06:33:59.202+0000 I CONTROL [initandlisten] db version v3.6.3
We delete the old some-mongo
instance, and start a new one, this time connecting it to mnet
.
Then in another window we can run this:
$ docker run -it --rm --net mnet mongo sh -c 'exec mongo --host some-mongo'
MongoDB shell version v3.6.3
connecting to: mongodb://some-mongo:27017/
MongoDB server version: 3.6.3
Welcome to the MongoDB shell.
For interactive help, type "help".
...
> db.foo.find()
> db.foo.save({ a: 1});
WriteResult({ "nInserted" : 1 })
> db.foo.find()
{ "_id" : ObjectId("5a9ce5a60c4a3cbeda2ca453"), "a" : 1 }
>
Run this way, we start a Docker instance with interactive terminal session (the -it
option), attached to mnet
, using the mongo
image. This time we run a shell command mongo --host some-mongo
, and that starts a Mongo client connecting to the MongoDB server in the some-mongo
container. And we can prove the database works by running the test commands.
$ docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
ddc3ebc4cf9e mongo "docker-entrypoint.s…" 10 minutes ago Up 10 minutes 27017/tcp sharp_bohr
b142745a2ba9 mongo "docker-entrypoint.s…" 13 minutes ago Up 13 minutes 27017/tcp some-mongo
By the way this is an expensive way to get a MongoDB client running, because it also starts up a second MongoDB server. But, it proved that indeed we can easily have a Mongo client of some kind connect to a MongoDB server in another container.
Configuration file
root@ddc3ebc4cf9e:/# ls -l /etc/mongod.conf.orig
-rw-r--r-- 1 root root 626 Feb 22 20:24 /etc/mongod.conf.orig
There is a default MongoDB configuration file in the container, but the file is not enabled.
Documentation on the MongoDB configuration file:
https://docs.mongodb.com/manual/reference/configuration-options/
One could mount a configuration file into the container by adding this option to the command line: -v ./mongod.conf:/etc/mongod.conf
Or, in a docker-compose.yml
:
db-mongo:
image: mongo:3.6-jessie
container_name: db-mongo
networks:
- _network name_
volumes:
- ./mongod.conf:/etc/mongod.conf
The documentation suggests that using the configuration file then requires that mongod
be launched as mongod --config /etc/mongod.conf
. To do this requires overriding the CMD command in the Dockerfile. The docker run
command doesn't allow overriding the CMD command, but you can do it from docker-compose.yml
db-mongo:
image: mongo:3.6-jessie
container_name: db-mongo
networks:
- _network name_
volumes:
- ./mongod.conf:/etc/mongod.conf
command: mongod --config /etc/mongod.conf
That isn't tested, but this documentation suggests that's what would work:
https://docs.docker.com/compose/compose-file/#command
Persisting the database
So far the database used by the MongoDB instance has lived solely within the container. Therefore the database was deleted as soon as the container was deleted.
Docker container lifecycle's are incompatible with database lifecycles. We expect a database to potentially have a useable lifetime measuring in decades, while a container's lifetime can be measured in minutes. Therefore we need to store the MongoDB database outside the container.
Fortunately that's simple, and simply requires using an option we just saw.
$ docker rm some-mongo
$ docker run --name some-mongo --net mnet -v ./data-directory:/data/db mongo
Or
db-mongo:
image: mongo:3.6-jessie
container_name: db-mongo
networks:
- _network name_
volumes:
- ./db-notes-mongo:/data/db
- ./mongod.conf:/etc/mongod.conf
command: mongod --config /etc/mongod.conf
Mongo Express
This is a web-based MongoDB administrative service.
https://hub.docker.com/_/mongo-express/
This is rather easy to set up:
$ docker run -it --rm \
--name mongo-express \
--net mnet -p 8081:8081 \
-e ME_CONFIG_OPTIONS_EDITORTHEME="ambiance" \
-e ME_CONFIG_BASICAUTH_USERNAME="user" \
-e ME_CONFIG_BASICAUTH_PASSWORD="fairly long password" \
-e ME_CONFIG_MONGODB_SERVER="some-mongo" \
mongo-express

As a Docker Compose setup, it might look like this:
db-mongo:
image: mongo:3.6-jessie
container_name: db-mongo
networks:
- _network name_
volumes:
- ./db-notes-mongo:/data/db
- ./mongod.conf:/etc/mongod.conf
command: mongod --config /etc/mongod.conf
db-mongo-admin:
image: mongo-express
container_name: db-mongo-admin
networks:
- _network name_
environment:
ME_CONFIG_OPTIONS_EDITORTHEME: ambiance
ME_CONFIG_BASICAUTH_USERNAME: user
ME_CONFIG_BASICAUTH_PASSWORD: fairlylongpassword
ME_CONFIG_MONGODB_SERVER: some-mongo
This is untested but a straight-forward translation of the command-line.