Advanced Jenkins

Pipeline Structure and Scripted vs Declarative

Scripted Pipeline K8S Agent

In this lesson, you’ll learn how to run scripted Jenkins pipeline stages inside Kubernetes Pods using the Jenkins Kubernetes plugin’s podTemplate. We’ll compare a Declarative Pipeline on a static agent versus a Scripted Pipeline on a dynamic K8s agent, then walk through defining pod templates and share a full example.

Prerequisites

  • Jenkins server with the Kubernetes Plugin installed
  • Access to a Kubernetes cluster and a configured Kubernetes cloud in Jenkins
  • Credentials for any external services (e.g., MongoDB, Gitea) stored in Jenkins

Declarative Pipeline Example

Here’s a standard Declarative Pipeline bound to a static Jenkins agent:

pipeline {
  agent {
    node {
      label 'ubuntu-docker-jdk17-node20'
      environment {
        NODEJS_HOME        = "${tool 'nodejs-22-6-0'}"
        PATH               = "${env.NODEJS_HOME}/bin:${env.PATH}"
        MONGO_URI          = "mongodb+srv://supercluster.d83j"
        MONGO_DB_CREDS     = credentials('mongo-db-creds')
        MONGO_USERNAME     = credentials('mongo-db-user')
        MONGO_PASSWORD     = credentials('mongo-db-pass')
        SONAR_SCANNER_HOME = tool 'sonarqube-scanner'
        GITEA_TOKEN        = credentials('gitea-api-token')
      }
    }
  }
  properties {
    // repository properties
  }
  stages {
    stage('Installing Dependencies') {
      steps {
        sh 'npm install'
      }
    }
    stage('Dependency Scanning') {
      steps {
        sh 'npm audit'
      }
    }
    stage('Unit Testing') {
      steps {
        withCredentials([usernamePassword(credentialsId: 'credential')]) {
          sh 'node -v'
          sh 'npm test'
        }
      }
    }
  }
}
$ git checkout -b pipeline/scripted
Switched to a new branch 'pipeline/scripted'

To switch this Declarative Pipeline onto Kubernetes Pods, update the agent block:

pipeline {
  agent {
    kubernetes {
      cloud            'dasher-prod-k8s-us-east'
      yamlFile         'k8s-agent.yaml'
      defaultContainer 'node-18'
    }
  }
  environment {
    MONGO_URI        = "mongodb+srv://supercluster.d83jj.mongodb.net/super"
    MONGO_DB_CREDS   = credentials('mongo-db-credentials')
    MONGO_USERNAME   = credentials('mongo-db-username')
    MONGO_PASSWORD   = credentials('mongo-db-password')
    GITEA_TOKEN      = credentials('gitea-api-token')
  }
  // ...
}

Scripted Pipeline with podTemplate

For Scripted Pipelines, the podTemplate step defines how Jenkins spins up Pods. You have two main options:

  1. Define Pod Templates in the Jenkins UI
  2. Generate with the Snippet Generator

1. Defining Pod Templates in the Jenkins UI

Navigate to Manage Jenkins → Configure Clouds → dasher-prod-k8s-us-east and click Add Pod Template. Configure Name, Namespace, Labels, Usage, then add container templates:

The image shows a Jenkins dashboard under the "Clouds" section, listing a cloud named "dasher-prod-k8s-us-east" with an option to configure it.

The image shows a Jenkins interface for creating a new pod template, with fields for name, namespace, labels, usage, and other settings.

2. Using the Snippet Generator

Open Pipeline Syntax → Snippet Generator, choose podTemplate, then select your cloud and a unique label (e.g., nodejs-pod). Click Add Container Template:

The image shows a Jenkins interface with a "Snippet Generator" for creating pipeline scripts, featuring a dropdown menu with various options for execution steps.

Configure the pod label and usage:

The image shows a Jenkins pipeline configuration screen with options for node usage and pod template settings. It includes a label field set to "nodejs-pod" and a dropdown for usage selection.

Define the container details:

The image shows a Jenkins pipeline configuration screen, specifically a container template setup with fields for Docker image, working directory, and command to run.

Clean up the generated snippet to only include fields you need:

