Docker Compose: Node.js Express and MongoDB example

Docker provides lightweight containers to run services in isolation from our infrastructure so we can deliver software quickly. In this tutorial, I will show you how to dockerize Nodejs Express and MongoDB example using Docker Compose.

Related Posts:

Dockerize fullstack:
Docker Compose: React + Node.js Express + MongoDB


Node.js Express and MongoDB with Docker Overview

Assume that we have a Nodejs Application working with MongoDB database.
The problem is to containerize a system that requires more than one Docker container:

  • Node.js Express for API
  • MongoDB for database

Docker Compose helps us setup the system more easily and efficiently than with only Docker. We’re gonna following these steps:

  • Create Nodejs App working with MongoDB database.
  • Create Dockerfile for Nodejs App.
  • Write Docker Compose configurations in YAML file.
  • Set Environment variables for Docker Compose
  • Run the system.

Directory Structure:

docker-compose-nodejs-mongodb-example-structure

Create Nodejs App

You can read and get Github source code from one of following tutorials:

Using the code base above, we put the Nodejs project in bezkoder-app folder and modify some files to work with environment variables.

Firstly, let’s add dotenv module into package.json.

{
  ...
  "dependencies": {
    "dotenv": "^10.0.0",
    ...
  }
}

Next we import dotenv in server.js and use process.env for setting port.

require("dotenv").config();
..
// set port, listen for requests
const PORT = process.env.NODE_DOCKER_PORT || 8080;
app.listen(PORT, () => {
  console.log(`Server is running on port ${PORT}.`);
});

Then we change modify database configuration and initialization.

app/config/db.config.js

const {
  DB_USER,
  DB_PASSWORD,
  DB_HOST,
  DB_PORT,
  DB_NAME,
} = process.env;

module.exports = {
  url: `mongodb://${DB_USER}:${DB_PASSWORD}@${DB_HOST}:${DB_PORT}/${DB_NAME}?authSource=admin`
};

We also need to make a .env sample file that shows all necessary arguments.

bezkoder-app/.env.sample

DB_HOST=localhost
DB_USER=root
DB_PASSWORD=123456
DB_NAME=bezkoder_db
DB_PORT=27017

NODE_DOCKER_PORT=8080

Create Dockerfile for Nodejs App

Dockerfile defines a list of commands that Docker uses for setting up the Node.js application environment. So we put the file in bezkoder-app folder.

Because we will use Docker Compose, we won’t define all the configuration commands in this Dockerfile.

bezkoder-app/Dockerfile

FROM node:14

WORKDIR /bezkoder-app
COPY package.json .
RUN npm install
COPY . .
CMD npm start

Let me explain some points:

  • FROM: install the image of the Node.js version.
  • WORKDIR: path of the working directory.
  • COPY: copy package.json file to the container, then the second one copies all the files inside the project directory.
  • RUN: execute a command-line inside the container: npm install to install the dependencies in package.json.
  • CMD: run script npm start after the image is built.

Write Docker Compose configurations

On the root of the project directory, we’re gonna create the docker-compose.yml file. Follow version 3 syntax defined by Docker:

version: '3.8'

services: 
    mongodb:
    app:

volumes:
  • version: Docker Compose file format version will be used.
  • services: individual services in isolated containers. Our application has two services: app (Nodejs) and mongodb (MongoDB database).
  • volumes: named volumes that keeps our data alive after restart.

Let’s implement the details.

docker-compose.yml

version: "3.8"

services:
  mongodb:
    image: mongo:5.0.2
    restart: unless-stopped
    env_file: ./.env
    environment:
      - MONGO_INITDB_ROOT_USERNAME=$MONGODB_USER
      - MONGO_INITDB_ROOT_PASSWORD=$MONGODB_PASSWORD
    ports:
      - $MONGODB_LOCAL_PORT:$MONGODB_DOCKER_PORT
    volumes:
      - db:/data/db
  app:
    depends_on:
      - mongodb
    build: ./bezkoder-app
    restart: unless-stopped
    env_file: ./.env
    ports:
      - $NODE_LOCAL_PORT:$NODE_DOCKER_PORT
    environment:
      - DB_HOST=mongodb
      - DB_USER=$MONGODB_USER
      - DB_PASSWORD=$MONGODB_PASSWORD
      - DB_NAME=$MONGODB_DATABASE
      - DB_PORT=$MONGODB_DOCKER_PORT
    stdin_open: true
    tty: true

volumes:
  db:

mongodb:

  • image: official Docker image
  • restart: configure the restart policy
  • env_file: specify our .env path that we will create later
  • environment: provide setting using environment variables
  • ports: specify ports will be used
  • volumes: map volume folders

app:

  • depends_on: dependency order, mongodb is started before app
  • build: configuration options that are applied at build time that we defined in the Dockerfile with relative path
  • environment: environmental variables that Node application uses
  • stdin_open and tty: keep open the terminal after building container

You should note that the host port (LOCAL_PORT) and the container port (DOCKER_PORT) is different. Networked service-to-service communication uses the container port, and the outside uses the host port.

Docker Compose Environment variables with MongoDB

In the service configuration, we used environmental variables defined inside the .env file. Now we start writing it.

.env

MONGODB_USER=root
MONGODB_PASSWORD=123456
MONGODB_DATABASE=bezkoder_db
MONGODB_LOCAL_PORT=7017
MONGODB_DOCKER_PORT=27017

NODE_LOCAL_PORT=6868
NODE_DOCKER_PORT=8080

Run Nodejs MongoDB with Docker Compose

We can easily run the whole with only a single command:
docker-compose up

