Getting started with Docker and MeanJS

We’re working on Coursality and found this great tutorial on running a MEAN stack on Docker.
http://blog.giantswarm.io/getting-started-with-docker-and-meanjs

To get started with a new technology it’s great to have a small, yet non-trivial example.Docker is an open-source project to easily create lightweight, portable, and self-sufficient containers from any application. We are using Docker as our core technology. With this tutorial we demonstrate how to use Docker by dockerizing MeanJS, a popular Node.JS Webstack.

One of the great features of Docker is the low barrier of entry. With the proper Dockerfile and Docker & fig installed it’s basically a simple fig up to get everything up and running. Here’s an ASCII cast for an overview:

Now let’s take a step back and see what this is all about.

Why MEAN.JS?

MEAN is an abbreviation for:

  • MongoDB: a document database,
  • Express: a web application framework for node,
  • Angular.JS: a client side JavaScript framework and
  • Node.JS: a somewhat popular JavaScript runtime.

Without arguing the different components and possible alternatives it’s easy to say that they are all very popular. If you are a JavaScript developer MEAN gives you a collection of effective and proven tools.

The term MEAN was coined in the MongoDB blog and it characterizes the collection of these tools. So there is no actual “THE Mean stack”. With its growing popularity there have been various projects, which glue these different components together and make it very easy to get started. The most prominent are a Yeoman MEAN generator, MEAN.io, and it’s fork MEAN.JS.

This tutorial discusses the dockerization of MEANJS.org but it should be easily applicable to the other MEAN stacks.

Motivation for Dockerization

When starting out with a web application, it’s common to start with one machine. But as the application grows the demand for the different parts changes. And as many software developers know: once something is mixed up it’s hard to split it up again. So why not start with different components from the get go?

systems2

When looking at the example MEAN.JS: Why not build a container for the database and the webserver and have each running in their own container respectively? In development they could still run on the same host, but when going into production these containers could be put on different machines.

The greatest objection is the increased effort in creating, starting, and maintaining these containers. We believe that the inital effort is very low and the long run benefit very high. Let us show you how easy it is to get started.

Prerequisites

If you haven’t done so far, please install Docker. For this tutorial please also install fig, which will make development much easier.

Ensure that both tools are installed:

$ docker version
$ fig --version

Build and run

The easiest way to get started is to clone the MEAN.JS fork with the proper Dockerfile:

$ git clone https://github.com/luebken/mean.git
$ cd mean

The easiest way to build and and run our two containers is fig. This tool looks at the project’s fig.yml and builds and runs the Docker containers appropriately:

Build the Docker containers with fig:

$ fig build

Run the Docker containers with fig:

$ fig up

That’s it.

Building and running your containers with pure Docker is just a little more complicated. Only the mean container needs to be built since the mongo container uses a predefined image.

Build the container with mean installed:

$ docker build -t mean .

  • -t mean tags the build image with mean

To get the application running the mongo needs be started first:

$ docker run -p 27017:27017 -d --name db mongo

  • -p 27017:27017 exposes the MongoDB port so the mean container can connect to it
  • -d runs it as a background
  • --name db gives this cointaner a name so it can be referenced
  • mongo is the image name that should be run

Next the mean container has to be started and connected to the db:

$ docker run -p 3000:3000 --link db:db_1 mean

  • -p 3000:3000 exposes the webserver port 3000
  • -d runs it as a background
  • --link db:db_1 links the db container

Again. That’s it.

Fig actually does the same thing. And to recapitulate let’s examine fig’s yml file:fig.yml:

web:
  build: .
links:
- db
ports:
- "3000:3000"
db:
image: mongo
ports:
- "27017:27017"

For a detailed explanation see the fig reference.

To the virtual box / boot2docker users don’t forget to enable port forwarding for the appropriate ports:

VBoxManage modifyvm "boot2docker-vm" --natpf1 "tcp-port3000,tcp,,3000,,3000";

Wether we started with fig or with docker, opening the browser at localhost:3000should show the MEAN.JS starting site:

Docker_MeanJS

Now, let’s examine what the two containers are about.

The database container

The database container doesn’t require custom code. This is because it uses the official predefined mongo image: registry.hub.docker.com/_/mongo. Currently the Dockerfile, from which the image is built is not linked but can be found here: github.com/docker-library/mongo.

Here are some commands for fooling around with the mongo image:

# Pull the official image:
$ docker pull mongo
# Run a mongo container in open a bash shell in it:
$ docker run -i -t mongo /bin/bash
# Inspect the different layers
$ docker history mongo
# Show low-level information on a container
$ docker inspect mongo

With databases the foremost question is where it stores its data. An examination of themongo Dockerfile shows near the end that it marks /data/db as a volume: VOLUME /data/db.

For detailed information on volumes see the userguide but to get started, you might want to examine the volume and backup the data:

# Run docker inspect and filter for the volumes mounted
$ docker inspect --format '' mean_db_1

# To run a simple backup command start
$ docker run --volumes-from db -v $(pwd):/backup ubuntu tar cvf /backup/backup.tar /data/db

Mean.JS Dockerfile

The container with the mean application is a little more interesting:

FROM dockerfile/nodejs
MAINTAINER Matthias Luebken, matthias@giantswarm.io
WORKDIR /home/mean

# Install Mean.JS Prerequisites
RUN npm install -g grunt-cli RUN npm install -g bower

# Install Mean.JS packages
ADD package.json /home/mean/package.json RUN npm install

# Manually trigger bower
ADD .bowerrc /home/mean/.bowerrc
ADD bower.json /home/mean/bower.json
RUN bower install --config.interactive=false --allow-root

# Make everything available for start
ADD . /home/mean

# currently only works for development
ENV NODE_ENV development

# Port 3000 for server Port 35729 for livereload
EXPOSE 3000 35729

# Run
CMD ["grunt"]

A Dockerfile is a set of instructions to build and create an image. After each instruction the docker build commits a new layer. If a layer hasn’t changed, it doesn’t need to be rebuilt the next time the build runs. Instead the cached layers are used. This layering system is one of the reasons why Docker is so fast.

Let’s go through a brief overview of the instructions used in this Dockerfile:

  • FROM tells the Docker with which image to start. All Docker images need to have one root image / layer. In this case it is dockerfile/nodejs.
  • RUN starts arbitrary commands during the build process. The first two are installing the tools bower and grunt.
  • ADD adds files from the host file system into the Docker container. In the first instance the package.json is added so that in a subsequent step the packages can be installed via package.json.
  • Note that there are several ADD and RUN instructions. The reason for this are the different layers. For example as long as the package.json is not changed the appropriate layer is not changed. Docker can use the existing layer. So new NPM packages only get installed if needed.
  • ENV sets environment variables.
  • EXPOSE exposes PORTS from the container.
  • CMD sets the command that is executed once the container is run.

Be the first to comment

Leave a Reply