podTemplate(
  cloud:   'dasher-prod-k8s-us-east',
  label:   'nodejs-pod',
  containers: [
    containerTemplate(
      name:       'node-18',
      image:      'node:18-alpine',
      command:    'sleep',
      args:       '9999999',
      privileged: true,
      ttyEnabled: true
    )
  ]
) {
  // your scripted pipeline steps
}

Full Scripted Jenkinsfile Example

Below is a consolidated Scripted Pipeline that uses:

  • A static node for checkout and dependency install
  • A Kubernetes pod for isolated unit testing
  • stash/unstash for sharing artifacts
#!/usr/bin/env groovy

podTemplate(
  cloud:   'dasher-prod-k8s-us-east',
  label:   'nodejs-pod',
  containers: [
    containerTemplate(
      name:       'node-18',
      image:      'node:18-alpine',
      command:    'sleep',
      args:       '9999999',
      privileged: true,
      ttyEnabled: true
    )
  ]
) {
  // Static agent for checkout & install
  node('ubuntu-docker-jdk17-node20') {
    env.NODEJS_HOME = tool('nodejs-22-6-0')
    env.PATH        = "${env.NODEJS_HOME}/bin:${env.PATH}"
    env.MONGO_URI   = "mongodb+srv://supercluster.d83jj.mongodb.net/superData"

    stage('Checkout') {
      checkout scm
    }

    wrap([$class: 'TimestamperBuildWrapper']) {
      stage('Installing Dependencies') {
        cache(maxCacheSize: 550, caches: [
          arbitraryFileCache(
            cacheName:                 'npm-dependency-cache',
            cacheValidityDecidingFile: 'package-lock.json',
            includes:                  '**/*',
            path:                      'node_modules'
          )
        ]) {
          sh 'node -v'
          sh 'npm install --no-audit'
          stash includes: 'node_modules/', name: 'solar-system-node-modules'
        }
      }
    }
  }

  // Kubernetes Pod for unit testing
  stage('Unit Testing') {
    node('nodejs-pod') {
      container('node-18') {
        checkout scm
        unstash 'solar-system-node-modules'

        withCredentials([usernamePassword(
          credentialsId:    'mongo-db-credentials',
          usernameVariable: 'MONGO_USERNAME',
          passwordVariable: 'MONGO_PASSWORD'
        )]) {
          sh 'node -v'
          sh 'npm test'
        }
      }
    }
  }
}
$ git checkout -b pipeline/scripted
$ git commit -am "Use podTemplate for scripted pipeline"
$ git push origin pipeline/scripted

In Blue Ocean you’ll see the pipeline stages and Pod creation in action:

The image shows a Jenkins pipeline interface with multiple build stages, including "Checkout," "Installing Dependencies," and "Unit Testing." It also displays a build history with several builds listed, one of which is pending.

Under the hood, Jenkins spins up a Pod similar to:

apiVersion: "v1"
kind:       "Pod"
metadata:
  name:       "nodejs-pod-XXXXX"
  namespace:  "jenkins"
  labels:
    jenkins/label: "nodejs-pod"
spec:
  containers:
    - name:  "node-18"
      image: "node:18-alpine"
      command: ["sleep"]
      args:    ["9999999"]
      tty:     true
      securityContext:
        privileged: true
      volumeMounts:
        - mountPath: "/home/jenkins/agent"
          name:      "workspace-volume"

Once dependencies are unstashed, unit tests run inside the node-18 container:

+ node -v
v18.20.4
+ npm test
> Solar [email protected] test /home/jenkins/agent/workspace/solar-system
> mocha app-test.js --timeout 10000 --reporter mocha-junit-reporter --exit

  ✔ should retrieve the solar objects
  √ will handle missing data correctly

2 tests complete (xxxxms)

Pipeline Stage Summary

StageAgentTasks
Checkoutubuntu-docker-jdk17-node20SCM checkout
Installing Dependenciesubuntu-docker-jdk17-node20npm install, stash node_modules
Unit Testingnodejs-pod (container node-18)Unstash modules, run tests with credentials

By combining a static agent for caching and Kubernetes pods for isolated execution, you achieve a scalable, flexible Scripted Pipeline. Use podTemplate, node, container, and stash/unstash to coordinate across stages.

Watch Video

Watch video content

Practice Lab

Practice lab

Previous
Scripted Pipeline Static Agent