DEV Community

Cover image for Using Dockerfile and Docker Compose For Local Development with Node.js, MongoDB and MongoExpress
Otobong Edoho
Otobong Edoho

Posted on

Using Dockerfile and Docker Compose For Local Development with Node.js, MongoDB and MongoExpress

Introduction

In this post, I'll show you how to set up a local development environment using Docker with Node.js, MongoDB, and MongoExpress. Docker is a powerful tool that makes it easy to package applications and their dependencies, ensuring consistency across different environments.

The goal of this guide is to help you spin up a simple Node.js app connected to a MongoDB database. We'll also use MongoExpress as a lightweight web-based interface to manage the database, all running inside Docker containers. By the end of this post, you’ll have a fully functional environment that can be set up and torn down with just a few commands.

Prerequisites
Before we dive in, please make sure you have the following installed:

  • Docker: You can download and install Docker from here.
  • Basic understanding of Node.js and MongoDB.
  • An EC2 Cloud instance for Non-ubuntu users

If you’re new to Docker, there's no need to worry! This guide will walk you through the essential commands you need to know to get your environment up and running.

Setting up the Project

Setup for Docker
So we will start setting up the project, The first thing we need to do is pull the mongodb images and mongo express UI image from dockerhub.

Let's install docker but first we need to update the package lists

sudo apt update
sudo apt upgrade -y
Enter fullscreen mode Exit fullscreen mode

Install Required Dependencies
Install packages that allow apt to use repositories over HTTPS:

sudo apt install -y apt-transport-https ca-certificates curl software-properties-common
Enter fullscreen mode Exit fullscreen mode

Add Docker’s Official GPG Key

curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg
Enter fullscreen mode Exit fullscreen mode

Set Up the Docker Repository
Add the Docker repository to apt sources:

echo \
  "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu \
  $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
Enter fullscreen mode Exit fullscreen mode

Install Docker Engine

sudo apt-get install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
Enter fullscreen mode Exit fullscreen mode

Now that docker is installed its time to pull the images
Let's pull the mongodb image first

mongodb image


The docker run command does two things, it pulls the image and runs the image which is what we call a container. A container is the running instance of an image.

Docker containers run in an isolated network meaning if we are running two different containers and we want them to be able to communicate we must put them in the same network.

Explanation of the Screenshot:

docker run:

This command starts a new container from a Docker image.

-d:

The -d flag tells Docker to run the container in "detached" mode (in the background), so it won't block the terminal.

-p 27017:27017:

This option maps port 27017 on the host machine to port 27017 in the container. MongoDB uses this port for communication.

  • The syntax is host_port:container_port, which means MongoDB will be accessible via localhost:27017 on the host machine.

--network mongo-network:

This option connects the container to a Docker network named mongo-network. The network allows multiple containers to communicate with each other.

  • If the network doesn't exist, create it with docker network create mongo-network.

--name mongodb:

This assigns a name (mongodb) to the running container. It allows you to refer to the container by name rather than by its container ID.

-e MONGO_INITDB_ROOT_USERNAME=admin:

The -e flag sets environment variables inside the container. In this case, it sets MONGO_INITDB_ROOT_USERNAME to admin, which specifies the MongoDB root user's username.

-e MONGO_INITDB_ROOT_PASSWORD=changethis123:

Similar to the previous option, this sets the environment variable MONGO_INITDB_ROOT_PASSWORD to changethis123, defining the password for the MongoDB root user.

mongo:

This is the name of the image to use. In this case, it is the official MongoDB image from Docker Hub.

Now that we have some knowledge about docker let's proceed to pull the mongodb express image and run it

mongo express image

To check the network available, we can run
docker network ls

It will output the name of the network that we just created, so they can talk to each other using just the container name.

So we can access the mongo express server from our browser using localhost:8081


mongoexpress


Now there's a quicker and better setup, that is using dockerfile and docker compose rather than just running the commands in the terminal. Just to be clear a Docker Compose file uses YAML syntax, it defines how to configure and run multi-container applications on Docker while a Dockerfile is a text file that contains instructions for building a container image.

Setting up the Project

First, let's create a simple Node.js application. If you don't already have Node.js installed, you can download it here.

  1. Start by creating a project folder:
   mkdir docker-node-mongo
   cd docker-node-mongo
Enter fullscreen mode Exit fullscreen mode
  1. Initialize a new Node.js project:
   npm init -y
Enter fullscreen mode Exit fullscreen mode
  1. Install the necessary dependencies. For this setup, we’ll need Express for our web server and Mongoose to interact with MongoDB:
   npm install express mongoose
