Operations 17 min read

Setting Up a Jenkins CI/CD Pipeline for a MERN Application on Azure

This article provides a step‑by‑step guide to creating a CI/CD pipeline for a MERN stack application using Jenkins on Azure, covering prerequisites, Azure VM provisioning, Jenkins installation, pipeline configuration with a Jenkinsfile, Docker image building, and deployment to Docker Hub.

DevOps Cloud Academy
DevOps Cloud Academy
DevOps Cloud Academy
Setting Up a Jenkins CI/CD Pipeline for a MERN Application on Azure

Modern software development requires continuous integration and continuous deployment (CI/CD) to automate testing, building, and releasing code. This tutorial shows how to set up a CI/CD pipeline for a MERN (MongoDB, Express, React, Node.js) application using Jenkins on Azure.

Prerequisites

Basic knowledge of the MERN stack.

Basic understanding of Docker.

Access to the source code on GitHub.

Problem

Manually running tests, building Docker images, and pushing them to a registry is time‑consuming and error‑prone. The article illustrates the manual workflow with screenshots of the steps and the resulting delays.

Solution

Automate the entire workflow by creating a Jenkins CI/CD pipeline that triggers on code changes and executes testing, image building, and deployment automatically.

What is CI/CD and why it matters?

CI/CD is a set of automated steps that integrate code changes and deploy them to production, forming the core of DevOps practices. The article explains the four stages of the MERN app lifecycle: test, build Docker image, push to a registry, and deploy to a cloud provider.

The Project

The tutorial uses a simple full‑stack MERN application consisting of two micro‑services (frontend and backend), each with its own Dockerfile .

What is Jenkins?

Jenkins is a popular open‑source CI/CD server that runs the pipeline steps. Alternatives such as GitHub Actions, Travis CI, CircleCI, GitLab CI/CD, AWS CodePipeline, Azure DevOps, and Google Cloud Build are mentioned.

How to set up Jenkins on Azure

Because Jenkins does not provide a managed cloud service, the tutorial demonstrates provisioning a virtual machine on Azure and installing Jenkins manually.

mkdir jenkins
cd jenkins

Create a cloud‑init file to install OpenJDK and Jenkins:

#cloud-config
package_upgrade: true
runcmd:
  - sudo apt install openjdk-11-jre -y
  - wget -qO - https://pkg.jenkins.io/debian-stable/jenkins.io.key | sudo apt-key add -
  - sh -c 'echo deb https://pkg.jenkins.io/debian-stable binary/ > /etc/apt/sources.list.d/jenkins.list'
  - sudo apt-get update && sudo apt-get install jenkins -y
  - sudo service jenkins restart

Create a resource group and a VM:

az group create --name jenkins-rg --location centralindia
az vm create \
  --resource-group jenkins-rg \
  --name jenkins-vm \
  --image UbuntuLTS \
  --admin-username "azureuser" \
  --generate-ssh-keys \
  --public-ip-sku Standard \
  --custom-data cloud-init-jenkins.txt

Open port 8080 for Jenkins:

az vm open-port \
  --resource-group jenkins-rg \
  --name jenkins-vm  \
  --port 8080 --priority 1010

Retrieve the VM’s public IP and access Jenkins at http:// :8080 :

az vm show \
  --resource-group jenkins-rg \
  --name jenkins-vm -d \
  --query [publicIps] \
  --output tsv

Obtain the initial admin password:

sudo cat /var/lib/jenkins/secrets/initialAdminPassword

How to configure Jenkins

Install suggested plugins, create an admin user, and add the “Blue Ocean” plugin for a modern UI. The tutorial shows the UI steps to install plugins and configure credentials.

How to write a Jenkinsfile

The Jenkinsfile, written in Groovy, defines the pipeline stages. A minimal example starts with:

pipeline {

}

Specify an agent:

pipeline {
  agent any
}

Stage 1: Checkout code

pipeline {
  agent any
  stages {
    stage('Checkout') {
      steps {
        checkout scm
      }
    }
  }
}

Stage 2: Client Tests

stage('Client Tests') {
  steps {
    dir('client') {
      sh 'npm install'
      sh 'npm test'
    }
  }
}

