Devops_tutorial_Jenkins_
Devops_tutorial_Jenkins_
Architecture:
Jenkins follows a master–agent (controller–agent) model
152
Step5. Access Jenkins UI
[Link]
admin password:
ubuntu@ip-172-31-1-6:~$ sudo cat /var/lib/jenkins/secrets/initialAdminPassword
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.
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]
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.
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.
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.
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.
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'
"""
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}"
}
}
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('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}
"""
}
}
}
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'])).
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:
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'
"""
}
}
}
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
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.
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
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('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'
"""
}
}
}
}
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
• 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.
pipeline {
agent any
// 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'
}
stage('Checkout Code') {
steps {
echo " Cloning source from ${GIT_REPO}, branch: ${[Link]}"
git branch: "${[Link]}", url: "${GIT_REPO}"
}
}
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('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'
"""
}
}
}
}
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.)
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"
}
}
}
}
}
}
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.
pipeline {
agent any
// Jenkins to run the pipeline automatically whenever a push or PR event occurs from GitHub
triggers {
githubPush() // For GitHub 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 {
3. Upstream/Downstream Job Triggers: Trigger a job after another Jenkins job completes.
174
triggers {
}
[Link]
81cc39f4701b
Shared libraries:
Shared Libraries used in Jenkins Pipeline for enabling reusability, maintainability, & consistency across
multiple pipelines.
175
}
}
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.
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.
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
Java app (clone from git+ sonarqube scan + build using maven + push war to jfrog + deployment in
tomcat server)
stages {
stage('git clone') {
steps {
git branch: 'main', url: '[Link]
}
}
}
}
178