Building a MongoDB Cluster using Docker Containers

This post explains the steps I've taken to build a cluster of 3 MongoDB servers, each one of whom is contained in a Docker container.

I've done this as an experiment in learning Docker yet the resulting cluster can be used by anyone who wants to quickly bring up a MongoDB cluster to gain a deeper understanding of MongoDB replica sets etc.

Requirements & Assumptions

You need an operational Docker environment.  I use an affordable VPS on Digital Ocean, running stock Ubuntu 12.04 in to which I've installed Docker.

If you run into an AUFS-related error. Follow the tips from this Stack Overflow post.

For the sake of brevity and sanity, my console output below assumes you're logged in as root. If in doubt - sudo. :-)

Step 1 - Prepare the folder structure

I've documented my thoughts on how to best setup Docker's folder structure in a separate post.

So lets create the folders that will be mapped into the containers

mkdir -p /var/docker/mongodb1/data
mkdir -p /var/docker/mongodb2/data
mkdir -p /var/docker/mongodb3/data

Create a mongodb.conf file in /home/me/docker/mongodb folder. The only thing worth changing is the replSet name if you don't like mine.

# mongodb.conf
dbpath=/data
logpath=/data/mongodb.log
logappend=true
replSet = cbrep

Copy the conf file into the data folders for our 3 MongoDB containers.

cp mongodb.conf /var/docker/mongodb1/data
cp mongodb.conf /var/docker/mongodb2/data
cp mongodb.conf /var/docker/mongodb3/data

Step 2 - Build the container

Download the Dockerfile from this gist or copy & paste it below. Its derived from the great blog post written by Arunoda Susiripala.

# MongoDB
#
# VERSION               0.0.1
#
# requires mongodb.conf @ https://gist.github.com/ijonas/6844358 

FROM ubuntu
MAINTAINER [email protected]

# make sure the package repository is up to date
RUN echo "deb http://archive.ubuntu.com/ubuntu precise main universe" > /etc/apt/sources.list
RUN apt-get update

RUN apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv 7F0CEB10
RUN echo 'deb http://downloads-distro.mongodb.org/repo/ubuntu-upstart dist 10gen' | tee /etc/apt/sources.list.d/10gen.list

RUN apt-get update -y
RUN apt-get install mongodb-10gen=2.4.6

EXPOSE 27017
ENTRYPOINT ["mongod", "-f", "/data/mongodb.conf"]

Next step, build the container in the /home/me/docker/mongodb folder assuming that's where you've placed your Dockerfile.

docker build -t yourname/mongodb .

Confirm the container was built, by finding it  in the image list with

docker images

Step 3 - Launch the containers

With all the prep done, you can launch the containers

docker run -d -v /var/docker/mongodb1/data:/data -t yourname/mongodb
docker run -d -v /var/docker/mongodb2/data:/data -t yourname/mongodb
docker run -d -v /var/docker/mongodb3/data:/data -t yourname/mongodb

Confirm they're running with

docker ps

You should see similar output to

ID IMAGE COMMAND CREATED STATUS PORTS
5c249b3b5e21 caseblocks/mongodb:latest mongod -f /data/mong 12 hours ago Up 12 hours 49182->27017
dc33980b796a caseblocks/mongodb:latest mongod -f /data/mong 12 hours ago Up 12 hours 49181->27017
0bffc776aec2 caseblocks/mongodb:latest mongod -f /data/mong 12 hours ago Up 12 hours 49180->27017

Step 4 - Configuring the MongoDB cluster

You now need to find out the IP addresses of the 3 MongoDB containers using the container id (which you can find in the docker ps output).

docker inspect 5c249b3b5e21

Amongst the big lump of JSON being returned you should see a NetworkSettings section

"NetworkSettings": {
    "IPAddress": "172.17.0.47",
    "IPPrefixLen": 16,
    "Gateway": "172.17.42.1",
    "Bridge": "docker0",
    "PortMapping": {
        "Tcp": {
            "27017": "49182"
        },
        "Udp": {}
     }
 },

Write down or copy and paste the IPAddress values.

Launch a mongo shell using a new container

docker run -i -t -entrypoint='mongo' yourname/mongodb 172.17.0.47/admin

Once in the shell execute the following MongoDB commands

rs.initiate()
rs.add('172.17.0.46')
rs.add('172.17.0.45')

Now you might have a problem with routing inside the cluster. The container from which you initiated the cluster will have used its hostname rather than IP address. The other two containers need an IP address to route to, so lets change that.

Retrieve the replicaset config

cfg = rs.conf()

You'll get output similar to

{
 "_id" : "cbrep",
 "version" : 3,
 "members" : [
 {
 "_id" : 0,
 "host" : "5c249b3b5e21:27017"
 },
 {
 "_id" : 1,
 "host" : "172.17.0.46:27017"
 },
 {
 "_id" : 2,
 "host" : "172.17.0.45:27017"
 }
 ]
}

You'll need to rewrite the first host entry in the members list above.

cfg.members[0].host = '172.17.0.47:27017'
rs.reconfig(cfg)

You should be all set now. You can confirm everything is running smoothly by checking the log files from your Docker host environment

tail /var/docker/mongodb1/data/mongodb.log
tail /var/docker/mongodb2/data/mongodb.log
tail /var/docker/mongodb3/data/mongodb.log

Feel free to leave comments and questions below. Good luck.