This page requires JavaScript to display.
J
Unpacking...
← DevOps
DevOps

Jenkins Reference

Declarative pipelines, a full Jenkinsfile for a PySpark project, credentials, triggers and pull requests, agents, shared libraries and best practices.

Contents
1. What Jenkins Is 2. A Declarative Jenkinsfile 3. Pipeline Syntax Reference 4. Credentials & Secrets 5. Triggers, Branches & Pull Requests 6. Agents: Static, Docker & Kubernetes 7. Shared Libraries 8. Best Practices 9. Jenkins vs Other CI/CD Tools

1. What Jenkins Is

Jenkins is an open-source automation server for CI/CD. A controller schedules work and stores configuration; agents (VMs, containers, Kubernetes pods) run the builds. Almost everything else (Git, Docker, Kubernetes, credentials, notifications) comes from plugins.

Job typeUse
PipelineA pipeline defined in a Jenkinsfile stored with the code (the standard today)
Multibranch PipelineDiscovers branches and pull requests automatically and runs each one's Jenkinsfile
Organization folderScans a whole GitHub/GitLab organization for repositories with Jenkinsfiles
FreestyleLegacy UI-configured jobs; avoid for new work, since configuration is not in version control

2. A Declarative Jenkinsfile

A CI/CD pipeline for a PySpark project: test on every branch, deploy to dev on main, and deploy to prod after manual approval.

pipeline {
  agent { docker { image 'python:3.11-slim' } }

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

  parameters {
    booleanParam(name: 'DEPLOY_PROD', defaultValue: false, description: 'Promote to prod after dev')
  }

  environment {
    DATABRICKS_HOST = 'https://adb-1234567890.11.azuredatabricks.net'
  }

  stages {
    stage('Install') {
      steps { sh 'pip install -r requirements-dev.txt' }
    }
    stage('Quality') {
      parallel {
        stage('Lint')  { steps { sh 'ruff check src tests' } }
        stage('Tests') { steps { sh 'pytest -q --junitxml=reports/junit.xml' } }
      }
    }
    stage('Build') {
      steps { sh 'python -m build --wheel' }
    }
    stage('Deploy dev') {
      when { branch 'main' }
      steps {
        withCredentials([string(credentialsId: 'databricks-dev-token', variable: 'DATABRICKS_TOKEN')]) {
          sh 'databricks bundle deploy -t dev'
        }
      }
    }
    stage('Deploy prod') {
      when { allOf { branch 'main'; expression { params.DEPLOY_PROD } } }
      steps {
        input message: 'Deploy to production?', submitter: 'release-managers'
        withCredentials([string(credentialsId: 'databricks-prod-token', variable: 'DATABRICKS_TOKEN')]) {
          sh 'databricks bundle deploy -t prod'
        }
      }
    }
  }

  post {
    always  { junit allowEmptyResults: true, testResults: 'reports/*.xml' }
    failure { echo "Build failed: ${env.BUILD_URL}" }   // or slackSend / emailext
  }
}

The Databricks CLI must be installed in the agent image. Use single quotes for shell strings so secrets are expanded by the shell, not interpolated by Groovy into the build log.

3. Pipeline Syntax Reference

DirectivePurposeExample
agentWhere the pipeline or a stage runsagent { label 'linux' }, docker { image … }, kubernetes { … }, none
stages / stage / stepsOrdered phases and the commands within themsh 'make test'
environmentEnvironment variables, optionally from credentialsAWS_CREDS = credentials('aws-ci')
parametersInputs chosen when triggering a buildstring, choice, booleanParam
optionsTimeouts, retries, concurrency, log retentionretry(2), timestamps()
triggersAutomatic startscron('H 2 * * *'), pollSCM('H/5 * * * *')
whenRun a stage conditionallybranch 'main', changeset 'sql/**', expression { … }
parallelRun stages concurrentlyLint and tests side by side
inputPause for human approvalProduction gates
postActions after the run, by outcomealways, success, failure, unstable, cleanup

In cron triggers, H spreads start times by a hash of the job name so all jobs do not fire on the same minute. Declarative syntax is preferred; Scripted pipelines (node { … }) give full Groovy but are harder to maintain.

4. Credentials & Secrets

Store secrets in the Jenkins credentials store (or an external vault via plugins) and reference them by ID. Jenkins masks bound values in console output.

environment {
  // username/password credential exposes REGISTRY (user:pass), REGISTRY_USR and REGISTRY_PSW
  REGISTRY = credentials('docker-registry')
}
steps {
  sh 'echo "$REGISTRY_PSW" | docker login -u "$REGISTRY_USR" --password-stdin myregistry.io'

  withCredentials([file(credentialsId: 'gcp-sa-key', variable: 'GOOGLE_APPLICATION_CREDENTIALS')]) {
    sh 'gcloud auth activate-service-account --key-file="$GOOGLE_APPLICATION_CREDENTIALS"'
  }
}

5. Triggers, Branches & Pull Requests

6. Agents: Static, Docker & Kubernetes

Agent typeHowTrade-off
Static agentsLong-lived VMs connected to the controller, chosen by labelSimple, but state leaks between builds and capacity is fixed
Docker agentagent { docker { image 'python:3.11' } }Clean, reproducible tool versions per build; needs Docker on the host
Kubernetes agentKubernetes plugin starts a pod per build from a pod templateElastic and isolated; the usual choice at scale
agent {
  kubernetes {
    yaml """
apiVersion: v1
kind: Pod
spec:
  containers:
    - name: python
      image: python:3.11-slim
      command: ["sleep"]
      args: ["infinity"]
"""
    defaultContainer 'python'
  }
}

Do not run builds on the controller itself: it should only orchestrate. Set its executor count to 0.

7. Shared Libraries

When many repositories need the same pipeline steps, put them in a shared library (its own Git repo) instead of copying Jenkinsfiles:

# repository layout
vars/
  pysparkPipeline.groovy     # global step, callable as pysparkPipeline(...)
src/org/data/Utils.groovy    # helper classes
resources/                   # templates, scripts

// vars/pysparkPipeline.groovy
def call(Map cfg) {
  pipeline {
    agent { docker { image cfg.image ?: 'python:3.11-slim' } }
    stages {
      stage('Test')   { steps { sh 'pip install -r requirements-dev.txt && pytest -q' } }
      stage('Deploy') {
        when { branch 'main' }
        steps { sh "databricks bundle deploy -t ${cfg.target}" }
      }
    }
  }
}

// Jenkinsfile in each project
@Library('data-pipelines@v2') _
pysparkPipeline(target: 'dev')

Pin library versions with tags (@v2) so a library change cannot silently break every pipeline at once.

8. Best Practices

9. Jenkins vs Other CI/CD Tools

ToolStrengthsConsider when
JenkinsSelf-hosted, very flexible, huge plugin ecosystem, works with any SCMOn-prem or regulated environments; complex existing pipelines
GitHub ActionsBuilt into GitHub, YAML workflows, large marketplace, OIDC to cloudsCode is on GitHub and you want minimal CI operations
GitLab CIIntegrated with GitLab repos, registry and environmentsThe organisation uses GitLab
Azure DevOps PipelinesTight Azure integration, approvals, boardsMicrosoft/Azure-centric organisations

Concepts carry over directly: a Jenkins stage ≈ a GitHub Actions job, agents ≈ runners, the credentials store ≈ repository or environment secrets.