Working with Docker-Compose

This article gives you a quick start on how to use docker-compose and scenario in which it will be useful. Compose is a tool for defining and running multi-container Docker applications.

Working with docker-compose

To demonstrate the usage of docker compose, lets create a project whose sole purpose is to show the number of visits to the website.

Prerequistes
  1. A webserver - Node app
  2. Redis - to keep track of visits
Solution 1

Single container with node and redis running in it.

Problem

In case of scaling up your application where you have multiple containers running both node and redis in it, one redis instance thinks that page has been visited once whereas others think it has been visited 100 times.

Solution 2

Multiple node containers(containing the web site) talking to the single redis container. Add following files to the project directory where you want your application

1.index.js

const express = require('express');
const redis = require('redis');

const app = express();
const client = redis.createClient();
client.set('visits', 0);

app.get('/', (req, res) => {
  client.get('visits', (err, visits) => {
    res.send('Number of visits is ' + visits);
    client.set('visits', parseInt(visits) + 1);
  });
});

app.listen(8081, () => {
  console.log('Listening on port 8081');
});

2.package.json

{
  "dependencies": {
    "express": "*",
    "redis": "2.8.0"
  },
  "scripts": {
    "start": "node index.js"
  }
}

3.Dockerfile for the node container

FROM node:alpine
WORKDIR /app
COPY ./package.json .
RUN npm install
COPY . .
CMD ["npm","start"]

4.docker-compose.yml

With this we introduce the docker compose. It is used for networking between containers using the docker cli. In above use case we want two containers talking to each other. Docker Compose makes them available to each other without any constratints.

#version of the docker-compose we want to work with
version: '3' 
#services refered to containers
services:
    #first container
	redis-server: 
        #name of the image
		image: 'redis'
    #second container    
	node-app: 
        #build the container from the current directory and Dockerfile
		build: .
		ports:
            # - in a .yaml file is equivalant to specifying the array
			- "8081:8081"

Note: in docker-compose.yml do not use tab, instead use spaces to indent the tags properly

Starting the application with the docker compose
$ docker-compose up -d  // -d means run in background
or
$ docker-compose up --build

Stopping the docker-compose

docker-compose down
Managing the container crash with the docker-compose

For automatic container restart we need to specify the restart policy inside a docker-compose.yaml e.g. “no” or “always” or “on-failure” or “unless-stopped” The updated docker-compose.yml file:

version: '3'
services:
  redis-server:
    image: 'redis'
  node-app:
    #added a restart policy for one of the container
    restart: always
    build: .
    ports:
      - "8081:8081"
Volumes with docker-compose

We have seen how volume works in the last article, now lets see how we introduce the same using docker-compose. A complete docker-compose.yml is as follows:

version: '3'
services:
 web:
  build: 
   context: .
   dockerfile: Dockerfile.dev
  ports:
   - "3000:3000"
  volumes:
   - /app/node_modules
   - .:/app

As mentioned in the previous article on docker that there are many approaches to run many containers at once docker-compose is one of them. Others are listed below

Next steps

  • Kubernetes
  • Docker Swarm