Docker Compose gives us the ability to define and orchestrate multiple containers in order to construct a service. In this article, we will use Docker Compose to create a MongoDB server and then another container that is used exclusively as a MongoDB client.
While it is entirely possible to manually create these containers, links, and set environment variables to the same affect; Docker Compose gives us a way to capture these relationships and standardize the process of deployment.
Prerequisites
If you haven’t installed Docker and Docker Compose, read my article here for full instructions.
Then install a git client so you can grab my source code from github.
$ sudo apt-get install git -y $ git clone https://github.com/fabianlee/docker-mongodb.git $ cd docker-mongodb
Build Docker image
The MongoDB server image is coming from the official repository, and will be downloaded when required. But our MongoDB client will be custom built on top of the alpine base image. The 4.2 version of the Mongo server was intentionally paired with Alpine 3.9 to use the 4.0.5 Mongo client from the Alpine community repository.
The Dockerfile for building this client is found in the subdirectory at my-mongoclient/Dockerfile, so in the docker-compose.yml we have specified that directory as shown below.
mongoclient: build: ./my-mongoclient image: fabianlee/my-mongoclient:3.9
Run the following command to build the image, and then get an image listing from docker and you should see a new available image named ‘fabianlee/my-mongoclient’.
$ sudo docker-compose build $ sudo docker-compose images Container Repository Tag Image Id Size ---------------------------------------------------------------- fabianlee/my-mongoclient 3.9 d74939567c02 125 MB mongo 4.2.3-bionic 14c497d5c758 386 MB
Run Compose
To bring up all the services in docker-compose.yml, run the following command.
$ sudo docker-compose up -d Creating network "docker-mongodb_mongo_net" with driver "bridge" Creating my-mongoclient ... done Creating my-mongodb ... done
Listing the running docker containers should show two running containers.
$ sudo docker-compose ps Name Command State Ports --------------------------------------------------------------------------------------------- my-mongoclient /bin/sleep 1d Up my-mongodb docker-entrypoint.sh mongod Up 0.0.0.0:27017->27017/tcp
Validate MongoDB server
Let’s validate the MongoDB server by tailing the logs. Using docker-compose this can be done by simply using:
$ sudo docker-compose logs -f my-mongodb
This is an example of docker-compose being able to intelligently understand its deployment context because for comparison ‘docker logs’ will also allow us to tail the logs of a container, but it requires the container id.
$ docker logs -f $(docker ps -f ancestor=mongo | tail -n 1 | awk {'print $1'})
We will see more output once when attempt a client connection in the section below.
Validate MongoDB client
We have one host console tailing the MongoDB server logs, so we need to open up a new host console so we can test the client container. After doing so and navigating back to the ‘docker-mongodb’ directory, issue the following command to start a shell inside the container.
$ sudo docker-compose exec my-mongoclient /bin/sh
Then run the command below to have the MongoDB client connect to server using the proper credentials which have been inserted into the environment. We are able to use ‘targetmongo’ as the hostname because that is how we linked it in docker-compose.yml.
mongo $MONGO_SERVER/$MONGO_INITDB_DATABASE -u $MONGO_INITDB_ROOT_USERNAME -p $MONGO_INITDB_ROOT_PASSWORD
This connection will result in a log entry on the server that looks like ‘Successfully authenticated as principal admin on test’. It will also show ‘unauthorized’ messages which are simply because the user is not a global administrator.
Test pulling data from the collection by issuing the following command at the client, and then ‘exit’.
> db.test.find().pretty() { "_id" : ObjectId("5b01a461e0aaab4d3c56eaea"), "myfield" : "test1", "anotherfield" : "TEST1" } { "_id" : ObjectId("5b01a461e0aaab4d3c56eaeb"), "myfield" : "test2", "anotherfield" : "TEST2" } > exit
Typing ‘exit’ one more time will exit the “/bin/sh” shell of the container and get you back to the host.
REFERENCES
https://docs.docker.com/compose/overview/
https://docs.docker.com/compose/compose-file/
https://docs.docker.com/compose/reference/run/
https://pkgs.alpinelinux.org/package/edge/community/x86_64/mongodb (alpine package for mongodb)
https://stackoverflow.com/questions/34559557/how-to-enable-authentication-on-mongodb-through-docker (using javascript to create user in database)
http://ignaciosuay.com/how-to-connect-to-mongodb-3-0-using-spring-boot/ (connecting to Mongo 3)
https://www.programcreek.com/java-api-examples/?api=com.mongodb.MongoCredential (Connecting using latest Mongo 3)
https://blog.kevinchisholm.com/javascript/mongodb/getting-started-with-mongo-shell-scripting-basic-crud-operations/ (mongodb javascript)
https://jbouffard.fr/article/use-case-add-an-init-script-to-the-docker-official-mongo-image (init script for mongo container)
https://lakshminp.com/docker-mongodb (customized shell scripts for mongo docker startup)
NOTES
To run only specific container in docker-compose
sudo docker-compose run mongoclient
long docker commands that get easier with docker-compose
docker logs -f $(docker ps -f ancestor=mongo | tail -n 1 | awk {‘print $1’})
docker exec -it $(docker ps -f ancestor=my-mongoclient | tail -n 1 | awk {‘print $1’}) /bin/sh
delete containers and delete named volumes
sudo docker-compose down -v
get Mongo database version
db.version()