0% found this document useful (0 votes)
4 views27 pages

Devops_tutorial_Jenkins_

Jenkins is an open-source automation server that facilitates CI/CD processes by automating code building, testing, and deployment. It operates on a master-agent architecture, where the master controls the build process and agents execute jobs. The document also outlines installation steps on Ubuntu, job types, pipeline options, and a sample Jenkinsfile for a Java Maven application integrating with SonarQube and JFrog Artifactory.

Uploaded by

Lohitaksha LB
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
4 views27 pages

Devops_tutorial_Jenkins_

Jenkins is an open-source automation server that facilitates CI/CD processes by automating code building, testing, and deployment. It operates on a master-agent architecture, where the master controls the build process and agents execute jobs. The document also outlines installation steps on Ubuntu, job types, pipeline options, and a sample Jenkinsfile for a Java Maven application integrating with SonarQube and JFrog Artifactory.

Uploaded by

Lohitaksha LB
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd

Jenkins

Jenkins is a free, open-source Java based tool that helps developers


automate the process of building, testing, and deploying code.

It’s mainly used for CI/CD (Continuous Integration / Continuous


Delivery), which, Automates
• Building code
• Testing applications
• Deploying to servers/environments

Architecture:
Jenkins follows a master–agent (controller–agent) model

Jenkins Master (Controller):


• This is the central control unit,
dispatches build requests to
available agents, collects &
presents results from the agents.
Jenkins Agent (Node/Slave):
• Agents are separate machines or
containers that execute the build
jobs dispatched by the Master.
• Multiple agents can be connected
to a single Master, allowing for
parallel execution.

Jenkins installation on ubuntu:


Step1: Update system & install Java
ubuntu@ip-172-31-1-6:~$ sudo apt update
sudo apt install -y fontconfig openjdk-17-jre
java -version

openjdk version "17.0.16" 2025-07-15


OpenJDK Runtime Environment (build 17.0.16+8-Ubuntu-0ubuntu124.04.1)
OpenJDK 64-Bit Server VM (build 17.0.16+8-Ubuntu-0ubuntu124.04.1, mixed mode,
sharing)

Step2: Add Jenkins repository & key


ubuntu@ip-172-31-1-6:~$ curl -fsSL [Link]
[Link] | sudo tee \
/usr/share/keyrings/[Link] > /dev/null

echo deb [signed-by=/usr/share/keyrings/[Link]] \


[Link] binary/ | sudo tee \
/etc/apt/[Link].d/[Link] > /dev/null

Step3: Install Jenkins


ubuntu@ip-172-31-1-6:~$ sudo apt update
sudo apt install -y jenkins

Step4. Start and enable service


ubuntu@ip-172-31-1-6:~$ sudo systemctl enable jenkins
sudo systemctl start jenkins
sudo systemctl status jenkins
Active: active (running) since Thu 2025-09-18 01:44:54 UTC; 22s ago

152
Step5. Access Jenkins UI
[Link]

admin password:
ubuntu@ip-172-31-1-6:~$ sudo cat /var/lib/jenkins/secrets/initialAdminPassword

go with Install suggested plugins

Manage Jenkins:
Most standard administrative tasks can be performed from Manage Jenkins section of the dashboard
1. System: Configure global settings and paths for the Jenkins controller like home directory (On
Ubuntu by default, this is set to /var/lib/jenkins.), Number of executors (determines how many
concurrent builds Jenkins can perform) etc…

2. Tools: Tools are external software that Jenkins needs to run builds. Tools section used to
Configure tools, their locations, and automatic installers.
Examples: JDK (Java Development Kit), Maven, Gradle

3. Plugins: Plugins extend Jenkins’ functionality, without plugins, Jenkins is just a barebones
automation server. Plugins section used to Add, update, remove, disable/enable plugins.
Examples: Git Plugin → adds Git SCM support, Docker Plugin → integrate Docker in builds.
• Updates → Shows available updates for installed plugins.
• Available Plugins → Browse and install new plugins.
• Installed → Shows currently installed plugins.
• Advanced → Manual upload plugins downloaded from repository.

4. Nodes: A Node is any machine Jenkins uses to run jobs. nodes section used to Add, remove,
control, and monitor the nodes used for the agents on which build jobs run.
• Master (Built-in Node)
o Runs the Jenkins web UI and scheduling.
o Can also run jobs (but best practice: set its executors to 0 and use only agents).
• Agent (Slave Node)
o Remote machine(s) that run build jobs.

153
o Connected to the master over SSH, JNLP, or cloud integrations.
o Useful for distributing workloads, running builds on different OS or
environments.

Addition of New node (Manage Jenkins → Nodes → New Node)


When adding a new node, you configure:
• Node Name → Unique identifier (e.g., linux-agent-01).
• Remote Root Directory → Path on the agent machine where Jenkins stores workspaces.
• Labels → Tags to group nodes (e.g., linux, docker, windows). Jobs can target nodes using
labels.
• # of Executors → Number of concurrent builds allowed on that node.
• Usage →
o Use this node as much as possible
o Only build jobs with label expressions matching this node
• Launch Method → How Jenkins connects:
o SSH → Most common.
o JNLP (Java Web Start) → Agent connects to master.
o Windows Service → Run agent as a Windows service.
o Cloud (e.g., AWS, Kubernetes, Docker) → Nodes created on demand.

5. Clouds: allows for the configuration and integration of various cloud providers to dynamically
provision build agents. This functionality is crucial for scaling Jenkins environments, as it
enables the creation and destruction of agents in the cloud as needed.

