Jenkins CI/CD Guide
Introduction
Jenkins is an open-source automation server that enables developers to build, test, and deploy their software. It provides hundreds of plugins to support building, deploying, and automating any project.
Key Features:
- Easy installation and configuration
- Rich plugin ecosystem
- Distributed builds
- Pipeline as Code
- Extensive monitoring
- Community support
Setup & Configuration
Docker Installation
# Dockerfile for Jenkins with Docker support
FROM jenkins/jenkins:lts
USER root
# Install Docker CLI
RUN apt-get update && \
apt-get -y install apt-transport-https ca-certificates curl software-properties-common && \
curl -fsSL https://download.docker.com/linux/debian/gpg | apt-key add - && \
add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/debian $(lsb_release -cs) stable" && \
apt-get update && \
apt-get -y install docker-ce-cli
# Install Docker Compose
RUN curl -L "https://github.com/docker/compose/releases/download/1.29.2/docker-compose-$(uname -s)-$(uname -m)" \
-o /usr/local/bin/docker-compose && \
chmod +x /usr/local/bin/docker-compose
USER jenkins
Configuration as Code
# jenkins.yaml
jenkins:
systemMessage: "Jenkins configured automatically by Jenkins Configuration as Code plugin"
numExecutors: 2
scmCheckoutRetryCount: 2
mode: NORMAL
securityRealm:
local:
allowsSignup: false
users:
- id: "admin"
password: "${ADMIN_PASSWORD}"
authorizationStrategy:
globalMatrix:
permissions:
- "Overall/Administer:admin"
- "Overall/Read:authenticated"
nodes:
- permanent:
name: "agent1"
remoteFS: "/home/jenkins"
launcher:
ssh:
host: "agent1.example.com"
credentialsId: "agent-ssh-key"
Pipeline Design
Declarative Pipeline
pipeline {
agent {
docker {
image 'node:16-alpine'
args '-v $HOME/.npm:/root/.npm'
}
}
environment {
CI = 'true'
STAGING_SERVER = 'staging.example.com'
PRODUCTION_SERVER = 'prod.example.com'
}
stages {
stage('Install') {
steps {
sh 'npm ci'
}
}
stage('Test') {
parallel {
stage('Unit Tests') {
steps {
sh 'npm test'
}
}
stage('Lint') {
steps {
sh 'npm run lint'
}
}
}
}
stage('Build') {
steps {
sh 'npm run build'
archiveArtifacts artifacts: 'dist/**/*'
}
}
stage('Deploy to Staging') {
when {
branch 'develop'
}
steps {
withCredentials([sshUserPrivateKey(credentialsId: 'ssh-key', keyFileVariable: 'SSH_KEY')]) {
sh """
scp -i \$SSH_KEY dist/* user@\${STAGING_SERVER}:/var/www/html/
ssh -i \$SSH_KEY user@\${STAGING_SERVER} 'sudo systemctl restart nginx'
"""
}
}
}
stage('Deploy to Production') {
when {
branch 'main'
}
steps {
input message: 'Deploy to production?'
withCredentials([sshUserPrivateKey(credentialsId: 'ssh-key', keyFileVariable: 'SSH_KEY')]) {
sh """
scp -i \$SSH_KEY dist/* user@\${PRODUCTION_SERVER}:/var/www/html/
ssh -i \$SSH_KEY user@\${PRODUCTION_SERVER} 'sudo systemctl restart nginx'
"""
}
}
}
}
post {
always {
cleanWs()
emailext subject: "Build ${currentBuild.result}: Job '${env.JOB_NAME} [${env.BUILD_NUMBER}]'",
body: """Build: ${currentBuild.result}
Job: ${env.JOB_NAME}
Build Number: ${env.BUILD_NUMBER}
Build URL: ${env.BUILD_URL}""",
recipientProviders: [[$class: 'DevelopersRecipientProvider']]
}
}
}
Shared Libraries
// vars/dockerBuild.groovy
def call(String imageName, String tag = 'latest') {
sh """
docker build -t ${imageName}:${tag} .
docker push ${imageName}:${tag}
"""
}
// Usage in Jenkinsfile
@Library('my-shared-library') _
pipeline {
agent any
stages {
stage('Build Docker Image') {
steps {
dockerBuild('my-app', env.BUILD_NUMBER)
}
}
}
}
Security & Best Practices
Security Configuration:
- Enable security
- Use HTTPS
- Implement RBAC
- Secure credentials
- Regular updates
- Audit logging
Credentials Management
pipeline {
agent any
environment {
AWS_CREDS = credentials('aws-credentials')
DOCKER_REGISTRY = credentials('docker-registry')
}
stages {
stage('Deploy') {
steps {
withCredentials([
usernamePassword(
credentialsId: 'app-credentials',
usernameVariable: 'APP_USER',
passwordVariable: 'APP_PASS'
)
]) {
sh """
docker login -u $DOCKER_REGISTRY_USR -p $DOCKER_REGISTRY_PSW
aws configure set aws_access_key_id $AWS_CREDS_USR
aws configure set aws_secret_access_key $AWS_CREDS_PSW
./deploy.sh --user $APP_USER --password $APP_PASS
"""
}
}
}
}
}
Essential Plugins
Core Plugins:
- Pipeline
- Git
- Docker
- Credentials
- Configuration as Code
- Blue Ocean
Testing & Quality:
- JUnit
- SonarQube Scanner
- Code Coverage API
- Checkstyle
Deployment:
- Kubernetes
- AWS
- Azure
- SSH Agent
Automation Examples
Multi-Branch Pipeline
// Jenkinsfile for multi-branch pipeline
pipeline {
agent any
options {
buildDiscarder(logRotator(numToKeepStr: '5'))
durabilityHint('PERFORMANCE_OPTIMIZED')
timeout(time: 1, unit: 'HOURS')
}
triggers {
pollSCM('H/15 * * * *')
}
environment {
BRANCH_NAME = "${env.BRANCH_NAME}"
ENVIRONMENT = getBranchEnvironment("${env.BRANCH_NAME}")
}
stages {
stage('Build') {
steps {
script {
def buildNumber = env.BUILD_NUMBER
def branchName = env.BRANCH_NAME.replaceAll('/', '-')
docker.build("myapp:${branchName}-${buildNumber}")
}
}
}
stage('Test') {
steps {
parallel(
"Unit Tests": {
sh 'npm test'
},
"Integration Tests": {
sh 'npm run test:integration'
}
)
}
}
stage('Deploy') {
when {
expression { ENVIRONMENT != null }
}
steps {
script {
deploy(ENVIRONMENT)
}
}
}
}
}
def getBranchEnvironment(branch) {
switch(branch) {
case 'main':
return 'production'
case 'develop':
return 'staging'
case ~/^release\/.*$/:
return 'qa'
default:
return null
}
}
def deploy(environment) {
echo "Deploying to ${environment}"
// Deployment logic here
}