CI/CD Pipeline Implementation: Jenkins and GitLab Automation Guide
Build robust CI/CD pipelines using Jenkins and GitLab to automate testing, building, and deployment processes. Learn industry best practices for continuous integration and deployment automation.
📑 Table of Contents
- Introduction to CI/CD Pipelines
- 1. Jenkins Installation and Configuration
- Jenkins Installation on Ubuntu
- 2. GitLab CI/CD Pipeline Configuration
- Advanced GitLab CI Configuration
- 3. Jenkins Pipeline Implementation
- Declarative Jenkins Pipeline
- 4. Deployment Automation Scripts
- Blue-Green Deployment Script
- Conclusion
Introduction to CI/CD Pipelines
Continuous Integration and Continuous Deployment (CI/CD) pipelines are essential for modern software development, enabling teams to deliver code changes rapidly and reliably.
1. Jenkins Installation and Configuration
Set up Jenkins as your CI/CD automation server:
Jenkins Installation on Ubuntu
# Add Jenkins repository
curl -fsSL https://pkg.jenkins.io/debian-stable/jenkins.io.key | sudo tee
/usr/share/keyrings/jenkins-keyring.asc > /dev/null
echo deb [signed-by=/usr/share/keyrings/jenkins-keyring.asc]
https://pkg.jenkins.io/debian-stable binary/ | sudo tee
/etc/apt/sources.list.d/jenkins.list > /dev/null
# Update package index and install Jenkins
sudo apt update
sudo apt install fontconfig openjdk-11-jre jenkins -y
# Start and enable Jenkins
sudo systemctl start jenkins
sudo systemctl enable jenkins
# Configure firewall
sudo ufw allow 8080
# Get initial admin password
sudo cat /var/lib/jenkins/secrets/initialAdminPassword
2. GitLab CI/CD Pipeline Configuration
Create comprehensive GitLab CI/CD pipelines for automated testing and deployment:
Advanced GitLab CI Configuration
# .gitlab-ci.yml for a comprehensive pipeline
stages:
- validate
- test
- security
- build
- deploy-staging
- integration-tests
- deploy-production
variables:
DOCKER_DRIVER: overlay2
DOCKER_TLS_CERTDIR: "/certs"
# Validation stage
code-quality:
stage: validate
image: sonarsource/sonar-scanner-cli:latest
script:
- sonar-scanner
-Dsonar.projectKey=$CI_PROJECT_NAME
-Dsonar.sources=.
-Dsonar.host.url=$SONAR_HOST_URL
-Dsonar.login=$SONAR_TOKEN
only:
- merge_requests
- main
- develop
# Testing stage
unit-tests:
stage: test
image: php:8.1-cli
services:
- postgres:13
- redis:alpine
script:
- apt-get update -qq && apt-get install -y -qq git curl libpq-dev
- docker-php-ext-install pdo pdo_pgsql
- curl -sS https://getcomposer.org/installer | php
- php composer.phar install --no-dev --optimize-autoloader
- php artisan migrate --force
- php artisan test --coverage --min=80
artifacts:
reports:
junit: tests/reports/junit.xml
coverage_report:
coverage_format: cobertura
path: tests/reports/coverage.xml
# Security scanning
security-scan:
stage: security
image: owasp/zap2docker-stable
script:
- mkdir -p /zap/wrk/reports
- /zap/zap-baseline.py -t http://staging.example.com -r baseline-report.html
artifacts:
paths:
- baseline-report.html
allow_failure: true
# Build stage
build-application:
stage: build
image: docker:20.10.16
services:
- docker:20.10.16-dind
before_script:
- docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
script:
- docker build -t $CI_REGISTRY_IMAGE:latest .
- docker tag $CI_REGISTRY_IMAGE:latest $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA
- docker push $CI_REGISTRY_IMAGE:latest
- docker push $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA
only:
- main
- develop
# Staging deployment
deploy-staging:
stage: deploy-staging
image: alpine:latest
environment:
name: staging
url: https://staging.example.com
script:
- apk add --no-cache openssh-client curl
- ssh deploy@staging-server "cd /var/www/app && ./deploy.sh staging $CI_COMMIT_SHA"
- sleep 30
- curl -f https://staging.example.com/health || exit 1
only:
- develop
when: manual
# Production deployment
deploy-production:
stage: deploy-production
image: alpine:latest
environment:
name: production
url: https://example.com
script:
- ssh deploy@prod-server "cd /var/www/app && ./deploy.sh production $CI_COMMIT_SHA"
- sleep 60
- for i in {1..5}; do curl -f https://example.com/health && break || sleep 10; done
only:
- main
when: manual
3. Jenkins Pipeline Implementation
Create sophisticated Jenkins pipelines using Jenkinsfile:
Declarative Jenkins Pipeline
// Jenkinsfile for comprehensive CI/CD pipeline
pipeline {
agent any
environment {
REGISTRY = "docker.io/mycompany"
IMAGE_NAME = "webapp"
SLACK_CHANNEL = "#deployments"
}
options {
buildDiscarder(logRotator(numToKeepStr: "10"))
timeout(time: 1, unit: "HOURS")
retry(2)
}
stages {
stage("Checkout & Validate") {
parallel {
stage("Code Quality") {
steps {
script {
def scannerHome = tool "SonarQube Scanner"
withSonarQubeEnv("SonarQube") {
sh "${scannerHome}/bin/sonar-scanner"
}
}
timeout(time: 10, unit: "MINUTES") {
waitForQualityGate abortPipeline: true
}
}
}
stage("Dependency Check") {
steps {
sh "npm audit --audit-level moderate"
sh "composer audit"
}
}
}
}
stage("Test") {
parallel {
stage("Unit Tests") {
steps {
sh "composer install --no-dev --optimize-autoloader"
sh "php artisan test --coverage --min=80"
publishTestResults testResultsPattern: "tests/reports/junit.xml"
}
}
stage("Integration Tests") {
steps {
sh "npm ci"
sh "npm run build"
sh "cypress run"
}
}
}
}
stage("Build & Push") {
when {
anyOf {
branch "main"
branch "develop"
}
}
steps {
script {
def image = docker.build("${REGISTRY}/${IMAGE_NAME}:${BUILD_NUMBER}")
docker.withRegistry("https://index.docker.io/v1/", "dockerhub") {
image.push()
image.push("latest")
}
}
}
}
stage("Deploy to Staging") {
when {
branch "develop"
}
steps {
sh "kubectl apply -f k8s/staging/ --namespace=staging"
sh "kubectl rollout status deployment/webapp --namespace=staging"
}
}
stage("Deploy to Production") {
when {
branch "main"
}
steps {
input "Deploy to Production?"
sh "kubectl apply -f k8s/production/ --namespace=production"
sh "kubectl rollout status deployment/webapp --namespace=production"
}
}
}
post {
success {
slackSend(
channel: env.SLACK_CHANNEL,
color: "good",
message: "Pipeline succeeded for ${env.JOB_NAME}"
)
}
failure {
slackSend(
channel: env.SLACK_CHANNEL,
color: "danger",
message: "Pipeline failed for ${env.JOB_NAME}"
)
}
}
}
4. Deployment Automation Scripts
Create automated deployment scripts for reliable deployments:
Blue-Green Deployment Script
#!/bin/bash
# deploy.sh - Blue-green deployment script
ENVIRONMENT=$1
IMAGE_TAG=$2
STRATEGY=${3:-rolling}
log() {
echo "[$(date +'%Y-%m-%d %H:%M:%S')] $*"
}
blue_green_deploy() {
log "Starting blue-green deployment..."
# Deploy to green environment
kubectl apply -f k8s/$ENVIRONMENT/green/
kubectl rollout status deployment/webapp-green --namespace=$ENVIRONMENT
# Health checks
sleep 30
kubectl exec -n $ENVIRONMENT deployment/webapp-green -- curl -f http://localhost/health
if [ $? -eq 0 ]; then
log "Green environment healthy, switching traffic..."
kubectl patch service webapp -n $ENVIRONMENT -p '{"spec":{"selector":{"version":"green"}}}'
# Clean up blue environment
sleep 60
kubectl delete deployment webapp-blue -n $ENVIRONMENT || true
log "Blue-green deployment completed successfully"
else
log "Health check failed, aborting deployment"
kubectl delete deployment webapp-green -n $ENVIRONMENT
exit 1
fi
}
rolling_deploy() {
log "Starting rolling deployment..."
kubectl set image deployment/webapp webapp=$REGISTRY/$IMAGE_NAME:$IMAGE_TAG --namespace=$ENVIRONMENT
kubectl rollout status deployment/webapp --namespace=$ENVIRONMENT --timeout=600s
log "Rolling deployment completed"
}
case $STRATEGY in
blue-green)
blue_green_deploy
;;
rolling)
rolling_deploy
;;
*)
log "Unknown deployment strategy: $STRATEGY"
exit 1
;;
esac
Conclusion
Implementing robust CI/CD pipelines with Jenkins and GitLab enables teams to deliver software faster and more reliably. These automated workflows reduce manual errors, improve code quality, and provide rapid feedback to developers.
Was this article helpful?
About Ramesh Sundararamaiah
Red Hat Certified Architect
Expert in Linux system administration, DevOps automation, and cloud infrastructure. Specializing in Red Hat Enterprise Linux, CentOS, Ubuntu, Docker, Ansible, and enterprise IT solutions.