Subscribe
Building a CI/CD Pipeline for Node.js Applications with Docker
7 mins read

By: vishwesh

Building a CI/CD Pipeline for Node.js Applications with Docker

If you're a developer, you probably know how important it is to have a good CI/CD pipeline for your code. A good CI/CD pipeline can save you time, increase your productivity, and ensure that your code is always of high quality. In this article, we're going to show you how to build a CI/CD pipeline for Node.js applications using Docker.

What is a CI/CD Pipeline?

CI/CD stands for Continuous Integration/Continuous Delivery or Continuous Deployment. It is a process that automates the building, testing, and deployment of code. A CI/CD pipeline ensures that the code is always of high quality, and that it can be deployed to production quickly and easily.

Why use Docker for CI/CD?

Docker is a powerful tool for building and deploying applications. It allows you to package your application and all its dependencies into a single container. This container can then be easily deployed to any environment, making it an ideal choice for building a CI/CD pipeline.

Setting up the Environment

To get started, you'll need to set up your development environment. You'll need Node.js, Docker, and a code editor.

Installing Node.js

If you don't have Node.js installed, you can download it from the official website. Once you've downloaded and installed Node.js, you can verify that it's installed correctly by running the following command in your terminal:

node --version

Installing Docker

To install Docker, you'll need to download it from the official website and follow the installation instructions for your operating system.

Setting up the Code Editor

You can use any code editor you like for this tutorial. Some popular choices include Visual Studio Code, Sublime Text, and Atom.

Creating a Node.js Application

Now that we have our development environment set up, let's create a simple Node.js application. Create a new directory for your project, and navigate to it in your terminal. Once you're in the directory, run the following command:

npm init

This command will create a new package.json file in your directory. This file will contain information about your project, such as its name, version, and dependencies.

Next, create a new file called index.js in your directory, and add the following code:

const http = require('http');

const hostname = '0.0.0.0';
const port = 3000;

const server = http.createServer((req, res) => {
  res.statusCode = 200;
  res.setHeader('Content-Type', 'text/plain');
  res.end('Hello, World!\n');
});

server.listen(port, hostname, () => {
  console.log(`Server running at http://${hostname}:${port}/`);
});

This code will create a simple HTTP server that listens on port 3000 and returns a "Hello, World!" message to any request.

Now let's test our application. In your terminal, run the following command:

node index.js

This command will start your application, and you should see the following message in your terminal:

Server running at http://0.0.0.0:3000/

Open your web browser and navigate to http://localhost:3000. You should see the "Hello, World!" message.

Creating a Dockerfile

Now that we have our Node.js application, let's create a Dockerfile to package it into a Docker container. Create a new file called Dockerfile in your project directory, and add the following code:

FROM node:14-alpine

WORKDIR /app

COPY package*.json ./

RUN npm install

COPY . .

EXPOSE 3000

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

This Dockerfile specifies that we want to use the node:14-alpine image as our base image. We then set the working directory to /app, and copy the package.json and package-lock.json files to the working directory. We run npm install to install all the required dependencies.

We then copy all the remaining files in the project directory to the working directory in the Docker container. We expose port 3000 to allow incoming traffic, and set the command to run node index.js when the container starts.

Building the Docker Image

Now that we have our Dockerfile, we can build the Docker image. In your project directory, run the following command:

docker build -t my-node-app .

This command builds a Docker image with the tag my-node-app and uses the . to specify the current directory as the build context.

Once the build is complete, you can verify that the image was created by running the following command:

docker images

You should see the my-node-app image in the list of images.

Testing the Docker Image

Now that we have built the Docker image, let's test it by running a container. In your terminal, run the following command:

docker run -p 3000:3000 my-node-app

This command runs a Docker container from the my-node-app image, and maps port 3000 on the host machine to port 3000 in the container.

Open your web browser and navigate to http://localhost:3000. You should see the "Hello, World!" message.

Setting up a CI/CD Pipeline

