A quick dive into MongoDB and Docker
www.mongodb.com

A quick dive into MongoDB and Docker

In times where everyone talks about DevOps, containers and docker I decided that I, as a Engineer and Projectmanager can no longer wait to get my own view on this. Well and it was worth to do so. Let me share some of my experiences, and please do not take this as a deep dive.

Before we begin to set up a simple node.js / mongodb app which we dockerize later please make sure you have Node.js, npm, express and Docker installed.

The tryout Node app

Let’s start by creating the Node.js app. For this we use the express generator. If you have express not yet installed please do so via:

npm install -g express

npm install -g express-generator

Then cd into a directory you want and create the tryout-app:

$ express tryout-app
   create : tryout-app
   create : tryout-app/package.json
   create : tryout-app/app.js
   create : tryout-app/publiccreate : tryout-app/routes
   create : tryout-app/routes/index.js
   create : tryout-app/routes/users.js
   create : tryout-app/views
   create : tryout-app/views/index.jade
   create : tryout-app/views/layout.jade
   create : tryout-app/views/error.jade
   create : tryout-app/bincreate : tryout-app/bin/www
   create : tryout-app/public/javascripts
   create : tryout-app/public/images
   create : tryout-app/public/stylesheets
   create : tryout-app/public/stylesheets/style.css

   install dependencies:
     $ cd tryout-app && npm install

   run the app:
     $ DEBUG=tryout-app:* npm start

Just go ahead and install the needed dependencies, as printed out and run the tryout-app

DEBUG=tryout-app:* npm start
> tryout-app@0.0.0 start /home/mi01/Projects/mongodb-docker/tryout-app
> node ./bin/www
tryout-app:server Listening on port 3000 +0ms

Head over to your browser and open up http://localhost:3000 You should see the “Welcome to Express” page. You should see the “Welcome to Express” page.


Let’s go to the dock

Ok, ok too early for a beer. So let’s get some work done... The absolute basic tryout.app is there, so next is to move this to docker.

The first thing to think about is to choose an image which we we’ll use to run our app container. There are many different choices. The most popular and easy choice might be the official Node.js image. I poked a little bit around and found that this is compressed already over a 190 MB large. Little bit much for this tryout. I came across a Dockerfile which is using the alpine image it uses a minimal linux so that some package need to be installed but a compressed size of 2 MB made me curious.

The Dockerfile

Go to the just created tryout-app folder and create a file named Dockerfile. This file contains the instructions order to build the project image. Please use the following content:

# the image is based on alpine-node

FROM mhart/alpine-node:latest
RUN rm -rf /tmp/node_modules
ADD package.json /tmp/package.json
RUN cd /tmp && npm install
RUN mkdir -p /opt/app && cp -a /tmp/node_modules /opt/app/
WORKDIR /opt/app
ADD . /opt/app
EXPOSE 3000
CMD ["npm", "start"]


Building the image, running the container

In order to build our Docker image we’ll use the docker build command. Head over to your console and in the project root directory run the following:

docker build -t tryout-app .
Successfully built 8827c4c8874b
Successfully tagged tryout-app:latest

You can check the built image in your local images list:

$ docker images 
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
tryout-app          latest              8827c4c8874b        28 seconds ago      87.6MB

Once you’ve built the image, you can run it on a container. Please stop the local server if it is still running and fire up the following command:

$ docker run -p 3000:3000 -ti tryout-app

> tryout-app@0.0.0 start /opt/app

> node ./bin/www

Super!! Seems to be ok. You want to see something? Just go to the browser and open up http://localhost:3000 again. You get the “Welcome to Express” page again. But this time out of your image! By the way 3000:3000 is a kind of port redirect. The container, which doesn’t know you mapped port 3000 of that container to 3000, making the correct URL http://localhost:3000. So you can have a different public port as the one you exposed in the dockerfile.


Docker Compose

For a simple webapp, it’s easy with a single Dockerfile and using docker build and docker run. But when we have multiple containers as we will later with MongoDB, it becomes a bit more complex.

Docker comes with a very useful tool called docker-compose. This tool allows us to define all of our container and the relationships between them in a single docker-compose.yml file. So let’s build the docker-compose file for the same configuration we ran before later we’ll add a MongoDB container and connect them. Create a docker-compose.yml file in the project root and put the following contents in it:

services:
web:
build: .
Ports:
- "3000:3000"

A quick glance on it:

- use version 2 of Docker Compose config syntax

- define all the services that will be run (for the beinning this is only a webservice)

- build in the current directory . is the target

- define the port mappings for the container, which are the same we used before with the -p option of the docker run command.

Now we can build and run the container via docker-compose. In case this is not installed please check this page

docker-compose build

This will build the image. Again you will get a message similar to this one:

Successfully built d077df0fb8a1
Successfully tagged tryoutapp web:latest

Then you can run the container with

 docker-compose up


Bring MongoDB to the game

