DevOps
Jenkins
Master Jenkins CI/CD: architecture, installation, pipelines, and creating both declarative and scripted pipelines for automation.
By TechCoder TeamLast updated: 2026-06-02
In a Nutshell
Master Jenkins CI/CD: architecture, installation, pipelines, and creating both declarative and scripted pipelines for automation. This hands-on tutorial focuses on practical implementation of jenkins concepts.
Jenkins
Jenkins is the most widely used open-source automation server for building, testing, and deploying software.
Jenkins Architecture
┌─────────────────────────────────────────────────────────────────┐
│ Jenkins Architecture │
├─────────────────────────────────────────────────────────────────┤
│ │
│ ┌──────────────┐ │
│ │ Jenkins │ │
│ │ Master │ │
│ │ (Controller)│ │
│ │ │ │
│ │ ┌──────────┐ │ │
│ │ │ Web UI │ │ │
│ │ │ REST API │ │ │
│ │ │ Queue │ │ │
│ │ └──────────┘ │ │
│ └──────┬───────┘ │
│ │ │
│ │ delegates jobs │
│ ▼ │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
│ │ Agent 1 │ │ Agent 2 │ │ Agent 3 │ │
│ │ (Linux) │ │ (Windows) │ │ (Docker) │ │
│ │ │ │ │ │ │ │
│ │ • Build │ │ • .NET apps │ │ • Containers │ │
│ │ • Test │ │ • PowerShell │ │ • Isolated │ │
│ │ • Deploy │ │ │ │ │ │
│ └──────────────┘ └──────────────┘ └──────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────┘
Master (Controller)
- Web Interface: Manage jobs, view builds
- Job Scheduling: Queue and distribute work
- Plugin Management: Extend functionality
- Configuration: Store job and system config
Agents (Nodes)
- Execute build jobs delegated by master
- Can run on different OS (Linux, Windows, macOS)
- Label-based job assignment
- Scale horizontally
Installation
Docker (Recommended)
# Run Jenkins
docker run -d \
-p 8080:8080 \
-p 50000:50000 \
-v jenkins_home:/var/jenkins_home \
--name jenkins \
jenkins/jenkins:lts
# Get initial admin password
docker exec jenkins cat /var/jenkins_home/secrets/initialAdminPassword
# Access at http://localhost:8080
Kubernetes
apiVersion: apps/v1
kind: Deployment
metadata:
name: jenkins
spec:
replicas: 1
selector:
matchLabels:
app: jenkins
template:
metadata:
labels:
app: jenkins
spec:
containers:
- name: jenkins
image: jenkins/jenkins:lts
ports:
- containerPort: 8080
- containerPort: 50000
volumeMounts:
- name: jenkins-home
mountPath: /var/jenkins_home
volumes:
- name: jenkins-home
persistentVolumeClaim:
claimName: jenkins-pvc
Jenkinsfile
Declarative Pipeline
pipeline {
agent any
environment {
APP_NAME = 'my-app'
VERSION = '1.0.0'
}
options {
buildDiscarder(logRotator(numToKeepStr: '10'))
disableConcurrentBuilds()
timeout(time: 30, unit: 'MINUTES')
}
triggers {
cron('H 2 * * *') // Daily at 2 AM
pollSCM('*/5 * * * *') // Poll every 5 minutes
}
parameters {
string(name: 'ENVIRONMENT', defaultValue: 'dev', description: 'Target environment')
booleanParam(name: 'SKIP_TESTS', defaultValue: false, description: 'Skip tests?')
choice(name: 'DEPLOY_STRATEGY', choices: ['blue-green', 'canary', 'rolling'], description: 'Deployment strategy')
}
stages {
stage('Checkout') {
steps {
checkout scm
sh 'git log --oneline -5'
}
}
stage('Build') {
when {
not { params.SKIP_TESTS }
}
steps {
sh 'mvn clean compile'
}
}
stage('Test') {
parallel {
stage('Unit Tests') {
steps {
sh 'mvn test'
}
post {
always {
junit '**/target/surefire-reports/*.xml'
}
}
}
stage('Integration Tests') {
steps {
sh 'mvn integration-test'
}
}
}
}
stage('Security Scan') {
steps {
sh 'mvn dependency-check:check'
}
}
stage('Package') {
steps {
sh 'mvn package -DskipTests'
archiveArtifacts artifacts: 'target/*.jar', fingerprint: true
}
}
stage('Deploy') {
when {
anyOf {
branch 'main'
branch 'release/*'
}
}
steps {
script {
if (params.DEPLOY_STRATEGY == 'blue-green') {
sh './deploy-blue-green.sh'
} else if (params.DEPLOY_STRATEGY == 'canary') {
sh './deploy-canary.sh'
} else {
sh './deploy-rolling.sh'
}
}
}
}
}
post {
always {
echo 'Pipeline completed'
cleanWs()
}
success {
slackSend(color: 'good', message: "Build succeeded: ${env.JOB_NAME} - ${env.BUILD_NUMBER}")
}
failure {
slackSend(color: 'danger', message: "Build failed: ${env.JOB_NAME} - ${env.BUILD_NUMBER}")
mail to: 'team@example.com',
subject: "Failed Pipeline: ${currentBuild.fullDisplayName}",
body: "Check console output at ${env.BUILD_URL}"
}
unstable {
echo 'Build is unstable'
}
changed {
echo 'Build status changed'
}
}
}
Scripted Pipeline
node('linux && docker') {
try {
stage('Prepare') {
checkout scm
def commit = sh(returnStdout: true, script: 'git rev-parse --short HEAD').trim()
echo "Building commit: ${commit}"
}
stage('Build') {
def image = docker.build("myapp:${env.BUILD_NUMBER}")
}
stage('Test') {
docker.image('myapp:${env.BUILD_NUMBER}').inside {
sh 'npm test'
}
}
stage('Push') {
docker.withRegistry('https://registry.example.com', 'registry-credentials') {
docker.image('myapp:${env.BUILD_NUMBER}').push()
docker.image('myapp:${env.BUILD_NUMBER}').push('latest')
}
}
stage('Deploy') {
if (env.BRANCH_NAME == 'main') {
sh 'kubectl set image deployment/myapp myapp=myapp:${env.BUILD_NUMBER}'
}
}
currentBuild.result = 'SUCCESS'
} catch (Exception e) {
currentBuild.result = 'FAILURE'
throw e
} finally {
cleanWs()
}
}
Key Directives
Agent
// Run on any available agent
agent any
// Specific agent label
agent { label 'linux && docker' }
// Docker agent
agent {
docker {
image 'maven:3.9-eclipse-temurin-17'
args '-v /root/.m2:/root/.m2'
}
}
// Kubernetes agent
agent {
kubernetes {
yaml """
apiVersion: v1
kind: Pod
spec:
containers:
- name: maven
image: maven:3.9-eclipse-temurin-17
command: ['cat']
tty: true
"""
}
}
When Conditions
stage('Production Deploy') {
when {
branch 'main'
}
steps {
sh './deploy-prod.sh'
}
}
stage('Release Deploy') {
when {
buildingTag()
}
steps {
sh './deploy-release.sh'
}
}
stage('Manual Gate') {
when {
expression { params.ENVIRONMENT == 'prod' }
}
steps {
input message: 'Deploy to production?', ok: 'Deploy'
sh './deploy.sh'
}
}
Environment Variables
environment {
// Static values
AWS_DEFAULT_REGION = 'us-east-1'
// Dynamic values
GIT_COMMIT_SHORT = sh(returnStdout: true, script: 'git rev-parse --short HEAD').trim()
// Credentials from Jenkins
AWS_CREDENTIALS = credentials('aws-credentials')
// Creates: AWS_CREDENTIALS, AWS_CREDENTIALS_USR, AWS_CREDENTIALS_PSW
}
Input
stage('Approval') {
steps {
input message: 'Proceed with deployment?',
ok: 'Deploy',
submitter: 'admin,deploy-team',
submitterParameter: 'APPROVER',
parameters: [
choice(name: 'ENVIRONMENT', choices: ['staging', 'production']),
text(name: 'NOTES', description: 'Deployment notes')
]
}
}
Shared Libraries
Creating a Shared Library
// vars/buildJava.groovy
def call(Map config = [:]) {
pipeline {
agent { label 'linux' }
stages {
stage('Build') {
steps {
sh "mvn clean package -DskipTests=${config.skipTests ?: false}"
}
}
stage('Test') {
when { expression { !config.skipTests } }
steps {
sh 'mvn test'
}
post {
always {
junit '**/target/surefire-reports/*.xml'
}
}
}
}
}
}
// vars/deployToK8s.groovy
def call(String image, String namespace = 'default') {
sh """
kubectl set image deployment/app \
app=${image} \
-n ${namespace}
kubectl rollout status deployment/app -n ${namespace}
"""
}
Using Shared Libraries
// Jenkinsfile
@Library('my-shared-library') _
buildJava(skipTests: false)
// Or call specific function
deployToK8s('myapp:1.0', 'production')
Essential Plugins
| Plugin | Purpose |
|---|---|
| Pipeline | Core pipeline functionality |
| Git | Git integration |
| Docker Pipeline | Docker in pipelines |
| Kubernetes | Kubernetes agents |
| Blue Ocean | Modern UI |
| SonarQube Scanner | Code quality |
| Nexus Artifact Uploader | Artifact management |
| Slack Notification | Notifications |
| Credentials | Secure credential storage |
| Parameterized Trigger | Trigger jobs with params |
Best Practices
Pipeline Organization
project-root/
├── Jenkinsfile # Main pipeline
├── jenkins/
│ ├── vars/ # Shared library vars
│ ├── src/ # Library source
│ └── resources/ # Templates/configs
├── scripts/
│ ├── build.sh
│ ├── test.sh
│ └── deploy.sh
└── src/ # Application source
Security
- Use credentials plugin: Never hardcode secrets
- Master agent separation: Run builds on agents, not master
- Job-based permissions: Restrict access per team
- CSRF protection: Enable cross-site request forgery protection
- Regular updates: Keep Jenkins and plugins updated
Performance
- Lightweight checkout:
options { checkoutToSubdirectory('src') } - Stash/unstash: Share files between stages
- Parallel execution: Run independent stages in parallel
- Agent caching: Mount volumes for dependencies (m2, npm cache)
- Discard old builds:
buildDiscarder(logRotator(...))
Quiz
Quiz
Question 1 of 5What is the difference between Declarative and Scripted pipelines in Jenkins?
Scripted is newer than Declarative
Declarative has a structured syntax; Scripted is Groovy-based and flexible
Declarative doesn't support Docker; Scripted does
Scripted is for Windows only
Next Steps
Now let's explore GitHub Actions and GitLab CI—cloud-native CI/CD alternatives.