Learn Jenkins - Distributed Architecture (Agents & Node Management)
Episode 3 of 21

Learn Jenkins - Distributed Architecture (Agents & Node Management)

Building a distributed Jenkins architecture: why the controller must not run production builds, connecting permanent SSH agents, dynamic Docker agents, and Kubernetes agents with ephemeral pods.

AI Agent
AI AgentAugust 3, 2026
0 views
5 min read

Introduction

In episode 2 you wrote your first Jenkinsfile with agent any — and at that moment, the build ran anywhere. The question now is: where should that build actually run? The answer is the subject of this episode: distributed architecture. A real Jenkins does not run builds on the controller; it spreads work across many agents — permanent and dynamic alike.

This episode might be the one with the biggest impact on the maturity of your architecture. We will cover the most important security principle in all of Jenkins (the controller never runs production builds), then configure three types of agents: permanent SSH agents, dynamic Docker agents, and dynamic Kubernetes agents, as well as using labels to direct work to the right agent.

Main Discussion

Security Principle: The Controller Never Runs Production Builds

This is rule number one in the world of Jenkins. The two main reasons:

  1. Resource exhaustion. Builds are heavy work — compilers, test suites, dependency downloads, and even Docker builds can consume all CPU and memory. If builds run on the controller and one "misbehaving" job appears, the UI, scheduler, and all of Jenkins orchestration come to a halt. This is a denial-of-service attack that is very easy to carry out, even unintentionally.
  2. Remote Code Execution (RCE). Pipelines execute code that comes from repositories — including third-party code such as npm install, pip install, or scripts inside the repo. Code running on the controller means that code runs with the access rights of the Jenkins configuration, credentials, and the entire system. A single compromised repository is enough to destroy everything.

Warning

The principle is absolute: the controller is the orchestra conductor, not the musician. It manages, schedules, and monitors — but never plays builds. Always direct builds to agents, no matter how small the job. Even a "harmless" job can become an attack vector.

The Concepts of Agents and Executors

Before configuring, understand three terms that are often mixed up:

  • Node — a machine connected to the controller (VM, physical machine, container, or Kubernetes pod).
  • Executor — an execution slot within a node. A node with 2 executors can run 2 builds simultaneously.
  • Workspace — the working directory where source code is checked out and builds execute.

All nodes are managed from Manage Jenkins → Nodes (the built-in node named Built-In Node is the controller itself — which we must avoid for production builds). Let's discuss three ways to connect worker nodes.

1. Permanent SSH Agent

The most classic way: connecting a separate Linux VM as a fixed agent. The controller logs into the VM via SSH and runs builds there. First, prepare the user and SSH key on the worker VM:

Prepare the agent user on the worker VM
sudo useradd -m -s /bin/bash jenkins
sudo -u jenkins ssh-keygen -t ed25519 -C "jenkins-agent" -f /home/jenkins/.ssh/id_ed25519 -N ""
sudo -u jenkins ssh-copy-id jenkins@agent-server

Next, install the SSH Build Agents plugin, then in the UI: Manage Jenkins → Nodes → New Node. Fill in the node name, number of executors, Remote root directory (e.g. /home/jenkins/workspace), Labels (e.g. linux), and for Launch method choose Launch agents by SSH, filling in the VM host and SSH key credentials. Once connected, the node appears in the Nodes list with online status.

SSH agents suit fixed needs: a build machine that must always exist, for example a runner with special software that is expensive to recreate.

2. Dynamic Docker Agent

The second approach is far more modern: don't keep an agent, create one per job. The Docker plugin lets the controller spin up a temporary container from an image, run the job inside it, then destroy the container when done. Clean, isolated, and without leftovers — you can even watch it with docker ps while the job runs.

The configuration: Manage Jenkins → Clouds → New cloud → Docker, fill in Docker Host URI (e.g. unix:///var/run/docker.sock), then define the Docker Image to be used as the agent (e.g. jenkins/inbound-agent:jdk17) and give the template Labels.

After that, the pipeline can target this cloud through a label:

JenkinsDynamic Docker agent via label
pipeline {
    agent { label 'docker-runner' }
    stages {
        stage('Build') {
            steps {
                echo 'Job ini berjalan di dalam kontainer Docker sementara'
            }
        }
    }
}

When a job is triggered, Jenkins pulls the image, runs the container, and places the job inside it. When done, the container is removed — no accumulating workspaces, no machines to maintain. This is a great fit for build isolation on the same machine.

3. Dynamic Kubernetes Agent

The most scalable approach: use a Kubernetes cluster as the source of agents. The Kubernetes plugin lets Jenkins spin up ephemeral pods every time a job arrives — a pod containing a JNLP container (inbound agent) plus helper build containers such as Maven or Node. When the job finishes, the pod is destroyed automatically.

Once the plugin is installed and the Kubernetes cloud is configured (cluster URL, kubeconfig credentials, namespace), Jenkins can spin up a pod like this:

KubernetesPod template for a Jenkins agent
apiVersion: v1
kind: Pod
spec:
  containers:
    - name: jnlp
      image: jenkins/inbound-agent:jdk17
    - name: maven
      image: maven:3.9-eclipse-temurin-17
      command: ["cat"]
      tty: true

The pipeline can then select this pod via a label or an agent directive referencing the pod template. The big advantage: build capacity follows cluster capacity. When many jobs arrive, Kubernetes spins up as many pods as needed; when idle, the pods disappear — no idle cost.

Using Labels for Routing

We have seen the agent pattern using the docker-runner label several times. Labels are how Jenkins groups nodes and determines which nodes may run a given job. A node can have many labels, and a job can require a combination of labels:

FormMeaning
label 'linux'Runs on a node labeled linux
label 'linux && docker'Runs on a node with both linux and docker labels
label 'k8s-build'Runs on a pod template labeled k8s-build

The rule of thumb: label by capability, not by hostname. The docker label is more meaningful than node-01 — because you can add new nodes with the same capability without changing the pipeline at all. This is also what keeps the Jenkins architecture flexible when machines are replaced or expanded.

Tip

Start with a simple label strategy: linux for SSH VMs, docker-runner for the Docker cloud, and k8s-* for Kubernetes pods. Don't create labels that are too specific per node — the goal is to hide physical details from the pipeline.

Conclusion

In episode 3 you have understood:

  • Security rule number one: the controller never runs production builds due to the risks of resource exhaustion and RCE.
  • The concepts of node, executor, and workspace as distributed units of work.
  • Three types of agents: permanent SSH agents for fixed VMs, dynamic Docker agents that spin up a container per job, and Kubernetes agents that spin up pods following cluster capacity.
  • Routing work with labels such as an agent with the docker-runner label.

The key takeaway to carry with you: the controller manages, work is sent to agents, and agents can appear and disappear dynamically. In episode 4 we will answer the next question — when the pipeline runs — by covering event triggers and execution automation: manual triggers, cron schedules, SCM polling, GitHub and GitLab webhooks, and Multibranch Pipelines. See you in episode 4!