6. Appearance: used to customize jenkin UI's look and feel, specifically by installing theme
plugins like Dark Theme or Material Theme.

7. Managed files: centralized configuration files stored in Jenkins. Instead of hardcoding config
files in every job, you manage in Jenkins and reuse them across jobs or pipelines.
Ex. Maven [Link]

8. Security: manages to configure authentication, authorization, and overall access control.


• Authentication ("Who are you?)à Defines how Jenkins knows the identity of users.
o Jenkins’ own user database (local accounts).
o LDAP / Active Directory (corporate directory integration)àcommonly used
• Authorization ("What can you do?")à Defines what authenticated users allowed to do.
o Matrix-based security (fine-grained permissions).
o Project-based matrix authorization (different jobs can have different permissions).
o Logged-in users can do anything (simpler, but risky).
o Anyone can do anything (not recommended).

Ex. Create a project, create a user and provide necessary access


<to be updated>

9. Credentials: credentials are a secure way to store and manage sensitive information like
passwords, tokens, API keys, and SSH keys.
Manage Jenkins à Credentials à system à Global credentialsà Add Credentials
• Secret Text: single string of secret text, such as an API key or personal access token.
• Username with password: Jenkins expose these as environment variables during build.
• SSH Username with Private Key: credential used for authenticating via SSH.

154
• Secret file: A credential for uploading a file that contains sensitive information. The file is
temporarily made available to a job during execution.
• Certificate: Used for certificates in PKCS#12 format.
Use with “Credentials” step in Jenkinsfile (Pipeline script), this binds the credential to a variable that
is available for a specified block of code.

10. Users: refers to the process of creating, configuring and maintaining Jenkins internal users,
Administrators with the appropriate permissions can perform following actions.
• Creating new users.
• Configuring user details such as full name, email address, and password.
• Modifying user information.
• Deleting users.

11. System information: provides detailed runtime report of the Jenkins controller (master)
environment. It’s mainly used for troubleshooting, debugging, and support.

Jobs in Jenkins:
Jenkins jobs" are automated processes within the Jenkins CI/CD tool that perform tasks like code
compilation, testing, and deployment, often integrated with version control systems like Git.

Types of Jenkins Jobs


• Freestyle Project: The most basic type, allowing build, test, and deployment steps.
• Pipeline Project: Defines the entire build, test, and deployment process as code using Jenkins.
• Multi-configuration Project: Allows running same build with different configurations.
• Multibranch Pipeline: Integrates with Git, automatically build & test branches from code repo
• External Job: Runs jobs on remote machines or other external systems.
• Folder: Used to organize other Jenkins jobs and projects.

Jenkins pipeline options:


Status: Shows the current state of the pipeline (Success, Failed, In progress, Not built yet), Also
displays the build history, duration, and logs.

Changes: Lists the SCM (Source Control) changes (like Git commits) included in each build. Useful to
see what code changes triggered the build.

Build Now: Manually triggers a new pipeline run immediately, regardless of any triggers. Great for
testing new changes or forcing a rebuild.

Configure: modify pipeline settings and definitions, such as:


• Pipeline type (Scripted / Declarative / SCM)
• Build triggers (e.g., GitHub webhook, schedule)
• Environment variables
• Post-build actions

Delete Pipeline: Permanently removes pipeline job from Jenkins (deletes build history & logs too).

Stages: Shows each stage’s status and execution time, helping diagnose failures quickly (Blue Ocean/
classic view).

Rename: change the pipeline job’s name. Jenkins will update internal references but be cautious if
other jobs refer to it.

155
Pipeline Syntax: Syntax Generator, a built-in helper to generate Jenkinsfile code snippets.
• checkout scm
• sh or bat commands
• withCredentials
• archiveArtifacts etc.

Credentials: store and manage secrets (e.g., SSH keys, tokens, passwords) securely. Refer these
credentials inside pipelines using Jenkins credentials IDs.

156
CI/CD (Continuous Integration & Continuous Deployment/Delivery)
Continuous Integration (CI) is the practice of automatically building, testing, and validating code every
time a developer commits changes to a shared repository.

continuous delivery or continuous deployment (CD): both of which are automation-focused practices
that automate the release of code from a repository to a production environment.

Continuous delivery: automatically prepares code for release, but requires a manual approval to
deploy to production
Continuous deployment: automatically deploys every validated change to production.

Step1: Code Commit (Developer Action):


• Developers write code & push it to a shared Git repository (GitHub, GitLab, Bitbucket, etc.).
• This triggers the Jenkins CI pipeline (via webhook or periodic polling).

Step2: Code Checkout: Jenkins checks out the latest code from the Git repository.
git branch: 'main', url: '[Link]

Step3: Build the Application: Jenkins compiles code & builds the application using a build tool like:
• Maven (for Java)
• Gradle
• npm/yarn (for [Link])
Ex. (maven): sh 'mvn clean package -DskipTests' à Generates build artifacts like .jar or .war files.

Step4: Run Automated Tests


• Unit and integration tests are executed automatically.
• Ensures new code doesn’t break existing functionality.
Ex. sh 'mvn test' à Jenkins shows test results in the build console or as a report.

Step5: Static Code Analysis, Jenkins integrates with tools like:


• SonarQube (code quality, security, and coverage)
• Checkstyle / PMD / FindBugs
Ex. withSonarQubeEnv('SonarQube') {
sh 'mvn sonar:sonar'
}

Step6: Code Quality Gate


• Jenkins waits for SonarQube Quality Gate results.
• The build fails if quality rules (like code coverage, bugs, vulnerabilities) don’t pass.

Step7: Push Artifacts to Repository (Optional) Artifacts can be published to repositories like:
• JFrog Artifactory
• Nexus
• AWS S3
Ex. def server = [Link]('jfrog-server')
def uploadSpec = """{
"files": [{"pattern": "target/*.war", "target": "libs-release-local/java-app/"}]
}"""
[Link] spec: uploadSpec

157
Step8: Archive Build Artifacts
• store the built .jar or .war file locally for later use (for deployment, QA testing, etc.).
Ex. archiveArtifacts artifacts: 'target/*.war', fingerprint: true

Step9: deploy to tomcat: copy war files using scp and restart tomcat
// Make sure Jenkins has SSH credentials set up for the remote server
sshagent(['tomcat-ssh-key']) {
sh """
scp -o StrictHostKeyChecking=no target/*.war ${TOMCAT_SERVER}:${WAR_PATH}
ssh ${TOMCAT_SERVER} 'sudo systemctl restart tomcat'
"""

Step10: Notifications: Jenkins sends build notifications via:


• Email
• Slack / Teams
• Webhook
mail to: 'dev-team@[Link]',
subject: "Build ${[Link]}: ${env.JOB_NAME}",
body: "Check Jenkins for details."

Step11: Continuous Feedback: Developers get immediate feedback on:


• Build status
• Test results
• Code quality
• Deployment readiness
This feedback loop helps catch issues early — a key principle of CI.

Summary of Jenkins CI & CD Flow


1. Code Commit à Git
2. Checkout Code à Jenkins Git Plugin
3. Build à Maven/Gradle
4. Run Tests (Unit/integration) à JUnit / TestNG
5. Static Code Analysis à SonarQube Plugin
6. Quality Gate à SonarQube
7. Push Artifacts à Artifactory (J Frog)
8. Archive Artifacts(local) à Jenkins
9. Deploy to tomcat (SCO) + restart Tomcat deployed WAR
10. Notify Team à Email / Slack
11. Feedback Loop à Jenkins Dashboard

Sample CI/CD Jenkinsfile for Java Maven App (Sonar + JFrog + Tomcat):
• Git clone
• Maven build
• Unit testing
• SonarQube code analysis
• Quality gate enforcement
• WAR artifact upload to JFrog Artifactory
• War file deployment to tomcat
• Email notification

158
pipeline {
agent any

environment {
GIT_REPO = '[Link]
BRANCH = 'main'
SONARQUBE_ENV = 'SonarQube'
MAVEN_HOME = tool name: 'Maven3', type: 'maven'
ARTIFACTORY_SERVER = 'jfrog-server'
ARTIFACTORY_REPO = 'libs-release-local'
TOMCAT_SERVER = 'ec2-user@<Tomcat-Server-IP>' // remote Tomcat server SSH user@IP
WAR_PATH = '/opt/tomcat/webapps/' // Tomcat webapps folder
EMAIL_RECIPIENTS = 'dev-team@[Link]'
}

stages {

stage('Checkout Code') {
steps {
echo " Cloning source from ${GIT_REPO}"
git branch: "${BRANCH}", url: "${GIT_REPO}"
}
}

stage('Build & Unit Test') {


steps {
echo " Running Maven build and tests"
sh """
${MAVEN_HOME}/bin/mvn clean test
${MAVEN_HOME}/bin/mvn package -DskipTests
"""
}
post {
always {
junit '**/target/surefire-reports/*.xml'
}
}
}

stage('SonarQube Code Analysis') {


environment {
scannerHome = tool 'SonarQubeScanner'
}
steps {
echo " Running SonarQube Analysis"
withSonarQubeEnv("${SONARQUBE_ENV}") {
sh """
${scannerHome}/bin/sonar-scanner \
-[Link]=java-app \
-[Link]=src \
-[Link]=target \

159
-[Link]=JavaApp \
-[Link]=1.0
"""
}
}
}

stage('Quality Gate') {
steps {
echo " Waiting for SonarQube quality gate..."
timeout(time: 2, unit: 'MINUTES') {
waitForQualityGate abortPipeline: true
}
}
}

stage('Publish to JFrog Artifactory') {


steps {
echo " Uploading WAR to JFrog Artifactory"
script {
def server = [Link]("${ARTIFACTORY_SERVER}")
def uploadSpec = """{
"files": [
{
"pattern": "target/*.war",
"target": "${ARTIFACTORY_REPO}/java-app/"
}
]
}"""
[Link] spec: uploadSpec
[Link]
}
}
}

stage('Archive Artifact') {
steps {
echo " Archiving WAR file"
archiveArtifacts artifacts: 'target/*.war', fingerprint: true
}
}

stage('Deploy to Tomcat') {
steps {
echo " Deploying WAR file to Tomcat server"
// Make sure Jenkins has SSH credentials set up for the remote server
sshagent(['tomcat-ssh-key']) {
sh """
scp -o StrictHostKeyChecking=no target/*.war ${TOMCAT_SERVER}:${WAR_PATH}
ssh ${TOMCAT_SERVER} 'sudo systemctl restart tomcat'
"""

160
}
}
}
}

post {
success {
echo " CI/CD Pipeline executed successfully!"
mail to: "${EMAIL_RECIPIENTS}",
subject: " SUCCESS: Jenkins Build #${BUILD_NUMBER} - ${JOB_NAME}",
body: """
The Jenkins CI/CD pipeline completed successfully.
WAR deployed to Tomcat Server.
Build Details: ${BUILD_URL}
"""
}
failure {
echo " CI/CD Pipeline failed!"
mail to: "${EMAIL_RECIPIENTS}",
subject: " FAILURE: Jenkins Build #${BUILD_NUMBER} - ${JOB_NAME}",
body: """
The Jenkins CI/CD pipeline failed.
Check logs here: ${BUILD_URL}
"""
}
}
}

Necessary Plugins and Credentials to run the pipeline


Jenkins Plugins
Install:
• Git Plugin
• Maven Integration Plugin
• SonarQube Scanner for Jenkins
• JFrog Artifactory Plugin
• SSH Agent Plugin
• Email Extension Plugin

Credentials Setup
1. SonarQube Server
o Configure in Jenkins → Manage Jenkins → Configure System → SonarQube Servers
o Add token and name it SonarQube.
2. JFrog Artifactory Server
o Configure under Manage Jenkins → Configure System → Artifactory.
o Name it jfrog-server.
3. SSH Key for Tomcat Deployment
o Go to Manage Jenkins → Credentials → System → Global credentials (unrestricted)
o Add your private key (same key as in ~/.ssh/authorized_keys on Tomcat server).
o ID: tomcat-ssh-key (used in sshagent(['tomcat-ssh-key'])).

Tomcat Server Setup

161
• Ensure Tomcat is installed and running (e.g., /opt/tomcat/).
• Jenkins user must have SSH access to this server.
• The WAR file will be copied to ${WAR_PATH} (e.g., /opt/tomcat/webapps/).
• Restart Tomcat using:

Deployment using Anisble:


For above pipeline example (Git → SonarQube → JFrog → Tomcat), instead of using scp and ssh, deploy
WAR into Tomcat using Ansible.

Step1: In Jenkins file, replace stage('Deploy to Tomcat') by stage('Deploy using Ansible') as below
stage('Deploy to Tomcat') {
steps {
echo " Deploying WAR file to Tomcat server"
sshagent(['tomcat-ssh-key']) {
sh """
scp -o StrictHostKeyChecking=no target/*.war ${TOMCAT_SERVER}:${WAR_PATH}
ssh ${TOMCAT_SERVER} 'sudo systemctl restart tomcat'
"""
}
}
}

stage('Deploy using Ansible') {


steps {
echo "Deploying WAR using Ansible"
// Ensure Ansible is installed on the Jenkins agent
sh """
ansible-playbook -i ansible/inventory/dev ansible/[Link] \
--extra-vars "war_file=target/[Link]"
"""
}
}

Step2: Create an Ansible Playbook


• Create a folder in your Git repo (or on the Jenkins server):

Vi ansible/inventory/[Link]
[tomcat]
ec2-user@<Tomcat-Server-IP> ansible_ssh_private_key_file=~/.ssh/[Link]
• ansible/[Link]
---
- name: Deploy Java WAR to Tomcat

162
hosts: tomcat
become: yes

vars:
war_source: "{{ war_file }}"
deploy_path: /opt/tomcat/webapps/

tasks:
- name: Stop Tomcat service
service:
name: tomcat
state: stopped

- name: Copy WAR file to Tomcat webapps directory


copy:
src: "{{ war_source }}"
dest: "{{ deploy_path }}"
owner: tomcat
group: tomcat
mode: '0644'

- name: Start Tomcat service


service:
name: tomcat
state: started

Pre perquisites:
• Jenkins agent must have Ansible installed (ansible --version should work).
• The Jenkins user or node must have SSH access to the target Tomcat server.

Java app deployment using K8s through docker image:


For K8s deployment, need to retain Git(checkout) → Maven (build & test) → SonarQube (analysis)
stages are as it is. Docker Builds image from WAR and pushes to a Docker registry (JFrog Docker
registry). Then, JFrog image pulled & deployed to cluster using K8S manifest (Deployment + Service).

Step 1: Create Dockerfile In Git repo root (Dockerfile):


Here, java app image is built using Tomcat 9 Base Image, then, WAR file copied from local target
directory into Tomcat’s webapps folder. When Tomcat starts, it automatically deploys the WAR file.

FROM tomcat:9-jdk11-openjdk
COPY target/[Link] /usr/local/tomcat/webapps/[Link]
EXPOSE 8080
CMD ["[Link]", "run"]

Step2: Kubernetes manifest: deploys docker images from Jfrog repo into clusters
• inside git repo, create

163
• k8s/[Link]
apiVersion: apps/v1
kind: Deployment
metadata:
name: java-app
labels:
app: java-app
spec:
replicas: 2
selector:
matchLabels:
app: java-app
template:
metadata:
labels:
app: java-app
spec:
containers:
- name: java-app
image: <your-jfrog-repo>/java-app:latest
ports:
- containerPort: 8080

• k8s/[Link]
apiVersion: v1
kind: Service
metadata:
name: java-app-service
spec:
selector:
app: java-app
ports:
- port: 80
targetPort: 8080
type: LoadBalancer

Step3: Update Jenkinsfile


Here, instead of pushing and archiving .war, docker image will be pushed to jfrog and archived, again,
image will be utilized by k8s, stages to be updated accordingly

pipeline {
agent any

environment {
GIT_REPO = '[Link]
BRANCH = 'main'

164
SONARQUBE_ENV = 'SonarQube'
MAVEN_HOME = tool name: 'Maven3', type: 'maven'
DOCKER_REGISTRY = 'your-jfrog-docker-registry' // Example: [Link]/docker
IMAGE_NAME = 'java-app'
EMAIL_RECIPIENTS = 'dev-team@[Link]'
KUBECONFIG_CREDENTIALS = 'kubeconfig-cred' // Jenkins credential ID for kubeconfig
}

stage('Publish to JFrog Artifactory') {


steps {
echo " Uploading WAR to JFrog Artifactory"
script {
def server = [Link]("${ARTIFACTORY_SERVER}")
def uploadSpec = """{
"files": [
{
"pattern": "target/*.war",
"target": "${ARTIFACTORY_REPO}/java-app/"
}
]
}"""
[Link] spec: uploadSpec
[Link]
}
}
}

stage('Archive Artifact') {
steps {
echo " Archiving WAR file"
archiveArtifacts artifacts: 'target/*.war', fingerprint: true
}
}

stage('Deploy to Tomcat') {
steps {
echo " Deploying WAR file to Tomcat server"
// Make sure Jenkins has SSH credentials set up for the remote server
sshagent(['tomcat-ssh-key']) {
sh """
scp -o StrictHostKeyChecking=no target/*.war ${TOMCAT_SERVER}:${WAR_PATH}
ssh ${TOMCAT_SERVER} 'sudo systemctl restart tomcat'
"""
}
}
}
}

stage('Build Docker Image & push to repo') {


steps {
script {

165
[Link]("[Link] 'jfrog-docker-credentials') {
def app = [Link]("${DOCKER_REGISTRY}/${IMAGE_NAME}:${BUILD_NUMBER}")
[Link]()
[Link]("latest")
}
}
}
}

stage('Deploy to Kubernetes') {
steps {
echo "Deploying Java App to Kubernetes Cluster"
withCredentials([file(credentialsId: "${KUBECONFIG_CREDENTIALS}", variable:
'KUBECONFIG')]) {
sh """
kubectl apply -f k8s/[Link]
kubectl apply -f k8s/[Link]
kubectl rollout status deployment/java-app
"""
}
}
}
}
Parameters:
Parameters allow user to customize builds at runtime, when a pipeline has parameters defined,
Jenkins shows a “Build with Parameters” option, letting user select values before starting the job.

Types of parameters:
Type Syntax Description
String Parameter string(name: 'BRANCH', defaultValue: 'main', description: '...') Takes text input
Choice choice(name: 'ENV', choices: ['dev', 'test', 'prod'], description:
Dropdown list
Parameter '...')
Boolean booleanParam(name: 'RUN_TESTS', defaultValue: true,
Checkbox
Parameter description: '...')
Password Hidden input
password(name: 'SECRET', defaultValue: '', description: '...')
Parameter (masked)
text(name: 'CONFIG', defaultValue: '', description: 'Enter
Text Parameter Multiline text box
YAML or config text')
File Parameter file(name: 'UPLOAD_FILE', description: 'Upload a file') Upload file input

Java application deployment using parameters:


Enhanced Jenkins pipeline where each environment (dev, test, prod) automatically deploys to its own
Tomcat server and optionally to different JFrog repos or paths if needed.

• ENV parameterà Choose between dev, test, prod — affects deployment and naming.
• BRANCH parameter à Select which Git branch to build.
• APP_VERSION parameterà Tag artifacts and SonarQube version with this version.
• SKIP_TESTS flagà Option to skip Maven tests dynamically.
• Multiple Tomcat Servers à Dev, Test, and Prod each have their own IP or hostname.

166
• Separate Artifactory Reposà Optionally upload to different repos (e.g., libs-dev-local, libs-
test-local, etc.).
• Dynamic Email & Metadataà Emails include environment, version, server, & repository info.

Newly added Initialize Environment stageà Dynamically sets environment-specific variables


(TOMCAT_SERVER, ARTIFACTORY_REPO) based on ENV parameter.

pipeline {
agent any

// ---------- Parameters ----------


parameters {
choice(
name: 'ENV',
choices: ['dev', 'test', 'prod'],
description: 'Select the environment to deploy'
)
string(
name: 'BRANCH',
defaultValue: 'main',
description: 'Git branch to build from'
)
string(
name: 'APP_VERSION',
defaultValue: '1.0.0',
description: 'Application version (used for artifact naming)'
)
booleanParam(
name: 'SKIP_TESTS',
defaultValue: false,
description: 'Skip unit tests during Maven build'
)
}

// ---------- Global Environment Variables ----------


environment {
GIT_REPO = '[Link]
SONARQUBE_ENV = 'SonarQube'
MAVEN_HOME = tool name: 'Maven3', type: 'maven'
ARTIFACTORY_SERVER = 'jfrog-server'
EMAIL_RECIPIENTS = 'dev-team@[Link]'
WAR_PATH = '/opt/tomcat/webapps/'
}

// Stages
stages {

stage('Initialize Environment') {
steps {
script {
echo " Setting environment-specific variables for ${[Link]}"

167
if ([Link] == 'dev') {
env.TOMCAT_SERVER = 'ec2-user@[Link]'
env.ARTIFACTORY_REPO = 'libs-dev-local'
} else if ([Link] == 'test') {
env.TOMCAT_SERVER = 'ec2-user@[Link]'
env.ARTIFACTORY_REPO = 'libs-test-local'
} else if ([Link] == 'prod') {
env.TOMCAT_SERVER = 'ec2-user@[Link]'
env.ARTIFACTORY_REPO = 'libs-release-local'
}

echo " Tomcat Server: ${env.TOMCAT_SERVER}"


echo " Artifactory Repo: ${env.ARTIFACTORY_REPO}"
}
}
}

stage('Checkout Code') {
steps {
echo " Cloning source from ${GIT_REPO}, branch: ${[Link]}"
git branch: "${[Link]}", url: "${GIT_REPO}"
}
}

stage('Build & Unit Test') {


steps {
script {
def skipFlag = params.SKIP_TESTS ? "-DskipTests" : ""
echo " Running Maven build (Skip Tests: ${params.SKIP_TESTS})"
sh """
${MAVEN_HOME}/bin/mvn clean test
${MAVEN_HOME}/bin/mvn package ${skipFlag}
"""
}
}
post {
always {
junit '**/target/surefire-reports/*.xml'
}
}
}

stage('SonarQube Code Analysis') {


environment {
scannerHome = tool 'SonarQubeScanner'
}
steps {
echo "Running SonarQube Analysis"
withSonarQubeEnv("${SONARQUBE_ENV}") {
sh """

168
${scannerHome}/bin/sonar-scanner \
-[Link]=java-app-${[Link]} \
-[Link]=src \
-[Link]=target \
-[Link]=JavaApp-${[Link]} \
-[Link]=${params.APP_VERSION}
"""
}
}
}

stage('Quality Gate') {
steps {
echo " Waiting for SonarQube quality gate..."
timeout(time: 2, unit: 'MINUTES') {
waitForQualityGate abortPipeline: true
}
}
}

stage('Publish to JFrog Artifactory') {


steps {
echo " Uploading WAR to JFrog Artifactory (${env.ARTIFACTORY_REPO})"
script {
def server = [Link]("${ARTIFACTORY_SERVER}")
def uploadSpec = """{
"files": [
{
"pattern": "target/*.war",
"target": "${env.ARTIFACTORY_REPO}/java-
app/${[Link]}/${params.APP_VERSION}/"
}
]
}"""
[Link] spec: uploadSpec
[Link]
}
}
}

stage('Archive Artifact') {
steps {
echo " Archiving WAR file"
archiveArtifacts artifacts: 'target/*.war', fingerprint: true
}
}

stage('Deploy to Tomcat') {
steps {
echo " Deploying WAR to Tomcat (${[Link]} environment)"
sshagent(['tomcat-ssh-key']) {

169
sh """
scp -o StrictHostKeyChecking=no target/*.war ${TOMCAT_SERVER}:${WAR_PATH}
ssh ${TOMCAT_SERVER} 'sudo systemctl restart tomcat'
"""
}
}
}
}

// ---------- Post Actions ----------


post {
success {
echo " CI/CD Pipeline executed successfully!"
mail to: "${EMAIL_RECIPIENTS}",
subject: "SUCCESS: Jenkins Build #${BUILD_NUMBER} - ${JOB_NAME} (${[Link]})",
body: """
The Jenkins CI/CD pipeline completed successfully.
Environment: ${[Link]}
App Version: ${params.APP_VERSION}
Artifact Repo: ${env.ARTIFACTORY_REPO}
Tomcat Server: ${env.TOMCAT_SERVER}
Build URL: ${BUILD_URL}
"""
}
failure {
echo " CI/CD Pipeline failed!"
mail to: "${EMAIL_RECIPIENTS}",
subject: "FAILURE: Jenkins Build #${BUILD_NUMBER} - ${JOB_NAME} (${[Link]})",
body: """
The Jenkins CI/CD pipeline failed.
Environment: ${[Link]}
Check logs here: ${BUILD_URL}
"""
}
}
}

Above example deployment using ansible

170
Example: [Link] (Ansible Inventory)
[dev]
[Link] ansible_user=ec2-user ansible_ssh_private_key_file=~/.ssh/[Link]

[test]
[Link] ansible_user=ec2-user ansible_ssh_private_key_file=~/.ssh/[Link]

[prod]
[Link] ansible_user=ec2-user ansible_ssh_private_key_file=~/.ssh/[Link]

Microservices deployment:
Jenkins pipeline to support multi-service deployment (deploy one or more microservices in a single
run, using parameters.)

• Select single or multiple microservices at once (via checkbox or text input).


• Choose environment (dev, test, prod).
• Specify Docker image tag/version.
• Build, test, and deploy each selected service automatically — all in one go.

pipeline {
agent any

parameters {
// You can pass multiple microservices as comma-separated list
string(
name: 'SERVICES',
defaultValue: 'user-service,order-service,inventory-service',
description: 'Comma-separated list of microservices to build and deploy (e.g. user-
service,order-service)'
)

choice(
name: 'ENV',
choices: ['dev', 'test', 'prod'],
description: 'Select environment for deployment'
)

string(
name: 'IMAGE_TAG',
defaultValue: 'latest',
description: 'Docker image tag/version (e.g. 1.0.2 or latest)'
)
}

environment {
GIT_REPO = '[Link]
BRANCH = 'main'
MAVEN_HOME = tool name: 'Maven3', type: 'maven'
SONARQUBE_ENV = 'SonarQube'
DOCKER_REGISTRY = '[Link]/docker'
KUBECONFIG_CREDENTIALS = 'kubeconfig-cred'

171
}

stages {

stage('Checkout') {
steps {
git branch: "${BRANCH}", url: "${GIT_REPO}"
}
}
stage('SonarQube Code Analysis') {
steps {
script {
def serviceList = [Link](',')
for (service in serviceList) {
dir("${[Link]()}") {
withSonarQubeEnv("${SONARQUBE_ENV}") {
sh "${MAVEN_HOME}/bin/mvn sonar:sonar"
}
}
}
}
}
}

stage('Build & Test Selected Services') {


steps {
script {
def serviceList = [Link](',')
parallel [Link] { service ->
["${[Link]()}" : {
dir("${[Link]()}") {
echo " Building and testing ${[Link]()}"
sh """
${MAVEN_HOME}/bin/mvn clean package -DskipTests=false
"""
}
}]
}
}
}
}

stage('Docker Build & Push') {


steps {
script {
def serviceList = [Link](',')
parallel [Link] { service ->
["${[Link]()} Docker Build" : {
dir("${[Link]()}") {
def imageName = "${DOCKER_REGISTRY}/${[Link]()}:${IMAGE_TAG}"

172
echo " Building image ${imageName}"
sh """
docker build -t ${imageName} .
docker login -u $DOCKER_USER -p $DOCKER_PASS $DOCKER_REGISTRY
docker push ${imageName}
"""
}
}]
}
}
}
}

stage('Deploy to Kubernetes') {
steps {
withCredentials([kubeconfigFile(credentialsId: "${KUBECONFIG_CREDENTIALS}", variable:
'KUBECONFIG')]) {
script {
def serviceList = [Link](',')
for (service in serviceList) {
def svc = [Link]()
echo " Deploying ${svc} to ${ENV}"
sh """
kubectl apply -f k8s/${svc}-[Link] -n ${ENV}
kubectl set image deployment/${svc}
${svc}=${DOCKER_REGISTRY}/${svc}:${IMAGE_TAG} -n ${ENV}
kubectl rollout status deployment/${svc} -n ${ENV}
"""
}
}
}
}
}

stage('Post-Deployment Validation') {
steps {
sh "kubectl get pods -n ${ENV}"
sh "kubectl get svc -n ${ENV}"
}
}
}

post {
success {
echo " Successfully deployed services: ${SERVICES} to ${ENV} with tag ${IMAGE_TAG}"
}
failure {
echo "Deployment failed for one or more services: ${SERVICES}"
}
}
}

173
Triggers:
Triggers are used to automatically start a build or pipeline when certain events occur, for example,
when code is pushed to GitHub, when a schedule is reached, or when another job finishes.

Types of Triggers in Jenkins


1. GitHub / Git Triggers: Automatically start a build when code changes are pushed to a Git repo.
a. GitHub hook trigger for GITScm polling: (webhooks) is a push-based mechanism
where GitHub actively notifies Jenkins of changes. (majority usage)
b. Poll SCM: is a pull-based mechanism where Jenkins actively checks for changes.

pipeline {
agent any

// Jenkins to run the pipeline automatically whenever a push or PR event occurs from GitHub
triggers {
githubPush() // For GitHub webhook
}

GitHub Webhook Setup (Step-by-Step)


Step 1: Configure Jenkins Job
• Go to your Jenkins job → Configure
• Check: "GitHub project" → enter repo URL (e.g.
[Link]
• Under “Build Triggers”, tick:

⏹ “GitHub hook trigger for GITScm polling”

Step 2: Configure GitHub Webhook in GitHub repo:


• Go to Settings → Webhooks → Add webhook
• Set:
o Payload URL:
[Link]
o Content type:
application/json
o Events:
Select “Just the push event” (or include PR events if desired)
• Save webhook.

Step 3: Test It
• Push a new commit to GitHub.
• Jenkins will automatically detect it and trigger your pipeline.
manually trigger is still possible with custom parameters (for deployment or testing specific tags).

2. Periodic / Scheduled Builds: Use a CRON expression to run builds on a fixed schedule.
triggers {

cron('H 2 * * *') // runs daily at around 2 AM

3. Upstream/Downstream Job Triggers: Trigger a job after another Jenkins job completes.

174
triggers {

upstream(upstreamProjects: 'build-job', threshold: [Link])

}
[Link]
81cc39f4701b

Shared libraries:
Shared Libraries used in Jenkins Pipeline for enabling reusability, maintainability, & consistency across
multiple pipelines.

Benefits of Shared Libraries


• Reusability à Write code once, use it in multiple pipelines.
• Maintainability à Update logic in one place (the library), and all jobs get the fix.
• Consistency à All teams use the same build/deploy/test patterns.
• Version Control à You can version your shared library in Git.
• Modularity à Helps organize large, complex pipelines into logical parts.

Typical shared library repo Folder Structure

• vars/ — contains global functions accessible directly in Jenkinsfiles (e.g., buildApp()).


• src/ — contains helper classes in Java-like package structure.
• resources/ — stores static files (templates, configs, etc.).
• [Link] — documentation for library usage.
Example:
Step1: create shared lirary : jenkins-shared-library
Inside, create a simple global function:
vars/[Link]

def call(String buildTool = 'maven') {


echo "Building application using ${buildTool}"
if (buildTool == 'maven') {
sh 'mvn clean package'
} else if (buildTool == 'gradle') {
sh './gradlew build'

175
}
}

Step 2: Configure in Jenkins UI


• Manage Jenkins → Configure System
• Scroll to Global Pipeline Libraries
• Click Add
• Fill details:
o Name: shared-lib
o Default version: main (or specific branch/tag)
o Source Code Management: Git
o Repository URL: e.g. [Link]
[Link]
o Credentials: if private repo

Step 3: Use It in a Jenkinsfile


@Library('shared-lib') _
pipeline {
agent any

stages {
stage('Build') {
steps {
buildApp('maven') // runs maven from vars/[Link]
}
}
}
}

Dev SecOps:
Development, Security, and Operations is an extension of DevOps that integrates security practices
into every stage of the software development lifecycle (SDLC).

Instead of treating security as a separate step at the end, DevSecOps “shifts security left”, meaning it
builds security into the process from the very beginning.

Ideal DevSecOps CI/CD Pipeline stages:

Stage1: Checkout Code (Tools: GitHub / GitLab)


Jenkins checks out the latest version of the code from the repository (e.g., GitHub or GitLab). It ensures
that the build always runs on the most recent commit.

Stage2: Unit Tests (Tools: JUnit / PyTest)


Run unit and integration tests to validate the correctness of individual modules or functions. ensures
that recent code changes don’t break existing logic — a core DevOps “shift-left” testing principle.

Stage3: SAST (Static Application Security Testing) (Tools: SonarQube)


Analyzes source code for security vulnerabilities, bugs, & code smells before build. It detects issues like
SQL injection, XSS, insecure API usage, etc. Quality Gate can stop pipeline on severe issues.

176
Stage4: Secrets Scan (Tools: Git leaks)
Scans the codebase and git history for hardcoded credentials, API keys, or tokens that could be leaked
to public repositories — one of the most common security risks.

Stage5: Build Image (Tools: Maven & Docker)


The app is compiled, built, and containerized. Example: mvn clean package creates a JAR/WAR, then
docker build packages it into an image. This becomes the deployable artifact.

Stage6: SBOM Generation (Software Bill of Materials) (Tools: Syft)


Generates a machine-readable inventory (SBOM) of all packages, dependencies, & components inside
the image or project. This helps with transparency, license compliance, and supply-chain audits.

Stage7: SCA Scan (Software Composition Analysis) (Tools: Grype)


Scans dependencies listed in the SBOM (from Syft) against public CVE databases to detect vulnerable
open-source libraries. Prevents known-vulnerable versions from reaching production.

Stage8: Dockerfile Lint (Tools: Hadolint)


Lints (checks) the Dockerfile for best practices and security misconfigurations — e.g., running as root,
missing healthchecks, or using outdated base images. Helps harden your containers early.

Stage9: Image Vulnerability Scan (Tools: Trivy)


Performs a deep scan of the built Docker image to find OS-level CVEs, vulnerable packages, or
misconfigurations. This is one of the key container security checks.

Stage10: Sign Artifacts (Tools: Cosign)


Uses cryptographic signatures to sign container images and SBOMs. Ensures integrity and provenance
i.e., guarantees that images haven’t been tampered with and originated from a trusted pipeline.

Stage11: Push Image (Tools: JFrog Artifactory)


Pushes signed image to a trusted artifact repository (JFrog) for versioned storage & later deployment.
Artifactory enforces access control, immutability, and metadata tracking.

Stage12: IaC/K8s Scan (Tools: Checkov / Open Policy Agent (OPA))


Scans Infrastructure-as-Code (IaC) files (Terraform, Helm charts, Kubernetes YAMLs) for
misconfigurations like open ports, missing encryption, or privilege escalation. Prevents insecure
infrastructure deployment.

Stage13: Deploy to Cluster (Tools: kubectl / Helm)


Deploys the verified and signed container image to a Kubernetes cluster. Typically uses kubectl apply
or Helm charts for controlled, versioned deployments.

Stage14: DAST (Dynamic Application Security Testing) (Tools: OWASP ZAP)


Tests the running application in real time for vulnerabilities such as XSS, CSRF, broken authentication,
etc. Unlike SAST, it interacts with the app like an attacker would.

Stage15: Continuous Monitoring (Tools: Falco / Prometheus)


Monitors runtime behavior & performance metrics post-deployment. Falco detects anomalous activity
(container escape attempts), while Prometheus collects performance data for dashboards & alerts.

Stage16: Notify & Report (Tools: Slack / Email / Grafana)

177
Sends summarized build, scan, and deployment results to teams. This ensures visibility — developers,
security, and ops teams get notified of pipeline status, vulnerabilities, or incidents.

Summary:
• Code & Build (CI) à Stages 1–5
• Security Pre-Deployment (Shift Left) à Stages 3–12
• Deployment & Runtime Security (CD) à Stages 13–15
• Visibility & Feedback à Stages 16

Above pipeline achieves true DevSecOps maturity because it:


• Integrates security at every stage (from code to runtime)
• Ensures traceability and artifact integrity (via SBOM + signing)
• Enables continuous monitoring and fast feedback

Real time example on Jenkins CI/CD pipeline


<to be updated>

Java app (clone from git+ sonarqube scan + build using maven + push war to jfrog + deployment in
tomcat server)

Step1: create new job

New Itemàname<first-pipeline> àtry sample pipelineàtry sample pipeline (hello world)à


uncheck groovy sandbox

Step2: add first stage of git cloning

Pipeline syntaxàgit à enter branch & url à copy syntax

Update groovy syntax


pipeline {
agent any

stages {
stage('git clone') {
steps {
git branch: 'main', url: '[Link]
}
}
}
}

178

You might also like