Skip to main content
This lesson shows how to run scripted Jenkins pipeline stages inside Kubernetes pods using the Jenkins Kubernetes plugin. Unlike declarative pipelines where an agent block often handles checkout and workspace for you, scripted pipelines require more explicit control: define pod templates, manage checkouts on each node, and transfer artifacts between agents with stash/unstash. You will learn:
  • How to define a Kubernetes pod via podTemplate and containerTemplate.
  • How to run some stages on a static Jenkins agent and other stages inside Kubernetes containers.
  • How to move installed dependencies (for example node_modules) between agents using stash/unstash.

Inline podTemplate example

Below is a pod template you can generate from Jenkins “Pipeline Syntax” and then simplify for use inside a Jenkinsfile. This example defines a pod with two Node.js container templates:
podTemplate(
  cloud: 'dasher-prod-k8s-us-east',
  label: 'nodejs-pod',
  containers: [
    containerTemplate(
      name: 'node-18',
      image: 'node:18-alpine',
      command: 'sleep',
      args: '9999999',
      ttyEnabled: true,
      privileged: true
    ),
    containerTemplate(
      name: 'node-19',
      image: 'node:19-alpine',
      command: 'sleep',
      args: '9999999',
      ttyEnabled: true,
      privileged: true
    )
  ]
) {
  // node(POD_LABEL) { ... } will be added by the pipeline below where needed
}
Explanation:
  • cloud selects the Kubernetes cloud configured in Jenkins.
  • label is the pod label that binds a Jenkins node(...) to this pod template.
  • Each containerTemplate becomes a container inside the created pod. Using sleep keeps the container alive while the Jenkins agent communicates with it.
You can also configure these pod templates at the cloud level in the Jenkins UI so they are reusable across pipelines:
A screenshot of the Jenkins web UI on the "Clouds" page showing one configured cloud named "dasher-prod-k8s-us-east" and a "+ New cloud" button. The page header and navigation are visible across the top.

Use the “Pipeline Syntax” generator

To produce the initial Groovy block, use Jenkins’ “Pipeline Syntax” generator. The form looks like this when creating a pod template for a cloud:
A dark-themed Jenkins Pipeline Syntax page showing a podTemplate configuration form with fields like "Cloud to use" (set to dasher-prod-k8s-us-east), Name, Namespace, Label (nodejs-pod), and usage/inheritance options. The browser window and several tabs are visible along the top.
When adding container templates in the UI, make sure to set fields such as image, command, args, and allocate a TTY if required:
A dark-themed screenshot of a Jenkins Pipeline Syntax / k8s cloud agent configuration page showing container settings. It shows fields like Docker image "node:18-alpine", command "sleep" with argument "9999999", and the "Allocate pseudo-TTY" checkbox checked.
The generator often emits a verbose, YAML-like Groovy snippet including probes and resource defaults. Trim it to the essentials: cloud, label, and containers with name, image, command, args, tty, and privileged flags as needed. For example:
podTemplate(
  cloud: 'dasher-prod-k8s-us-east',
  label: 'nodejs-pod',
  containers: [
    containerTemplate(
      name: 'node-18',
      image: 'node:18-alpine',
      command: 'sleep',
      args: '9999999',
      ttyEnabled: true,
      privileged: true
    )
  ]
) {
  // pipeline code that references node('nodejs-pod') and container('node-18') ...
}
Other pod-level settings (namespace, service account, volumes, workspace directory) can be configured at the cloud level or overridden inline:
A dark-themed screenshot of a web UI (Jenkins Pipeline Syntax / k8s cloud agent settings) showing various form fields. Visible fields include Supplemental Groups, time to retain agent when idle, Pod deadline, Service Account, Node Selector, Working directory (/home/jenkins/agent) and Workspace Volume.

Practical scripted Jenkinsfile pattern

This common pattern uses:
  • A static Jenkins agent (e.g., long-lived Ubuntu/Docker executor) to perform checkout and install dependencies (fast, cache-friendly).
  • stash on that agent to capture installed dependencies.
  • A Kubernetes pod/container to run unit tests after unstashing the artifacts and checkout scm on that node.