Docker will pull the MongoDB and Node.js images (if our machine does not have it before).

The services can be run on the background with command:
docker-compose up -d

$ docker-compose up -d
Creating network "node-mongodb_default" with the default driver
Creating volume "node-mongodb_db" with default driver
Pulling mongodb (mongo:5.0.2)...
5.0.2: Pulling from library/mongo
16ec32c2132b: Pull complete
6335cf672677: Pull complete
cbc70ccc8ebe: Pull complete
0d1a3c6bd417: Pull complete
960f3b9b27d3: Pull complete
aff995a136b4: Pull complete
4249be7550a8: Pull complete
cc105ff5aa3c: Pull complete
82819807d07a: Pull complete
81447d2c233f: Pull complete
Digest: sha256:54d24682d00278f64bf21ff62b7ee62b59dae50f65139831a884b345922b0f8a
Status: Downloaded newer image for mongo:5.0.2
Building app
Sending build context to Docker daemon  19.46kB
Step 1/6 : FROM node:14
14: Pulling from library/node
eb18d230e067: Pull complete 
83600c1b4583: Pull complete 
4ae15c65bfa0: Pull complete 
c19c058edda5: Pull complete 
05cdaa0fd103: Pull complete 
8461dcff50c4: Pull complete 
84be4117f79d: Pull complete 
4ccb803887fd: Pull complete 
ab52680a5469: Pull complete 
Digest: sha256:c1fa7759eeff3f33ba08ff600ffaca4558954722a4345653ed1a0d87dffed9aa
Status: Downloaded newer image for node:14
 ---> 256d6360f157
Step 2/6 : WORKDIR /bezkoder-app
 ---> Running in 71b4b2e9dd6c
Removing intermediate container 71b4b2e9dd6c
 ---> 194372d3695c
Step 3/6 : COPY package.json .
 ---> 093f866b404a
Step 4/6 : RUN npm install
 ---> Running in 025f0f0365a9
npm notice created a lockfile as package-lock.json. You should commit this file.
npm WARN [email protected] No repository field.

added 81 packages from 128 contributors and audited 81 packages in 6.902s

2 packages are looking for funding
  run `npm fund` for details

found 0 vulnerabilities

Removing intermediate container 025f0f0365a9
 ---> 2f04aeaa93b1
Step 5/6 : COPY . .
 ---> 50e31a045a02
Step 6/6 : CMD npm start
 ---> Running in 7353ac17fa02
Removing intermediate container 7353ac17fa02
 ---> bd9d66054ea2
Successfully built bd9d66054ea2
Successfully tagged node-mongodb_app:latest
WARNING: Image for service app was built because it did not already exist. To rebuild this image you must use `docker-compose build` or `docker-compose up --build`.
Creating node-mongodb_mongodb_1 ... done
Creating node-mongodb_app_1     ... done

Now you can check the current working containers:

$ docker ps
CONTAINER ID   IMAGE              COMMAND                  CREATED         STATUS         PORTS                                         NAMES
42b9271dd73f   node-mongodb_app   "docker-entrypoint.s…"   2 minutes ago   Up 2 minutes   0.0.0.0:6868->8080/tcp, :::6868->8080/tcp     node-mongodb_app_1
e17bf545c0ba   mongo:5.0.2        "docker-entrypoint.s…"   2 minutes ago   Up 2 minutes   0.0.0.0:7017->27017/tcp, :::7017->27017/tcp   node-mongodb_mongodb_1

And Docker images:

$ docker images
REPOSITORY            TAG            IMAGE ID       CREATED         SIZE
node-mongodb_app      latest         bd9d66054ea2   5 minutes ago   960MB
node                  14             256d6360f157   6 minutes ago   944MB
mongo                 5.0.2          269b735e72cb   6 minutes ago   682MB

Let’s send an HTTP request to check the Express Rest API:

docker-compose-nodejs-mongodb-example-test-api

And the MongoDB database also:

docker-compose-nodejs-mongodb-example-test-database

Stop the Application

Stopping all the running containers is also simple with a single command:
docker-compose down

$ docker-compose down
Stopping node-mongodb_app_1     ... done
Stopping node-mongodb_mongodb_1 ... done
Removing node-mongodb_app_1     ... done
Removing node-mongodb_mongodb_1 ... done
Removing network node-mongodb_default

If you need to stop and remove all containers, networks, and all images used by any service in docker-compose.yml file, use the command:
docker-compose down --rmi all

$ docker-compose down --rmi all
Stopping node-mongodb_app_1     ... done
Stopping node-mongodb_mongodb_1 ... done
Removing node-mongodb_app_1     ... done
Removing node-mongodb_mongodb_1 ... done
Removing network node-mongodb_default
Removing image mongo:5.0.2
Removing image node-mongodb_app

Conclusion

Today we’ve successfully created Docker Compose file for Nodejs and MongoDB application. Now we can deploy Nodejs Express and MongoDB with Docker on a very simple way: docker-compose.yml.

You can apply this way to one of following project:

Or Dockerize fullstack:
Docker Compose: React + Node.js Express + MongoDB

Happy Learning! See you again.

Source Code

The source code for this tutorial can be found at Github.

You can deploy the container on Digital Ocean with very small budget: 5$/month.
Using referral link below, you will have 100$ in credit over 60 days. After that, you can stop the VPS with no cost.

DigitalOcean Referral Badge

2 thoughts to “Docker Compose: Node.js Express and MongoDB example”

  1. Thank you for this tutorial and related ones! Very helpful

    What are possible next steps to host the container so we can access the API online?

Leave a Reply

Your email address will not be published. Required fields are marked *