Project Report: Containerization of a javascript application, pushing it in private ECR and deploying it in development server

Project Report: Containerization of a javascript application, pushing it  in private ECR and deploying it in development server

1. Introduction

This project aims to containerize a Node.js application, its associated MongoDB database, and deploy them using Docker. The application will be deployed on a development server, and the Docker images will be stored in a private Amazon Elastic Container Registry (ECR). The report will provide a step-by-step guide from the initial setup to containerization and deployment.

2. Project Setup

  1. Set up an AWS EC2 instance or any development server where you will deploy the application.

  2. Install Docker on the EC2 instance following the appropriate instructions for your operating system.

  3. Clone the Node.js application repository from the GitHub repository to your EC2 instance:

git clone https://github.com/your-github-username/your-nodejs-app.git

Replace "your-github-username" and "your-nodejs-app" with the actual GitHub repository URL of your Node.js application.

3. Pulling MongoDB and mongo-express Images:

  1. Pull the MongoDB and mongo-express images from Docker Hub using the following commands:
docker pull mongo
docker pull mongo-express

4.Creating a Docker network:

Create a docker network naming "mongo-network" to allow communication between the MongoDB and mongo-express containers

docker network create mongo-network

5. MongoDB and mongo-expressContainerization

docker run -d --name mongodb -e MONGO_INITDB_ROOT_USERNAME=admin -e MONGO_INITDB_ROOT_PASSWORD=adminpassword --network docker-network -p 27017:27017 mongo:latest

Explanation:

  • The -e flag is used to set environmental variables. Here, we set the root username to "admin" and the root password to "adminpassword" for MongoDB initialization.

  • The -p flag maps port 27017 from the container to port 27017 on the host machine, allowing access to the MongoDB service.

MongoDB Express (mongo-express) Containerization: Run a MongoDB Express container connected to the "docker-network" using the following command:

docker run -d --name mongo-express -e ME_CONFIG_MONGODB_SERVER=mongodb -e ME_CONFIG_MONGODB_ADMINUSERNAME=admin -e ME_CONFIG_MONGODB_ADMINPASSWORD=adminpassword --network docker-network -p 8081:8081 mongo-express:latest

Explanation:

  • The -e flag sets environmental variables for the MongoDB Express container. We specify the MongoDB server ("mongodb"), along with the root username and password for authentication.

  • The -p flag maps port 8081 from the container to port 8081 on the host machine, enabling access to the MongoDB Express web interface.

6. Docker Compose for Multi-Container Deployment:

Now that we have individual Docker run commands for each container, we can simplify the management of these containers using Docker Compose. Docker Compose allows us to define and run multi-container applications with a single YAML file.

Step 6.1: Create docker-compose.yaml

In the project's root directory, create a file named docker-compose.yaml with the following content:

version: '3'
services:
  mongodb:
    image: mongo:latest
    container_name: mongodb
    environment:
      MONGO_INITDB_ROOT_USERNAME: admin
      MONGO_INITDB_ROOT_PASSWORD: adminpassword
    ports:
      - "27017:27017"
    networks:
      - docker-network

  mongo-express:
    image: mongo-express:latest
    container_name: mongo-express
    environment:
      ME_CONFIG_MONGODB_SERVER: mongodb
      ME_CONFIG_MONGODB_ADMINUSERNAME: admin
      ME_CONFIG_MONGODB_ADMINPASSWORD: adminpassword
    ports:
      - "8081:8081"
    networks:
      - docker-network

networks:
  docker-network:
    driver: bridge

Step 6.2: Running with Docker Compose

With the docker-compose.yaml file in place, you can now start all the containers with a single command:

docker-compose -f docker-compose.yaml up -d

Explanation:

  • The docker-compose -f docker-compose.yaml up command reads the docker-compose.yaml file and starts all defined services.

  • The -d flag runs the containers in detached mode, allowing them to run in the background.

Step 6.3: Stopping Containers

To stop and remove the containers created by Docker Compose, use the following command:

docker-compose -f docker-compose.yaml down

This will gracefully stop and remove all the containers defined in the docker-compose.yaml file.

7. Creating a Dockerfile:

A Dockerfile serves as a blueprint for building Docker images. We created a Dockerfile for the Node.js application that specifies the base Node.js image, sets environment variables for MongoDB credentials, and copies the application code into the container. Additionally, the Dockerfile installs application dependencies and starts the application using the server.js file.

FROM node:13-alpine

ENV MONGO_DB_USERNAME=admin \
    MONGO_DB_PWD=password

RUN mkdir -p /home/app

COPY ./app /home/app

WORKDIR /home/app

RUN npm install

CMD ["node", "server.js"]

8. Node.js Application Containerization and Connection to MongoDB:

Provided Dockerfile for the Node.js application, we will proceed with the containerization and connection to the MongoDB database.

Step 8.1: Dockerfile for Node.js Application:

Here's the Dockerfile:

