Dockerizing a Node.js Application with MongoDB

Syed Aun Abbas - Jun 28 - - Dev Community

In this blog post, I will guide you through Dockerizing a Node.js application that uses MongoDB. We will cover setting up the Node.js app, creating a MongoDB database, and using Docker to containerize both services. By the end of this tutorial, you'll have a working application running in Docker containers.

Prerequisites

  • Basic knowledge of Node.js and Express
  • Basic understanding of Docker and Docker Compose
  • Node.js and Docker installed on your machine

Project Structure

Image description

Step 1: Setting Up the Node.js Application

First, let's set up our Node.js application. We'll create a simple product management API using Express and MongoDB. We'll use the src folder for this in our project.

ProductController.js

This file contains the controller logic for handling requests related to products.

import Product from '../models/Product.js';

async function index(req, res, next) {
    try {
        const products = await Product.find();
        return res.status(200).json({
            status: 200,
            data: products
        });
    } catch (e) {
        console.log(e);
        return res.status(500).json({
            message: e
        });
    }
}

async function save(req, res, next) {
    try {
        const product = new Product();
        product.title = req.body.title;
        product.description = req.body.description;
        product.price = req.body.price;
        await product.save();

        return res.status(201).json({
            status: 201
        });
    } catch (e) {
        console.log(e);
        return res.status(500).json({
            message: e
        });
    }
}

export default {
    index,
    save
};
Enter fullscreen mode Exit fullscreen mode

Product.js

This file defines the Mongoose schema for our product model.

import mongoose from 'mongoose';

const ProductSchema = new mongoose.Schema({
    title: {
        type: String,
        required: true
    },
    description: {
        type: String,
        required: true
    },
    price: {
        type: String,
        required: true
    }
});

export default mongoose.model('Product', ProductSchema);
Enter fullscreen mode Exit fullscreen mode

products.js

This file defines the routes for our product API.

import express from 'express';
import productsController from '../controllers/ProductController.js';

const router = express.Router();

router.get('/', productsController.index);
router.post('/', productsController.save);

export default router;
Enter fullscreen mode Exit fullscreen mode

app.js

This file sets up our Express application and connects to MongoDB.

import express from 'express';
import productRoutes from './routes/products.js';
import mongoose from 'mongoose';
import config from '../config.js';
import bodyParser from 'body-parser';

const connectToDB = async () => {
    try {
        await mongoose.connect(config.db_uri, {});
    } catch (e) {
        console.log(e);
        process.exit(1);
    }
};

const app = express();

// middleware
app.use(bodyParser.urlencoded({ extended: false }));
app.use(bodyParser.json());

app.use('/products', productRoutes);

await connectToDB();

export default app;
Enter fullscreen mode Exit fullscreen mode

index.js

This file starts the Express application.

import app from './app.js';
import config from '../config.js';

app.listen(3000, () => {
    console.log(config.app_name + ' Started on Port 3000');
});
Enter fullscreen mode Exit fullscreen mode

config.js

import dotenv from 'dotenv';
import mongoose from "mongoose";

dotenv.config();

const config = {
    app_name: process.env['APP_NAME'],
    port: process.env['PORT'] ?? 3000,
    db_uri: process.env['DB_URI'] ?? 'mongodb://localhost:27017/docker',
    db_options: {
        useNewUrlParser: true,
        useUnifiedTopology: true
    }
}
export default config;
Enter fullscreen mode Exit fullscreen mode

env

APP_NAME=LearnDocker
PORT=3000
DB_URI=mongodb://127.0.0.1:27017/dockerlearn #This is a local Mongo database
Enter fullscreen mode Exit fullscreen mode

Step 2: Dockerizing the Application

Now, let's create a Dockerfile to containerize our Node.js application.

Dockerfile

# Use the official Node.js image based on Alpine Linux, which is a lightweight distribution
FROM node:alpine

# Set the working directory inside the container
WORKDIR /usr/src/app

# Copy package.json and package-lock.json to the working directory
COPY ./package.json ./
COPY ./package-lock.json ./

# Install the Node.js dependencies
RUN npm install

# Copy the application source code to the working directory
COPY ./src ./src

# Copy the environment configuration file
COPY ./.env ./

# Copy the configuration file
COPY ./config.js ./

# Define the command to run the application
CMD ["npm", "start"]
Enter fullscreen mode Exit fullscreen mode

Docker Compose

We'll use Docker Compose to set up our Node.js application and MongoDB as separate services.
docker-compose.yml

version: "3"

services:
  # Define the MongoDB service
  mongo_db:
    container_name: database_container  # Set a custom name for the MongoDB container
    image: mongo:latest  # Use the latest version of the MongoDB image
    restart: always  # Always restart the container if it stops or fails
    volumes:
      - mongo_db:/data/db  # Map the mongo_db volume to /data/db inside the container to persist data

  # Define the Node.js application service
  app:
    build: .  # Build the image from the Dockerfile in the current directory
    ports:
      - 4000:3000  # Map port 4000 on the host to port 3000 in the container
    environment:
      APP_NAME: LearnDocker  # Set the application name environment variable
      PORT: 3000  # Set the application port environment variable
      DB_URI: mongodb://mongo_db:27017/dockerlearn  # Set the MongoDB URI to connect to the MongoDB container
    depends_on:
      - mongo_db  # Ensure the mongo_db service is started before this service

volumes:
  mongo_db: {}  # Define a named volume for MongoDB data
Enter fullscreen mode Exit fullscreen mode

Step 3: Running the Application

To run the application, follow these steps:

  1. Build the Docker images:
   docker-compose build
Enter fullscreen mode Exit fullscreen mode
  1. Start the services:
   docker-compose up
Enter fullscreen mode Exit fullscreen mode

You can test the application on Postman at the endpoint localhost:4000/products

You should now see the product management API in action.

Conclusion

Congratulations! You've successfully Dockerized a Node.js application with MongoDB. This setup provides a clean and efficient way to manage your application and its dependencies. Feel free to expand this project further and explore more features of Docker and Node.js.

. . . . . . . . . .