Jenkins agents can be instructed to shut themselves down from within a pipeline, but it’s not as simple as just calling a shutdown command.

Let’s see this in action. Imagine you have a pipeline that needs to spin up a temporary agent, run some tests, and then cleanly shut down that agent to save costs.

pipeline {
    agent any
    stages {
        stage('Provision and Test') {
            agent {
                kubernetes {
                    label 'my-ephemeral-pod'
                    yaml """
apiVersion: v1
kind: Pod
spec:
  containers:
  - name: jenkins-agent
    image: jenkins/inbound-agent:latest
    command: ['/bin/agent', '--url', 'http://jenkins.example.com', '--tunnel', 'jenkins.example.com:50000', '--credentials', 'jenkins-agent-credentials', '--work-dir', '/home/jenkins/agent']
    resources:
      requests:
        memory: "256Mi"
        cpu: "100m"
      limits:
        memory: "512Mi"
        cpu: "200m"
"""
                }
            }
            steps {
                script {
                    // Agent is now running and connected to Jenkins
                    echo "Agent is ready. Running tests..."
                    // Simulate some work
                    sleep 60
                    echo "Tests complete. Initiating agent shutdown."
                    // How do we tell this pod to shut down?
                }
            }
        }
    }
}

The problem here is how to signal the specific agent pod provisioned by the Kubernetes agent plugin to terminate. It’s not a direct command you run on the agent itself in the traditional sense. Instead, Jenkins manages the lifecycle of these ephemeral agents.

Here’s how you actually achieve it, broken down by the common ways Jenkins manages agents:

1. Kubernetes Pod Agents (as in the example above):

  • Diagnosis: The Kubernetes plugin creates and manages the lifecycle of pods. To shut down an agent pod, you don’t execute a command inside the pod; you instruct the Jenkins controller to delete the pod.
  • Cause: The agent is provisioned as a Kubernetes Pod. Its existence is managed by the Kubernetes API.
  • Command/Check: You can’t directly kubectl delete pod <pod-name> from within the pipeline script that’s running on that pod, as it would likely fail due to permissions or race conditions. Instead, the pipeline needs to interact with the Jenkins controller, which then interacts with Kubernetes.
  • Fix: Use the podTemplate configuration in your Jenkinsfile and agent { kubernetes { ... } } block. To terminate it, the pipeline should exit gracefully. When the pipeline finishes its stages and the agent block scope ends, the Jenkins controller will automatically delete the associated Kubernetes pod if it was provisioned for that specific pipeline run. If you need to force an early shutdown, you can do so by cancelling the build from the Jenkins UI. The plugin is designed to clean up resources when the build is no longer active.
  • Why it works: The Kubernetes plugin tracks the pods it creates for ephemeral agents. When a build using such an agent completes or is cancelled, the plugin’s cleanup logic triggers the deletion of the corresponding pod via the Kubernetes API.

2. Docker Agents (via Docker Pipeline plugin):

  • Diagnosis: When using agent { docker { ... } }, Jenkins starts a Docker container. To stop it, you need to tell Jenkins to stop the container it launched.
  • Cause: The agent is a Docker container managed by the Docker Pipeline plugin.
  • Command/Check: You can use the docker.image('your-image').inside { ... } syntax. When the inside block finishes, the container is automatically stopped and removed by the plugin.
  • Fix: Structure your pipeline stages within the docker.image('your-image').inside { ... } block.
    stage('Run in Docker') {
        agent {
            docker {
                image 'maven:3.8.5-openjdk-11'
                args '-v /var/run/docker.sock:/var/run/docker.sock'
            }
        }
        steps {
            sh 'echo "Running inside Docker container"'
            sh 'mvn --version'
        }
    }
    
    When this stage completes, the container is automatically stopped.
  • Why it works: The Docker Pipeline plugin manages the lifecycle of containers it launches for pipeline stages. Upon completion of the inside block, the plugin executes docker stop and docker rm on the container it created.

3. JNLP Agents (Classic, "Swarm" agents):

  • Diagnosis: These are agents that connect to Jenkins using the JNLP protocol. They are typically long-running processes. Shutting them down from a pipeline requires a specific mechanism.
  • Cause: The agent is a dedicated Jenkins agent process (often a slave.jar or agent.jar) that connects to the Jenkins controller.
  • Command/Check: You can use the Jenkins global configuration to label nodes and check their status. To shut down a specific JNLP agent programmatically, you often need to execute a command on the Jenkins controller that targets the agent.
  • Fix: The most reliable way is to use the Jenkins API or a plugin that exposes agent management functions. A common method involves using the Jenkins CLI or Groovy scripts executed on the controller. For example, you could have a pipeline on a different agent execute a Groovy script:
    // On a different agent or controller:
    Jenkins.instance.getNode('my-jnlp-agent-name').terminate()
    
    Or, if the JNLP agent has access to jenkins-cli.jar:
    java -jar jenkins-cli.jar -s http://jenkins.example.com/ -auth YOUR_USER:YOUR_API_TOKEN delete-node my-jnlp-agent-name
    
    Note: terminate() is for shutting down the agent process itself, delete-node removes it from Jenkins configuration.
  • Why it works: Jenkins holds a reference to connected agents. The terminate() method on a Node object signals the agent process to shut down its connection and exit. delete-node removes the agent’s configuration from Jenkins.

4. SSH Agents (via SSH Agent plugin):

  • Diagnosis: Similar to JNLP agents, these are typically long-running processes.
  • Cause: The agent is a remote machine that Jenkins connects to via SSH to execute builds.
  • Command/Check: The SSH Agent plugin typically uses ssh commands to execute steps. Shutting down the remote machine from within a pipeline running on that machine is usually not feasible or advisable due to permissions and the risk of cutting off the connection.
  • Fix: Similar to JNLP agents, you’d typically manage the lifecycle of the remote machine externally or via a separate administrative pipeline. If you must shut down the remote machine from a pipeline running on it, you would need to ensure the SSH user Jenkins uses has sufficient privileges to execute a shutdown command (e.g., sudo shutdown -h now). This is highly discouraged for security and reliability reasons. A better approach is to use ephemeral SSH agents (e.g., provisioned by Terraform/Ansible and then deleted) or use Kubernetes/Docker agents.
  • Why it works: If the SSH user has privileges, the shutdown command directly instructs the operating system on the remote machine to halt.

5. Cloud Provisioned Agents (EC2, etc.):

  • Diagnosis: Agents launched by cloud plugins (like EC2) are virtual machines.
  • Cause: The agent is an instance in a cloud provider (AWS, Azure, GCP) managed by a Jenkins plugin.
  • Command/Check: The plugin automatically terminates the instance when the build is done. If you need to trigger it early, cancelling the build from the Jenkins UI is the standard way.
  • Fix: Ensure your cloud agent configuration is set up correctly to allow automatic termination. When a build using a dynamically provisioned cloud agent finishes, the plugin’s cleanup routine will signal the cloud provider to terminate the instance.
  • Why it works: The cloud plugins are designed to provision and de-provision resources. They track the instances they launch and, upon build completion or cancellation, use the cloud provider’s API to terminate them.

The next thing you’ll likely run into is managing credentials for these dynamic agent provisioning and cleanup operations.

Want structured learning?

Take the full Jenkins course →