So, the basic stuff is working, up and running. Let’s add some database stuff to the app now. The containers will be able to communicate to each other at the end via some more configuration in the same docker-compose.yml file.

First we need the mongodb driver for our project, so let us add this to the package.json (the ^ will make sure we get the minor version updates)

"mongodb": "^2.2.9"

Let’s add a new rout to routes/index.js that will connect to a MongoDB and return some data from the dummy collection. The route file will look like this:

var express = require('express');
var router = express.Router();
var mongodb = require('mongodb');
var client = mongodb.MongoClient;

var uri = "mongodb://mongo/tryout-app";

/* GET home page. */
router.get('/', function(req, res, next) {
  res.render('index', { title: 'Express' });
});

router.get('/data/from/db', function(req, res, next) {
    client.connect(uri, function (err, db) {
            if (err) return next(err);    
        var collection = db.collection('tryout');
        collection.find({}).toArray(function(err, docs) {
                        if (err) return next(err);
                        return res.json(docs);
        });                     
        });
});

The URL is mongo to refer to the host of the database. This is because our MongoDB container will have that name and we’ll link it to our webapp container so that they know each other, more on this later.

We’ll add another route to create some data in the collection as well:

router.post('/data/into/db', function(req, res, next) {
        client.connect(uri, function (err, db) {
            if (err) return next(err);
        var collection = db.collection('tryout');
        collection.insertMany(req.body, function(err, result) {
                        return res.json({ result: "success" });
        });
        });
});

This route simply takes an array sent in the request body and inserts all the objects in the array into the tryout collection.


MongoDB container

Now we can connect to a MongoDB instance, so it is time to setup a container to run the MongoDB. Lets add some lines to the docker-compose.yml file:

version: "2"
services:
web:
build: .
Ports:
- "3000:3000"
links:
- mongo
mongo:
image: mongo
volumes:
- /data/mongodb/db:/data/db
ports:
- "27017:27017"

The “links” tag is where the containers get “connect” so that they can reference each other. This is what allows us to use a MongoDB connection URL like mongodb://mongo/tryout. The mongo in the URL references the mongo container that we define little bit further down of the docker-compose file.

Then we tell Docker to mount the host directory /data/mongodb/db into the container /data/db directory. This is not a must, you can even create another special container which is simply a volume you can mount in any container you want.

Finally we tell Docker to map the port 27017 on the host to the port 27017 on the container so that we can connect to the MongoDB server from any client we have in our local host.

Now we can build the and run the stuff via: docker-compose build and docker-compose up 

Again you can see the welcome page in the browser on localhost:3000 

Here comes the interesting part: we will now insert data to MongoDB by using the endpoint POST /data/into/db.

$ curl -X POST -H "Content-type: application/json" http://localhost:3000/data/into/db \
    -d '[ { "a": 1 }, { "b": 2 }, { "c": 3 } ]'

You shoud get a {"result":"success"} back

Best of all let’s get the data back… by using our other endpoint GET /data/from/db 

 curl http://localhost:3000/data/from/db
[{"_id":"5a05baeabd0eba00109a9e81","a":1},{"_id":"5a05baeabd0eba00109a9e82","b":2},{"_id":"5a05baeabd0eba00109a9e83","c":3}]

That’s it. Just a quick note the code in this example is really “tryout” so please do not use this in any productive environment. But for the basic concepts this should be ok.

The complete code can be found here

Have fun with you next containers :-)

Michael






To view or add a comment, sign in

More articles by Michael Höller

  • Oh no, YAML – Yet an other MongoDB Love story ???

    Since many of us already know about the advantages of MongoDB, and since there are already quite a bit of great post…

  • MongoDB 3.6 - a view on its new features

    There are plenty new features, therefore MongoDB grouped them in categories: Speed to Develop: Change streams…

  • MongoDB in the Java-World ?

    MongoDB is well know as a matured noSQL Database, it can show its power in a lot of areas but would you have thought…

  • MongoDB released two major updates in MongoDB Atlas

    You can now replicate across regions to reduce latency for global users or to be more resilient to data center failure.…

  • Optimize Data Durability with MongoDB

    The primary sense of a database is to be a base of data. Pretty simple.

  • How can DevOps improve your apps?

    Can DevOps do that? Some people seem to consider the discussions about DevOps as just another hype. Let‘s cleanup the…

  • Backend as a service for MongoDB - MongoDB Stitch

    Based on the growing demand for a backend-as-a-service product, MongoDB decided to build Stitch, it’s own…

  • MongoDB Wizards - your wands get an upgrade!

    MongoDB 3.4 has been announced, the new version provides some real cools features.

  • Why the document model?

    In this blog post I want you to tell about the benefits of using MongoDB's document model for an application. As a…

    1 Comment
  • MongoDB Wizards catch your brooms!

    MongoDB Wizards catch your brooms! See you at MongoDB World 2017 Summit, June 20-21 in Chicago! Vote for my photo so I…

    1 Comment

Others also viewed

Explore content categories