TL;DR

Prefer declarative pipelines in a Jenkinsfile at the repo root. Use the Kubernetes plugin to run each build in an ephemeral Pod, store all secrets as Jenkins credentials (never in code), and use shared libraries for reusable pipeline logic across repos.

Declarative Pipeline

A declarative Jenkinsfile using the Kubernetes agent — the build runs inside a Pod with a Docker-in-Docker sidecar for image builds. Each stage maps to a phase of the CI workflow.

groovyJenkinsfile
pipeline {
  agent {
    kubernetes {
      yaml """
apiVersion: v1
kind: Pod
spec:
  containers:
  - name: build
    image: python:3.12
    command: [cat]
    tty: true
  - name: docker
    image: docker:24-dind
    securityContext:
      privileged: true
    env:
    - name: DOCKER_TLS_CERTDIR
      value: ""
"""
    }
  }

  environment {
    REGISTRY     = 'myregistry.io'
    IMAGE_NAME   = 'myapp'
    IMAGE_TAG    = "${env.GIT_COMMIT[0..7]}"
    FULL_IMAGE   = "${REGISTRY}/${IMAGE_NAME}:${IMAGE_TAG}"
  }

  stages {
    stage('Test') {
      steps {
        container('build') {
          sh 'pip install -r requirements.txt && pytest tests/ -v'
        }
      }
    }

    stage('Build & Push') {
      when { branch 'main' }
      steps {
        container('docker') {
          withCredentials([usernamePassword(
            credentialsId: 'registry-creds',
            usernameVariable: 'DOCKER_USER',
            passwordVariable: 'DOCKER_PASS'
          )]) {
            sh '''
              docker login -u $DOCKER_USER -p $DOCKER_PASS $REGISTRY
              docker build -t $FULL_IMAGE .
              docker push $FULL_IMAGE
            '''
          }
        }
      }
    }

    stage('Deploy') {
      when { branch 'main' }
      steps {
        container('build') {
          withCredentials([file(credentialsId: 'kubeconfig', variable: 'KUBECONFIG')]) {
            sh '''
              kubectl set image deployment/myapp myapp=$FULL_IMAGE -n staging
              kubectl rollout status deployment/myapp -n staging --timeout=5m
            '''
          }
        }
      }
    }
  }

  post {
    failure {
      slackSend(channel: '#alerts', message: "Build FAILED: ${env.JOB_NAME} #${env.BUILD_NUMBER}")
    }
    success {
      slackSend(channel: '#deployments', message: "Deployed ${FULL_IMAGE} to staging")
    }
  }
}

Credentials Management

Always bind secrets using withCredentials — this injects them as environment variables only within the block and masks their values in console output. Never hardcode secrets in the Jenkinsfile.

groovycredentials.groovy
// Username + Password (docker, npm, etc.)
withCredentials([usernamePassword(
  credentialsId: 'my-docker-creds',
  usernameVariable: 'USER',
  passwordVariable: 'PASS'
)]) {
  sh 'docker login -u $USER -p $PASS'
}

// Secret text (API key, token)
withCredentials([string(credentialsId: 'slack-token', variable: 'SLACK_TOKEN')]) {
  sh 'curl -H "Authorization: Bearer $SLACK_TOKEN" ...'
}

// File (kubeconfig, JSON key)
withCredentials([file(credentialsId: 'kubeconfig-prod', variable: 'KUBECONFIG')]) {
  sh 'kubectl get nodes'
}

// SSH key
withCredentials([sshUserPrivateKey(
  credentialsId: 'deploy-key',
  keyFileVariable: 'SSH_KEY',
  usernameVariable: 'SSH_USER'
)]) {
  sh 'ssh -i $SSH_KEY $SSH_USER@server "deploy.sh"'
}

Shared Libraries

A shared library lets you DRY up pipeline code across repositories by defining reusable Groovy functions in a central repo. Configure the library in Manage Jenkins → System → Global Pipeline Libraries.

groovyvars/dockerBuild.groovy (in shared-lib repo)
// vars/dockerBuild.groovy — callable as dockerBuild(image: 'myapp', tag: env.GIT_COMMIT)
def call(Map args) {
  def image = args.image
  def tag   = args.tag ?: env.GIT_COMMIT[0..7]
  withCredentials([usernamePassword(
    credentialsId: 'registry-creds',
    usernameVariable: 'DOCKER_USER',
    passwordVariable: 'DOCKER_PASS'
  )]) {
    sh """
      docker login -u \$DOCKER_USER -p \$DOCKER_PASS myregistry.io
      docker build -t myregistry.io/${image}:${tag} .
      docker push myregistry.io/${image}:${tag}
    """
  }
}

// Usage in Jenkinsfile:
// @Library('my-shared-lib') _
// dockerBuild(image: 'myapp', tag: env.GIT_COMMIT)

Operational Commands

Use the Jenkins CLI or REST API for programmatic pipeline management — useful for bulk job operations, triggering builds from scripts, and exporting pipeline definitions.

bashjenkins-ops.sh
JENKINS=https://jenkins.example.com
TOKEN="user:api-token"

# Trigger a build
curl -X POST "$JENKINS/job/my-pipeline/build" --user "$TOKEN"

# Trigger with parameters
curl -X POST "$JENKINS/job/my-pipeline/buildWithParameters" \
  --user "$TOKEN" \
  --data "BRANCH=main&ENV=staging"

# Get last build status
curl -s "$JENKINS/job/my-pipeline/lastBuild/api/json" \
  --user "$TOKEN" | jq '{result, url, duration}'

# Restart Jenkins safely (after draining builds)
curl -X POST "$JENKINS/quietDown" --user "$TOKEN"
curl -X POST "$JENKINS/restart" --user "$TOKEN"

# Install jenkins-cli.jar for scripted ops
curl -s "$JENKINS/jnlpJars/jenkins-cli.jar" -o jenkins-cli.jar
java -jar jenkins-cli.jar -s $JENKINS -auth $TOKEN list-jobs
java -jar jenkins-cli.jar -s $JENKINS -auth $TOKEN get-job my-pipeline > job.xml