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:
- Node.js Express Rest API with MongoDb
- Node.js Express Pagination with Mongoose and MongoDB
- Node.js + MongoDB: User Authentication & Authorization
- Upload/store images in MongoDB using Node.js, Express & Multer
- MongoDB One-to-One relationship tutorial with Mongoose example
- MongoDB One-to-Many Relationship tutorial with Mongoose examples
- MongoDB Many-to-Many Relationship with Mongoose examples
Dockerize fullstack:
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:
Create Nodejs App
You can read and get Github source code from one of following tutorials:
- Node.js Express Rest API with MongoDb
- Node.js Express Pagination with Mongoose and MongoDB
- Node.js + MongoDB: User Authentication & Authorization
- Upload/store images in MongoDB using Node.js, Express & Multer
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 scriptnpm 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) andmongodb
(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
andtty
: 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 node-express-mongodb@1.0.0 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:
And the MongoDB database also:
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:
- Node.js Express Rest API with MongoDb
- Node.js Express Pagination with Mongoose and MongoDB
- Node.js + MongoDB: User Authentication & Authorization
- Upload/store images in MongoDB using Node.js, Express & Multer
Or Dockerize fullstack:
Happy Learning! See you again.
Source Code
The source code for this tutorial can be found at Github.
Further Reading
Associations: