Jenkins: Declarative Pipelines, Distributed Agents, and Shared Libraries

Jenkins is an open-source automation server supporting distributed build orchestration. This guide covers modern Declarative Pipeline (Jenkinsfile) syntax, controller-agent architecture, containerized dynamic build agents on Kubernetes, credential binding, and shared pipeline libraries.


⚡ Quick Dive

Declarative Pipeline Syntax Cheat Sheet

Directive Purpose Example
pipeline { ... } Root wrapper for declarative pipeline Top-level block
agent Defines where pipeline executes agent { docker { image 'golang:1.22' } }
stages Container for sequence of stages stages { stage('Build') { ... } }
environment Defines environment variables or credentials environment { DB_PASS = credentials('db-secret') }
when Conditional execution of a stage when { branch 'main' }
parallel Runs multiple stages concurrently parallel { stage('Test 1') {...} stage('Test 2') {...} }
post Actions executed after stages/pipeline post { failure { mail to: 'ops@company.com' } }
options Pipeline-wide configuration options { timeout(time: 1, unit: 'HOURS') }

Production Jenkinsfile (Declarative)

pipeline {
    agent {
        kubernetes {
            yaml '''
apiVersion: v1
kind: Pod
metadata:
  labels:
    jenkins-agent: build-pod
spec:
  containers:
  - name: golang
    image: golang:1.22-alpine
    command: ['sleep']
    args: ['99d']
  - name: docker
    image: docker:26-dind
    securityContext:
      privileged: true
'''
        }
    }

    options {
        timeout(time: 30, unit: 'MINUTES')
        disableConcurrentBuilds()
        buildDiscarder(logRotator(numToKeepStr: '20'))
    }

    environment {
        APP_NAME = 'payment-service'
        REGISTRY = 'registry.internal.company.com'
        DOCKER_CREDS = credentials('docker-registry-credentials')
    }

    stages {
        stage('Lint & Test') {
            steps {
                container('golang') {
                    sh 'go test -v -race ./...'
                }
            }
        }

        stage('Build & Push Container') {
            when {
                branch 'main'
            }
            steps {
                container('docker') {
                    sh '''
                        docker login -u ${DOCKER_CREDS_USR} -p ${DOCKER_CREDS_PSW} ${REGISTRY}
                        docker build -t ${REGISTRY}/${APP_NAME}:${BUILD_NUMBER} .
                        docker push ${REGISTRY}/${APP_NAME}:${BUILD_NUMBER}
                    '''
                }
            }
        }
    }

    post {
        always {
            cleanWs()
        }
        failure {
            echo "Pipeline failed! Alerting incident channel..."
        }
    }
}

📖 Extended Guide

1. Modern Controller-Agent Architecture

                       ┌────────────────────────────┐
                       │ Jenkins Master Controller  │
                       │ (Web UI, Job Scheduler)    │
                       └─────────────┬──────────────┘
                                     │ (Dispatches over JNLP / SSH)
         ┌───────────────────────────┼───────────────────────────┐
         ▼                           ▼                           ▼
┌──────────────────┐        ┌──────────────────┐        ┌──────────────────┐
│ Static Agent VM  │        │ Dynamic K8s Pod  │        │ Docker Container │
│ (Legacy / macOS) │        │ (Auto-scaled)    │        │ (Local Worker)   │
└──────────────────┘        └──────────────────┘        └──────────────────┘
  • Best Practice: Never execute builds on the Jenkins Master Controller. Always offload workloads to dynamic, ephemeral worker agents (e.g. Kubernetes Pods) that terminate when the build completes.

2. Declarative vs. Scripted Pipelines

  • Declarative Pipeline (pipeline { ... }): Strict, opinionated syntax with built-in validation, structured error handling, and visual stage rendering in Jenkins Blue Ocean. Recommended for 95% of use cases.
  • Scripted Pipeline (node { ... }): Imperative Groovy-based syntax providing unlimited programming flexibility at the cost of readability and maintenance complexity.

3. Enterprise Jenkins Shared Libraries

Centralize and standardize deployment logic across hundreds of microservices using Jenkins Shared Libraries:

// In shared library repository: vars/standardMicroservicePipeline.groovy
def call(Map config = [:]) {
    pipeline {
        agent any
        stages {
            stage('Standard Build') {
                steps {
                    echo "Building ${config.appName} with version ${config.version}"
                }
            }
        }
    }
}

// In individual microservice Jenkinsfile:
@Library('company-shared-lib@v2.1.0') _
standardMicroservicePipeline(appName: 'order-api', version: '1.0.0')