Install Node.js on the VM if needed:

curl -sL https://deb.nodesource.com/setup_16.x | sudo -E bash -
sudo apt-get install -y nodejs

Stage 3: Server Tests

Add environment variables in Jenkins credentials and reference them in the pipeline:

environment {
  MONGODB_URI = credentials('mongodb-uri')
  TOKEN_KEY   = credentials('token-key')
  EMAIL       = credentials('email')
  PASSWORD    = credentials('password')
}
stage('Server Tests') {
  steps {
    dir('server') {
      sh 'npm install'
      sh 'export MONGODB_URI=$MONGODB_URI'
      sh 'export TOKEN_KEY=$TOKEN_KEY'
      sh 'export EMAIL=$EMAIL'
      sh 'export PASSWORD=$PASSWORD'
      sh 'npm test'
    }
  }
}

Stage 4: Build Docker Images

stage('Build Images') {
  steps {
    sh 'docker build -t rakeshpotnuru/productivity-app:client-latest client'
    sh 'docker build -t rakeshpotnuru/productivity-app:server-latest server'
  }
}

Stage 5: Push Images to DockerHub

stage('Push Images to DockerHub') {
  steps {
    withCredentials([usernamePassword(credentialsId: 'dockerhub', passwordVariable: 'DOCKER_PASSWORD', usernameVariable: 'DOCKER_USERNAME')]) {
      sh 'docker login -u $DOCKER_USERNAME -p $DOCKER_PASSWORD'
      sh 'docker push rakeshpotnuru/productivity-app:client-latest'
      sh 'docker push rakeshpotnuru/productivity-app:server-latest'
    }
  }
}

Full Jenkinsfile

// This is a Jenkinsfile. It is a script that Jenkins will run when a build is triggered.
pipeline {
    // Telling Jenkins to run the pipeline on any available agent.
    agent any

    // Setting environment variables for the build.
    environment {
        MONGODB_URI = credentials('mongodb-uri')
        TOKEN_KEY   = credentials('token-key')
        EMAIL       = credentials('email')
        PASSWORD    = credentials('password')
    }

    // This is the pipeline. It is a series of stages that Jenkins will run.
    stages {
        // Checkout source code.
        stage('Checkout') {
            steps {
                checkout scm
            }
        }

        // Run client tests.
        stage('Client Tests') {
            steps {
                dir('client') {
                    sh 'npm install'
                    sh 'npm test'
                }
            }
        }

        // Run server tests.
        stage('Server Tests') {
            steps {
                dir('server') {
                    sh 'npm install'
                    sh 'export MONGODB_URI=$MONGODB_URI'
                    sh 'export TOKEN_KEY=$TOKEN_KEY'
                    sh 'export EMAIL=$EMAIL'
                    sh 'export PASSWORD=$PASSWORD'
                    sh 'npm test'
                }
            }
        }

        // Build Docker images.
        stage('Build Images') {
            steps {
                sh 'docker build -t rakeshpotnuru/productivity-app:client-latest client'
                sh 'docker build -t rakeshpotnuru/productivity-app:server-latest server'
            }
        }

        // Push images to DockerHub.
        stage('Push Images to DockerHub') {
            steps {
                withCredentials([usernamePassword(credentialsId: 'dockerhub', passwordVariable: 'DOCKER_PASSWORD', usernameVariable: 'DOCKER_USERNAME')]) {
                    sh 'docker login -u $DOCKER_USERNAME -p $DOCKER_PASSWORD'
                    sh 'docker push rakeshpotnuru/productivity-app:client-latest'
                    sh 'docker push rakeshpotnuru/productivity-app:server-latest'
                }
            }
        }
    }
}

Conclusion

We explored why implementing CI/CD is essential for software development efficiency.

We learned the fundamentals of Jenkins and how to deploy a Jenkins server on Azure.

We customized Jenkins to meet specific project requirements.

We authored a Jenkinsfile and used Jenkins Blue Ocean to build and visualize the pipeline.

DockerCI/CDDevOpsJenkinsAzureMERN
DevOps Cloud Academy
Written by

DevOps Cloud Academy

Exploring industry DevOps practices and technical expertise.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.