# Use the official Node.js base image
FROM node:13-alpine

# Set environmental variables for MongoDB credentials
ENV MONGO_DB_USERNAME=admin \
    MONGO_DB_PWD=password

# Create a directory for the Node.js application inside the container
RUN mkdir -p /home/app

# Copy the contents of the local "app" directory into the container's app directory
COPY ./app /home/app

# Set the working directory to /home/app so that subsequent commands execute in this directory
WORKDIR /home/app

# Install Node.js dependencies using npm
RUN npm install

# Start the Node.js application using the "server.js" file in the /home/app directory
CMD ["node", "server.js"]

Step 8.2: Building and Running the Node.js Application Container:

Assuming you have your Node.js application files and the Dockerfile in the same directory, we will build the Docker image and run the Node.js application container connected to the MongoDB container through the docker-network.

  1. Open a terminal, navigate to the directory containing the Dockerfile and Node.js application code.

  2. Build the Docker image for your Node.js application using the following command:

docker build -t nodejs-app -f Dockerfile .
  1. After successfully building the image, you can run the Node.js application container and connect it to the MongoDB container through the docker-network:
docker run -d --name nodejs-container -e MONGO_URL=mongodb://mongodb:27017/your-database-name --network docker-network -p 3000:3000 nodejs-app

Explanation:

  • The -e flag sets the MONGO_URL environment variable inside the Node.js application container to specify the connection URL for MongoDB. Replace your-database-name with the name of your MongoDB database.

  • The -p flag maps port 3000 from the container to port 3000 on the host machine, allowing access to the Node.js application.

Step 8.3: Verify the Connection:

To verify that the Node.js application is successfully connected to the MongoDB database, access your Node.js application in a web browser or use tools like curl or Postman to interact with the application's API endpoints.

Example API Endpoint in server.js:

const express = require('express');
const app = express();
const mongoose = require('mongoose');

const mongoUrl = process.env.MONGO_URL || 'mongodb://localhost:27017/mydb';

mongoose.connect(mongoUrl, { useNewUrlParser: true, useUnifiedTopology: true })
  .then(() => {
    console.log('Connected to MongoDB successfully!');
  })
  .catch((error) => {
    console.error('Error connecting to MongoDB:', error);
  });

// Define your API routes and other application logic here

const PORT = process.env.PORT || 3000;
app.listen(PORT, () => {
  console.log(`Server is running on port ${PORT}`);
});

8. Building Docker Image for the Node.js Application:

With the Dockerfile ready, you can proceed to build the Docker image for your Node.js application. The image will be named "my-app" with the tag "1.0".

Step 8.1: Build Docker Image

  1. Open a terminal or command prompt.

  2. Navigate to the directory containing your Node.js application files and the Dockerfile.

  3. Use the following command to build the Docker image:

docker build -t my-app:1.0 -f Dockerfile .

Explanation:

  • docker build: This command is used to build a Docker image from a specified Dockerfile.

  • -t my-app:1.0: The -t flag tags the built image with the name "my-app" and the version "1.0".

  • -f Dockerfile: The -f flag specifies the path to the Dockerfile. In this case, it's in the current directory (denoted by the dot .).

Step 8.2: Verify the Built Image

After the build process completes, you can verify that the image "my-app" with the tag "1.0" is present in your Docker environment by running:

docker images

You should see the newly built image listed among your Docker images.

9. Running the "my-app:1.0" Container and Verifying Application Environment:

Now that you have built the Docker image for your Node.js application, it's time to run the container and verify that the application starts successfully and the environment is configured properly.

Step 9.1: Run the Container

Use the following command to run the "my-app:1.0" container:

docker run -d --name my-app-container -e MONGO_URL=mongodb://mongodb:27017/your-database-name --network docker-network -p 3000:3000 my-app:1.0

Explanation:

  • The -d flag runs the container in detached mode, allowing it to run in the background.

  • The --name my-app-container option specifies the name of the container as "my-app-container".

  • The -e flag sets the MONGO_URL environment variable inside the container to specify the connection URL for MongoDB. Replace your-database-name with the name of your MongoDB database.

  • The -p flag maps port 3000 from the container to port 3000 on the host machine, allowing access to the Node.js application.

  • Step 9.2: Verify Application and Environment

    1. Check if the "my-app-container" is running using the following command:
    docker ps
  1. Access your Node.js application in a web browser using localhost:3000 or use tools like curl or Postman to interact with the application's API endpoints.

  2. Ensure that the application behaves as expected and shows signs of successful initialization, such as logging indicating a successful MongoDB connection.

  3. Verify that the environment variables, including MONGO_DB_USERNAME, MONGO_DB_PWD, and MONGO_URL, are correctly applied within the container. For example, you can log these variables in your Node.js application to verify their values:

    console.log("MONGO_DB_USERNAME:", process.env.MONGO_DB_USERNAME);
    console.log("MONGO_DB_PWD:", process.env.MONGO_DB_PWD);
    console.log("MONGO_URL:", process.env.MONGO_URL);

