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.
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 jenkinsCreate 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 restartCreate 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.txtOpen port 8080 for Jenkins:
az vm open-port \
--resource-group jenkins-rg \
--name jenkins-vm \
--port 8080 --priority 1010Retrieve 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 tsvObtain the initial admin password:
sudo cat /var/lib/jenkins/secrets/initialAdminPasswordHow 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 nodejsStage 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.
DevOps Cloud Academy
Exploring industry DevOps practices and technical expertise.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.