In the last post, I have explained about docker and built a node application with it. If you have no idea about docker then you can check that out here About Docker.
If you can know what is Docker and how does it works then let’s roll with Docker Compose.
Introduction to Docker Compose
Docker-compose is a tool that helps with the management of several different containers at once. If your docker application includes more than one container (for example, a web server, a backend server and database running in the separate containers), building, running, and connecting the containers from separate Dockerfiles is inconvenient and time-consuming. Docker-compose solves this problem by allowing you to use a YAML file to define multiple containers. Then, with a single command, you create and start all the containers from your configuration.
Using a Compose is a three-step process:
- Define your app’s environment with a
Dockerfile
so it can be reproduced anywhere. - Define your services that make up your app in
docker-compose.yml
so they can be run together in the isolated environments. - Run
docker-compose up
and Compose runs and starts your entire app.
Compose has commands for managing the whole lifecycle of your application:
- Start, stop and rebuild services
- View the status of running services
- Stream the log output of running application
- Run a one-off command on a service
Difference between Docker and Docker Compose
The docker
is used to manage individual containers on the Docker engine. Docker is a tool which is used by developer and operation teams to create an automated deployment of the application in a lightweight environment so that application work efficiently in a different environment.
The docker-compose
is used to manage multi-container applications. Containers run in isolation but can interact with each other. In Docker compose, a user can start all the services with the single command.
Build a node-mongo app with Docker Compose
Now you have a basic idea about docker-compose, will be building a sample application with NodeJS and MongoDB.
We will create separate isolated containers for NodeJS and MongoDB, and connect both of them with Docker Compose.
If you don’t have Docker installed on your machine, follow this guide to install Docker on your machine Docker Installation.
You can verify if docker-compose
is installed on your machine with this command:
# For Docker
docker --version
# For docker-compose
docker-compose --version
Create a node-mongo sample app
First, create a directory where all the files are going to live. In this directory, create a package.json
that is going to describe your app and its dependencies.
{
"name": "docker-node-mongo-app",
"version": "1.0.0",
"description": "It is a sample node-mongo application that is containerizated and deployed using.",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"dependencies": {
"express": "4.17.1",
"mongoose": "5.6.13"
}
}
Now you have listed all the dependencies inside the package.json
file, install them by running this command inside your terminal:
# If you are using yarn, you can run `yarn install`.
npm install
Then, will create an app.js
file that defines a node application using Express.js framework. Also, we will mongoose
package to connect to MongoDB inside this file.
const express = require('express')
const mongoose = require('mongoose')
const app = express()
const port = 8080
let mongoServiceRuning = false
// fix depreciation warning.
mongoose.set('useFindAndModify', false);
mongoose.set('useNewUrlParser', true);
// connect to mongodb
mongoose.connect('mongodb://mongo:27017/docker-node-mongo-app', function (err) {
console.log('mongodb connected ?', err ? false : true);
mongoServiceRuning = err ? false : true
});
app.get('/', (req, res) => {
res.send(`Node application containerised using docker that is ${mongoServiceRuning ? 'successfully connected to mongoDB' : 'unable to connect to mongoDB.'}`)
})
app.listen(port, () => console.log(`Example app listening on port ${port}!`))
This application will be listening on port 8080
. You can see inside this file, there is flag called mongoServiceRuning
app use this flag to track if this application has successfully connected to MongoDB based on the value true
and false
.
Also, you must be wondering about this mongodb://mongo:27017/docker-node-mongo-app
why this app is using mongo
rather than localhost
because here MongoDB will be running as separate service in the separate container and inside docker-compose YAML file will be exposing that service as mongo
.
Now we have created a node-mongo application, in the next steps, we will going to run this application inside the Docker containers.
Create a Dockerfile
In this step, you write a Dockerfile that will set up the app’s environment. This image contains all the dependencies that are required to run the application inside the docker container.
In this directory, create a file called Dockerfile
and paste the following:
FROM node:10
# Create a work dir
WORKDIR /user/src/app
# Copy package.json and package-lock.json in docker container
COPY package*.json ./
# Install all the dependencies for the application
RUN npm install
COPY . .
# Your app binds to port 8080 so you will have use EXPOSE instruction to have it mapped with docker daemon:
EXPOSE 8080
# CMD command defines your app runtime.
CMD ["node", "app.js"]
This tells Docker to:
- Use Nodejs image version 10.
- Next, it defined WORKDIR, this is where the app is going to live inside the container.
- Copy
package.json
inside the docker container. - Then, run
npm install
inside the docker container to install app’s dependencies. - Copy all the files from the current directory to docker WORKDIR.
- Your app is running on port 8080 inside the docker container, with this command this port gets mapped to docker daemon.
- Finally, with CMD command defines your app runtime.
Create a .dockerignore
file to ignores files that you don’t want to copy inside the docker container. For example:
node_modules
npm-debug.log
Define services in a Docker Compose file
Create a file called docker-compose.yml
in your project directory and paste the following:
version: '3'
services:
web:
container_name: docker-node-mongo-app
restart: always
build: .
ports:
- '8000:8080'
links:
- 'mongo'
mongo:
container_name: mongo
image: mongo
ports:
- '27017:27017'
This compose file defines two services web
and mongo
.
web
service
The web
services use the image that’s going to build from Dockerfile
in the current directory. It then binds the container (8080
) and host machine (8080
) to the exposed port, 8000
and 8080
. Also, it links this service to the mongo
service as well.
mongo
service
The mongo
service uses a public MongoDB image pulled from the Docker Hub registry.
Build and run this app with Docker Compose
From your project directory, start up your application by running docker-compose up
.
# Use `-d` option to run it in the detached mode.
docker-compose up -d
Compose pull the MongoDB and NodeJS image, builds an image for your code, and starts the defined services. In this case, the code statically copied to the image in build time.
To test your app, open http://localhost:8000 inside your browser. And you hopefully see this message in the web page:
Node application containerised using docker that is successfully connected to mongoDB
Use the following command to see if docker containers are running:
$ docker container ls
CONTAINER ID IMAGE CREATED STATUS PORTS
cee722aab6d7 docker-node-mongo-app_web 2 minutes ago Up About a minute 0.0.0.0:9000->8080/tcp
7f929fe48f00 mongo 2 minutes ago Up About a minute 0.0.0.0:27017->27017/tcp
You can bring everything down, remove the container entirely, with the docker-compose down
command as following:
docker-compose down
NOTE: docker-compose up
never rebuilds an image. Rebuild your image by the following command:
docker-compose build
At this point, you have seen the basics of how the Docker Compose works.
Check out the application source code here.
I hope you must have enjoyed it. I write articles like this every week, you can check those out here mountainfirefly.dev.