10. Pushing Docker Image to AWS ECR:

With the Node.js application containerized and successfully running, we will proceed to push the Docker image to the private Amazon Elastic Container Registry (ECR) for secure storage.

Step 10.1: Authenticate Docker with AWS ECR

Before pushing the Docker image, you need to authenticate Docker with your AWS ECR registry. Follow these steps:

  1. Open a terminal or command prompt on your local machine.

  2. Run the following command to authenticate Docker with your AWS ECR registry:

    aws ecr get-login-password --region your-aws-region | docker login --username AWS --password-stdin your-aws-account-id.dkr.ecr.your-aws-region.amazonaws.com

Replace:

  • your-aws-region with the AWS region where your ECR repository is located (e.g., us-east-1).

  • your-aws-account-id with your AWS account ID.

This command retrieves the login credentials for your ECR registry and uses them to authenticate Docker.

Step 10.2: Tag the Docker Image

Next, you need to tag your Docker image with the ECR repository URI. Use the following command:

    docker tag my-app:1.0 your-aws-account-id.dkr.ecr.your-aws-region.amazonaws.com/my-app-repo:1.0

Replace:

  • your-aws-region with the AWS region where your ECR repository is located.

  • your-aws-account-id with your AWS account ID.

  • my-app-repo with the name of your ECR repository.

This command tags the "my-app:1.0" Docker image with the ECR repository URI.

Step 10.3: Push the Docker Image

Now, you can push the Docker image to your AWS ECR repository:

    docker push your-aws-account-id.dkr.ecr.your-aws-region.amazonaws.com/my-app-repo:1.0

Replace:

  • your-aws-region with the AWS region where your ECR repository is located.

  • your-aws-account-id with your AWS account ID.

  • my-app-repo with the name of your ECR repository.

This command pushes the "my-app:1.0" Docker image to your private AWS ECR repository.

Step 10.4: Verify Image in ECR

You can verify that the Docker image has been successfully pushed to your ECR repository by checking the AWS Management Console for ECR. Alternatively, you can use the AWS CLI:

    aws ecr describe-images --repository-name my-app-repo --region your-aws-region

Replace:

  • your-aws-region with the AWS region where your ECR repository is located.

  • my-app-repo with the name of your ECR repository.

This command will display information about the images in your ECR repository, including the "my-app:1.0" image.

11. Deploying Docker Compose with Private Image from AWS ECR:

With the Docker image successfully pushed to your private AWS ECR repository, we can now deploy the application using the Docker Compose file, which references the private image.

Step 11.1: Configure Docker Compose File

In your existing Docker Compose file, uncomment and modify the "my-app" service to use the private image from AWS ECR. Update the service configuration as follows:

    version: '3'
    services:
      my-app:
        image: your-aws-account-id.dkr.ecr.your-aws-region.amazonaws.com/my-app-repo:1.0
        ports:
          - 3000:3000
        environment:
          - MONGO_URL=mongodb://mongodb:27017/your-database-name
        depends_on:
          - mongodb
          - mongo-express
      mongodb:
        image: mongo
        ports:
          - 27017:27017
        environment:
          - MONGO_INITDB_ROOT_USERNAME=admin
          - MONGO_INITDB_ROOT_PASSWORD=password
        volumes:
          - mongo-data:/data/db
      mongo-express:
        image: mongo-express
        restart: always
        ports:
          - 8080:8081
        environment:
          - ME_CONFIG_MONGODB_ADMINUSERNAME=admin
          - ME_CONFIG
  • Replace:

    • your-aws-region with the AWS region where your ECR repository is located.

    • your-aws-account-id with your AWS account ID.

    • my-app-repo with the name of your ECR repository.

    • your-database-name with the name of your MongoDB database.

Step 11.2: Deploy Docker Compose

  1. Copy the updated Docker Compose file to your development server.

  2. Open a terminal on the development server and navigate to the directory containing the Docker Compose file.

  3. Run the following command to deploy your application:

    docker-compose up -d

The -d flag runs the containers in detached mode, allowing them to run in the background.

Step 11.3: Verify Deployment

Once the Docker Compose deployment is complete, you can verify that your application is running on the development server.

  1. Check the status of the containers to ensure they are running:
    docker-compose ps
  1. Access your Node.js application in a web browser using http://your-server-ip:3000. Ensure that the application behaves as expected and interacts with MongoDB correctly.

Conclusion:

By deploying your Docker Compose file with the private image from AWS ECR, you have successfully deployed your application on the development server. The Docker Compose file orchestrates the containers and allows them to communicate with each other using the specified configurations.

This step completes the deployment process, and your application should now be accessible and running on the development server.

Github Repo: https://github.com/itspsycho07/my-app-demo

Private ECR:

It is seen that the image is been successfully pushed in my private ECR and is displayed with its tag.