Full example Jenkinsfile (scripted pipeline):
// Jenkinsfile (scripted pipeline)
podTemplate(
  cloud: 'dasher-prod-k8s-us-east',
  label: 'nodejs-pod',
  containers: [
    containerTemplate(
      name: 'node-18',
      image: 'node:18-alpine',
      command: 'sleep',
      args: '9999999',
      ttyEnabled: true,
      privileged: true
    )
  ]
) {
  node('ubuntu-docker-jdk17-node20') { // static agent for heavy operations, checkout, caching
    // Tools and env setup on static node
    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"

    properties([])

    stage('Checkout') {
      checkout scm
    }

    wrap([$class: 'TimestamperBuildWrapper']) {
      stage('Installing Dependencies') {
        // Example cache wrapper (plugin-specific)
        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 node_modules to transfer to the k8s container later
          stash(includes: 'node_modules/**', name: 'solar-system-node-modules')
        }
      }
    }
  }

  // Run Unit Testing inside the Kubernetes pod/container
  stage('Unit Testing') {
    // node label must match the podTemplate label defined above
    node('nodejs-pod') {
      // select the container inside that pod
      container('node-18') {
        // In scripted pipelines you must explicitly checkout when switching nodes/pods
        checkout scm

        // restore the dependencies
        unstash 'solar-system-node-modules'

        // Run tests
        sh 'node -v'
        sh 'npm test'
      }
    }
  }
}
  • In scripted pipelines, switching to a different agent/node (for example from a static agent to a Kubernetes pod via node('label')) does not carry over the workspace or checked-out files. Always run checkout scm on the node where you will execute build/test commands, or use stash/unstash to transfer files between agents.
  • stash the produced artifacts on the producer agent (where you installed dependencies) and unstash them on the consumer agent (the Kubernetes container) to make tools and dependencies available where they are needed.

Common failure examples (and fixes)

  1. Missing repository files on the Kubernetes container (ENOENT: package.json).
    Cause: forgetting to checkout scm inside the k8s node(...) block. Failing log example:
+ node -v
v18.20.4

+ npm test
npm ERR! code ENOENT
npm ERR! syscall open
npm ERR! path /home/jenkins/agent/workspace/n_solar-system_pipeline_scripted/package.json
npm ERR! errno -2
npm ERR! enoent Could not read package.json Error: ENOENT: no such file or directory, open '/home/jenkins/agent/workspace/n_solar-system_pipeline_scripted/package.json'
npm ERR! enoent This is related to npm not being able to find a file.
Fix: run checkout scm on the same node/container where you invoke npm test.
  1. Missing dev/test tools (e.g., mocha: not found).
    Cause: dependencies were installed on a different agent and not transferred. Symptom: sh: mocha: not found.
    Fix: stash node_modules on the installing agent and unstash on the test agent, or install dependencies inside the test container.
Be mindful of stash size and limits: stashing large directories (e.g., entire build artifacts) may increase build time and storage use. Prefer caching plugins or artifact repositories for large dependencies. Also ensure workspace paths and ownership are compatible across agents (uid/gid differences can affect file access).
After adding checkout scm and unstash to the unit testing stage, the pipeline should successfully provision pods and run tests. Monitor pod provisioning, logs, and step output in the Jenkins UI (Blue Ocean or classic UI):
A Jenkins web dashboard showing the "Gitea-Organization / solar-system" pipeline activity with a table of recent builds (status, run number, commit, branch, message, duration, and completion time). The list shows green, red, and in-progress builds for branches like pipeline/scripted and feature/advanced-demo.
When the pod is provisioned, Jenkins prints the generated Pod YAML and container details in the agent logs. Example snippet you may see in the console output:
Created Pod: dasher-prod-k8s-us-east jenkins/nodejs-pod-3tll4-11lvm
Agent nodejs-pod-3tll4-11lvm is provisioned from template nodejs-pod-3tll4
---
apiVersion: "v1"
kind: "Pod"
metadata:
  name: "nodejs-pod-3tll4-11lvm"
  namespace: "jenkins"
spec:
  containers:
  - name: "node-19"
    image: "node:19-alpine"
    command: ["sleep"]
    args: ["9999999"]
    tty: true
    securityContext:
      privileged: true
    volumeMounts:
    - mountPath: "/home/jenkins/agent"
      name: "workspace-volume"
  - name: "node-18"
    image: "node:18-alpine"
    command: ["sleep"]
    args: ["9999999"]
    tty: true
    securityContext:
      privileged: true
    volumeMounts:
    - mountPath: "/home/jenkins/agent"
      name: "workspace-volume"
  serviceAccount: "agent"
  volumes:
  - emptyDir: {}
    name: "workspace-volume"

Quick reference table

FieldPurposeExample
cloudKubernetes cloud configured in Jenkinsdasher-prod-k8s-us-east
labelNode label used by node('label')nodejs-pod
containerTemplate.nameContainer identifier inside the podnode-18
containerTemplate.imageDocker image for the containernode:18-alpine
command / argsCommand to keep container alive for the agentsleep / 9999999
ttyEnabledAllocate pseudo-TTY for interactive runstrue
stash / unstashTransfer files between agentsstash(includes: 'node_modules/**', name: 'deps')

Summary

  • Use podTemplate and containerTemplate to define Kubernetes pods and containers for scripted pipelines.
  • Reference the pod via node('label') and execute inside a container with container('name').
  • Always checkout scm or use stash/unstash when switching between different agents or pods.
  • Define pod templates either inline in the Jenkinsfile (good for one-off pipelines) or in the Jenkins UI/cloud level (recommended for reuse).

Watch Video