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'