Enter fullscreen mode Exit fullscreen mode
  1. Create an index.js file with a simple Express server and a MongoDB connection using Mongoose:
   const express = require('express');
   const mongoose = require('mongoose');

   const app = express();
   const port = 3000;

   // MongoDB connection
   mongoose.connect('mongodb://mongo:27017/testdb', {
     useNewUrlParser: true,
     useUnifiedTopology: true,
   }).then(() => {
     console.log('Connected to MongoDB');
   }).catch(err => {
     console.log('Failed to connect to MongoDB', err);
   });

   // Routes
   app.get('/', (req, res) => {
     res.send('Hello from Node.js and MongoDB');
   });

   app.listen(port, () => {
     console.log(`App running at http://localhost:${port}`);
   });
Enter fullscreen mode Exit fullscreen mode

This sets up a basic Express server and connects it to a MongoDB instance running on mongodb://mongo:27017/testdb. Now let's Dockerize it.


Creating a Dockerfile for Node.js

Next, we need to create a Dockerfile that will define the environment for our Node.js app. A Dockerfile is essentially a blueprint for building the Docker image that will contain your application.

Create a file called Dockerfile in the root of your project directory and add the following:

# Use the official Node.js image from Docker Hub
FROM node:16

# Set the working directory inside the container
WORKDIR /app

# Copy package.json and install dependencies
COPY package*.json ./
RUN npm install

# Copy the rest of the app files
COPY . .

# Expose the port the app runs on
EXPOSE 3000

# Command to run the app
CMD ["node", "index.js"]
Enter fullscreen mode Exit fullscreen mode

This Dockerfile will:

  1. Use the official Node.js image.
  2. Set the working directory to /app.
  3. Copy the package.json and install the necessary dependencies.
  4. Copy the rest of the files and set the entry point to run the Node.js app.

Setting up MongoDB and MongoExpress with Docker Compose

Instead of running all services separately, we'll use Docker Compose to define and manage our multi-container environment. Docker Compose allows us to define services, networks, and volumes in a docker-compose.yml file, making it easy to orchestrate our entire stack. One thing to remember is that when using docker compose we don't need to create a network it automatically creates a network for our multiple containers defined in the yaml file.

Create a docker-compose.yml file in the project root:

version: '3'
services:
  nodeapp:
    build: .
    ports:
      - '3000:3000'
    volumes:
      - .:/app
    depends_on:
      - mongo
  mongo:
    image: mongo
    ports:
      - '27017:27017'
  mongo-express:
    image: mongo-express
    ports:
      - '8081:8081'
    environment:
      ME_CONFIG_MONGODB_ADMINUSERNAME: root
      ME_CONFIG_MONGODB_ADMINPASSWORD: example
      ME_CONFIG_MONGODB_SERVER: mongo
Enter fullscreen mode Exit fullscreen mode

This configuration defines three services:

  1. nodeapp: Our Node.js application.
  2. mongo: A MongoDB instance running on port 27017.
  3. mongo-express: A web-based interface to manage MongoDB, accessible on port 8081.

Running the Application

With everything set up, let’s run the app using Docker Compose.

Run the following command in your terminal:

docker-compose up
Enter fullscreen mode Exit fullscreen mode

To shut down the multiple containers currently using Docker Compose

docker-compose down
Enter fullscreen mode Exit fullscreen mode

Docker Compose will pull the necessary images, build the Node.js app, and start all services. After the process completes, you should see logs from MongoDB, Node.js, and MongoExpress.

  • Visit http://localhost:3000 to see the Node.js app running.
  • Visit http://localhost:8081 to access MongoExpress and manage your database.

Connecting Node.js to MongoDB

Our Node.js app is already set up to connect to MongoDB with the following connection string inside index.js:

mongoose.connect('mongodb://mongo:27017/testdb', {
  useNewUrlParser: true,
  useUnifiedTopology: true,
});
Enter fullscreen mode Exit fullscreen mode

The mongo hostname refers to the MongoDB service defined in our docker-compose.yml. Docker Compose automatically creates a network for the services, allowing them to communicate by their service names.


Conclusion

In this post, we’ve successfully set up a local development environment using Docker for Node.js, MongoDB, and MongoExpress. Using Docker Compose, we orchestrated multiple containers to work together seamlessly, making it easier to spin up a fully functional stack for development.

With this setup, you can easily add more services, manage your databases with MongoExpress, and have an isolated environment without needing to install MongoDB or other dependencies locally.

Happy Reading!!! Please Like, save, share and follow!!!


Top comments (0)