Now that we have our Dockerized Node.js application, let's set up a CI/CD pipeline for it. For this tutorial, we'll be using CircleCI as our CI/CD tool, but you can use any tool you like.

Setting up CircleCI

To set up CircleCI, you'll need to create an account and link it to your GitHub repository. Once you've done that, you can create a new configuration file called .circleci/config.yml in your repository, and add the following code:

version: 2
jobs:
  build:
    docker:
      - image: circleci/node:14
    working_directory: ~/app
    steps:
      - checkout
      - run: npm install
      - run: npm run test
      - save_cache:
          key: dependency-cache-{{ checksum "package.json" }}
          paths:
            - node_modules
      - run: npm run build
      - save_cache:
          key: dependency-cache-{{ checksum "package.json" }}
          paths:
            - node_modules
      - store_artifacts:
          path: dist
  deploy:
    docker:
      - image: docker:20
    working_directory: ~/app
    steps:
      - checkout
      - setup_remote_docker
      - run: |
          docker build -t my-node-app .
          docker tag my-node-app my-username/my-node-app:latest
      - run: |
          echo "$DOCKER_PASSWORD" | docker login -u "$DOCKER_USERNAME" --password-stdin
          docker push my-username/my-node-app:latest

This configuration file defines two jobs, build and deploy. The build job uses the circleci/node:14 Docker image as its base image, and runs the following steps:

  1. checkout: Check out the source code from the repository.
  2. npm install: Install the Node.js dependencies.
  3. npm run test: Run the tests.
  4. save_cache: Save the node_modules directory to the CircleCI cache, using the package.json file as the cache key.
  5. npm run build: Build the application.
  6. save_cache: Save the node_modules directory to the CircleCI cache again, in case any new dependencies were installed during the build.
  7. store_artifacts: Store the dist directory as a build artifact.

The deploy job uses the docker:20 Docker image as its base image, and runs the following steps:

  1. checkout: Check out the source code from the repository.
  2. setup_remote_docker: Set up access to the Docker daemon on the CircleCI machine.
  3. docker build: Build the Docker image.
  4. docker tag: Tag the Docker image with a unique name based on your username and the image name.
  5. docker login: Log in to Docker Hub using your Docker Hub username and password.
  6. docker push: Push the Docker image to Docker Hub.

Adding Environment Variables

To avoid hardcoding sensitive information like the Docker Hub username and password in the config.yml file, we can use CircleCI environment variables. To do this, go to your project settings on the CircleCI website, and click on "Environment Variables" in the sidebar. Add the following environment variables:

  • DOCKER_USERNAME: Your Docker Hub username.
  • DOCKER_PASSWORD: Your Docker Hub password.

Triggering the CI/CD Pipeline

With CircleCI set up and the environment variables configured, the final step is to trigger the CI/CD pipeline. Push any changes to your GitHub repository, and CircleCI will automatically detect the changes and start the pipeline.

You can view the progress of the pipeline on the CircleCI website, under the "Jobs" tab. If everything is configured correctly, you should see the pipeline complete successfully, and the Docker image should be pushed to Docker Hub.

Conclusion

In this article, we have seen how to set up a CI/CD pipeline for Node.js applications with Docker. We started by creating a Dockerfile to package the application in a container, and then used Docker Compose to set up a development environment. We then set up CircleCI to automatically build and deploy the application to Docker Hub whenever changes are pushed to the repository.

Using a CI/CD pipeline has many benefits, including faster and more reliable releases, improved code quality, and reduced manual intervention. With Docker, we can easily package our applications into containers and deploy them consistently across different environments. And with CircleCI, we can automate the build and deployment process, saving time and reducing the risk of human error.

While this article focused on Node.js applications, the concepts can be applied to other languages and frameworks as well. By following these best practices, you can improve the speed, quality, and reliability of your software development process, and ultimately deliver better software to your users.

Recent posts

Don't miss the latest trends

    Popular Posts

    Popular Categories