Setting Up Multiple Local Containers with Docker Compose

Setting Up Multiple Local Containers with Docker Compose

Lessons learned from a Udemy course on managing local containers with Docker Compose.

App overview:

Developed a Node.js Application that uses Redis for data storage, and Orchestrated the containers using Docker Compose.

step1: set up directory and initialized Node.js Application with index.js & package.json

'index.js' holds Node.js application,

//importing the Express framework to create a web application
const express = require('express');
const redis = require('redis'); // importing Redis client  library to interact with Redi server

const app = express(); //An instance of express application
const client = redis.createClient({
    host: 'redis-server'  //host name of Redis server defined docker-compose file
    port: 6379  //default port no for Redis
}); //An instance of a redis client to connect to redis server.
client.set('visits', 0); //Initializing a key 'visits' in Redis with the value 0

app.get('/', (req, res) => { // defining a route handler for the root url ('/')
  client.get('visits', (err, visits) => { //fetching current no. of visits from Redis
    res.send('Number of visits ' + visits); //sending no. visits as the response
    client.set('visits', parseInt(visits) + 1);// incrementing the visits count in Redis by 1
  });
});
//starting the server on port 8081 and logging a message to a console
  app.listen(8080, () => {
  console.log('listening on port 8080');
});

'pacakage.json' file below responsible for defining projects dependencies, scripts,version and other details.

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

Step 2: Creating 'Dockerfile' to containerize the application

#Base image
FROM node:alpine

WORKDIR '/app' ## Set the working directory
# Copy the pacakage.json to the container
COPY package.json . 
#install project dependencies
RUN npm install
#copy rest of the application  code to the working dir
COPY . .
#command to run the application.
CMD ["npm","start"]

Handling Redis connection issue:
~cd visits ~doker build -t thilsga/visits: latest . ~docker run thilaga/visists

//error message

C:\Users\thilaga\Documents\docker\simpleweb> docker run thilaga/node
@ start /app node index.js
listening on port 8081 events.js:377 throw er; // Unhandled 'error' event ^
Error: getaddrinfo EAI_AGAIN redis-server at GetAddrInfoReqWrap.onlookup [as oncomplete] (dns.js:71:26) Emitted 'error' event on RedisClient instance at:

Above error would face because redis image is not there. Even if we run Docker run redis from image - While running you may face redis server not connected error

To connect both containers redis & Express(node app) we can use docker cli’s network features or docker compose(separate cli that gets installed along with Docker).

Advantages of Docker compose:
used to start up multiple containers
used to automate some of the long-winded arguments which we parse through ‘docker run ‘ Example:
~docker build -t thilaga/visits:latest ~docker run -p 8080:8080 thilaga/visits

Step 3: Creating docker-compose.yml File to manage multi-container setup:
Networking with compose- we can use or call containers by the name in .yml file
--important is that we should use host name in web code. (add host: & port mentioned in yml)

version: '3' # version Docker compose
services: # containers to be created
  redis-server: #redis service name (container)
    image: 'redis' #official redis image
    restart: always # whenever stops restart always
  node-app: # node.js service name (conatiner)
    build: . #build docker image from current directory
    ports: # map ports
      - '8081:8080'#4001 on the host (local) & to port 8081 on the container

Few Docker compose commands utilized:
~docker-compose up (instead of run //start all service defined in docker-compose file)
(~docker-compose up –build) – to rebuild and run (rebuild image before starting up services)
~docker-compose up -d (to run group of containers - start services in detached mode)
~docker ps // list all running containerr
~docker-compose down //stop and remove all containers
When visits localhost:4001 - should see a message like "Number of visits is 0"
Evert time refresh the page number should increment by 1.

Note: Automate Container Restarts with Docker Compose
"no" (default) : Do not automatically restart the container
always: Always restart the container if it stops
on-failure: Restart the container only if it exits with non-zero
unless-stopped: Always restart unless we forcibly stop it.

We will not be able to run always build a image and run container whenever changes made in code right?
So Docker Volumes helps in solving this by referring the local data.
Docker Volumes:
-to persist data outside the container so it can be backed up or shared.
-developers can ensure that data remains intact even when containers are stopped or removed.
-Sharing Data Between Containers: Volumes can be shared between multiple containers, -allowing them to access and manipulate the same data.
example: ~docker run -p 5000:5000 -v /app/node-modules -v ${PWD}:/app pyweb we can configure this in docker-compose cli instead of docker cli

version: "3"
services:
  pythonweb:
    build:
      context: .
      dockerfile: Dockerfile
    ports:
      - "5000:5000"
    volumes:
      - .:/app
      - /app/node-modules
  • '- .:/app' - maps current directory to /app in the container

  • '- /app/node-modules - ensures node-modules persistent and overridden by local 'node-modules'