Ravindra BagaleCourses & study guides मराठी

Chapter 23: Jenkins Fundamentals, Install and Architecture

23.3 Controller and agents

Why: the problem

Think of Flipkart before the Big Billion Days sale. Hundreds of builds run at the same time: Java services, React apps, Android apps, Docker images. If every build runs on one Jenkins machine, that machine gets slow. One heavy Android build fills the disk and every other team waits. Worse, every build runs with the same rights as Jenkins itself, so one bad script can read Jenkins secrets. This is why Jenkins has two kinds of machines. The controller is the brain. It shows the web page, stores jobs and decides what runs where. Agents are the hands. They run the actual build steps. You can add a Linux agent for Java, a Windows agent for .NET, a Mac for iOS, or short-lived Docker containers. In this lesson you will add a real agent, give it labels, and move all builds off the controller.

What we will build

You will start a second container that acts as an SSH agent. You will add an SSH key credential, connect the agent from the controller, and give it the label linux-docker. Then you will set the controller executors to 0, so nothing runs on the brain. Finally you will use label-based agents and per-stage Docker agents in a Jenkinsfile.

What: every term in plain English

  • Controller — The main Jenkins server. Web page, job settings, scheduling, credentials. It should not run builds.
  • Agent — A machine that connects to the controller and runs build steps. Old name: slave or node.
  • Node — Jenkins word for any machine that can run builds, including the controller.
  • Executor — A slot for one build on a node. 2 executors means 2 builds at once.
  • Label — A tag on an agent like linux, docker or windows. Jobs ask for a label, not a machine name.
  • SSH agent — The controller logs in to the agent over SSH and starts the agent program.
  • Inbound agent — The agent connects to the controller itself, on port 50000 or over WebSocket. Good when the agent is behind a firewall.
  • Workspace — The folder on the agent where a build checks out code and runs.
Make an SSH key pair for agents Start an agent container Save the private key in Jenkins Add the node Fill node settings Stop builds on the controller Run a job on the label
Controller schedules, agents build, top to bottom

How: step by step

  1. Make an SSH key pair for agents

    ssh-keygen -t ed25519 -f ~/.ssh/jenkins_agent -N "" -C jenkins-agent
    

    What it does: The private key goes into Jenkins. The public key goes onto the agent.

    Output

    Your identification has been saved in /home/ravi/.ssh/jenkins_agent
    
  2. Start an agent container

    docker network create jenkins-net; docker network connect jenkins-net jenkins; docker run -d --name agent1 --network jenkins-net -e "JENKINS_AGENT_SSH_PUBKEY=$(cat ~/.ssh/jenkins_agent.pub)" jenkins/ssh-agent:latest-jdk17
    

    What it does: A ready agent image with Java and sshd. It trusts our public key.

    Output

    9b8c7d6e5f4a...
    
  3. Save the private key in Jenkins

    Manage Jenkins > Credentials > Global > Add > SSH Username with private key > ID agent-ssh > Username jenkins > paste ~/.ssh/jenkins_agent
    

    What it does: Jenkins uses it to log in to agents.

    Output

    Credential agent-ssh created
    
  4. Add the node

    Manage Jenkins > Nodes > New Node > agent1 > Permanent Agent
    

    What it does: Creates the node entry.

    Output

    Saved
    
  5. Fill node settings

    Executors 2 > Remote root /home/jenkins/agent > Labels linux-docker > Launch via SSH > Host agent1 > Credentials agent-ssh > Host Key Verification: Manually trusted
    

    What it does: Tells Jenkins how to reach and use the agent.

    Output

    Agent successfully connected and online
    
  6. Stop builds on the controller

    Manage Jenkins > Nodes > Built-In Node > Configure > Number of executors 0
    

    What it does: The controller only schedules now.

    Output

    Built-In Node: 0 executors
    
  7. Run a job on the label

    In a Jenkinsfile use agent { label "linux-docker" }
    

    What it does: The build goes to agent1.

    Output

    Running on agent1 in /home/jenkins/agent/workspace/...
    

Example 1: Pin a pipeline to a label and prove where each step runs

Stack. Jenkins controller + jenkins/ssh-agent

Goal. Pin a pipeline to a label and prove where each step runs.

Jenkinsfile

pipeline {
  agent { label 'linux-docker' }
  stages {
    stage('Where am I') {
      steps {
        sh 'echo "Node: $NODE_NAME"'
        sh 'echo "Workspace: $WORKSPACE"'
        sh 'hostname && whoami && nproc && free -m | head -2'
      }
    }
  }
}

What each line does

  • agent { label 'linux-docker' } — Run only on nodes with this label. Any agent with the label can be picked.
  • $NODE_NAME — The Jenkins name of the node that runs the build.
  • $WORKSPACE — The folder where the build runs on that node.
  • whoami — The Linux user that runs builds. On this image it is jenkins, not root.
  • nproc / free -m — CPU count and memory. Useful to size agents.

Green output

Running on agent1 in /home/jenkins/agent/workspace/where-am-i
+ echo Node: agent1
Node: agent1
+ echo Workspace: /home/jenkins/agent/workspace/where-am-i
+ hostname
9b8c7d6e5f4a
+ whoami
jenkins
+ nproc
4
               total        used        free
Mem:            7954        2130        3011
Finished: SUCCESS

Expected result. The log says Running on agent1, not on the built-in node. The controller did no build work.

Example 2: Use a different Docker image for each stage

Stack. Jenkins, Docker Pipeline plugin, Maven, Node

Goal. Use a different Docker image for each stage.

Jenkinsfile

pipeline {
  agent none
  stages {
    stage('Backend test') {
      agent { docker { image 'maven:3.9-eclipse-temurin-17'; label 'linux-docker'; args '-v maven-repo:/root/.m2' } }
      steps { sh 'mvn -v && mvn -B -q test' }
    }
    stage('Frontend test') {
      agent { docker { image 'node:20-alpine'; label 'linux-docker' } }
      steps { sh 'node -v && npm ci && npm test' }
    }
  }
}

What each line does

  • agent none — No agent for the whole pipeline. Each stage picks its own.
  • image 'maven:3.9-eclipse-temurin-17' — This stage runs inside a Maven container. No Java install on the agent needed.
  • label 'linux-docker' — Start the container on an agent with this label. That agent needs Docker.
  • args '-v maven-repo:/root/.m2' — Keeps downloaded Maven jars in a volume, so the next build is faster.
  • mvn -B -q test — Batch mode, quiet output, run unit tests.
  • image 'node:20-alpine' — The frontend stage uses a small Node image.

Green output

[Pipeline] stage (Backend test)
Running on agent1 in /home/jenkins/agent/workspace/shop
+ docker pull maven:3.9-eclipse-temurin-17
+ mvn -v
Apache Maven 3.9.9
[INFO] Tests run: 12, Failures: 0, Errors: 0, Skipped: 0
[Pipeline] stage (Frontend test)
+ node -v
v20.17.0
Tests: 8 passed, 8 total
Finished: SUCCESS

Expected result. Each stage used the right tools without installing them on the agent. For this, the agent must have Docker; the plain ssh-agent image does not, so use a VM agent with Docker installed or mount the Docker socket in a lab only.

Example 3: Connect an inbound agent from a machine behind a firewall

Stack. Inbound agent over WebSocket, Java 17

Goal. Connect an inbound agent from a machine behind a firewall.

agent-run.sh (on the agent machine)

#!/usr/bin/env bash
# Run on the build machine. The controller cannot reach it, but it can reach the controller.
set -euo pipefail
JENKINS_URL="https://jenkins.shop-lab.in"
AGENT_NAME="win-or-lan-01"
SECRET_FILE="$HOME/.jenkins-agent-secret"
mkdir -p "$HOME/agent"
curl -fsSLO "$JENKINS_URL/jnlpJars/agent.jar"
java -jar agent.jar -url "$JENKINS_URL/" -name "$AGENT_NAME" \
  -secret @"$SECRET_FILE" -webSocket -workDir "$HOME/agent"

What each line does

  • Inbound agent — Create the node with Launch method: Launch agent by connecting it to the controller.
  • agent.jar — The small agent program. The controller serves it at /jnlpJars/agent.jar.
  • -secret @file — Reads the node secret from a file, so it is not in shell history. Copy the secret from the node page once.
  • -webSocket — Connects over normal HTTPS port 443. No need to open port 50000.
  • -workDir — Where the agent keeps logs and workspaces.
  • mkdir -p — Creates the folder if it is missing.

Green output

INFO: Using Remoting version: 3261.v9c670a_4748a_9
INFO: Locating server among [https://jenkins.shop-lab.in/]
INFO: WebSocket connection open
INFO: Connected

Expected result. The node page turns from red cross to online. This is how office machines, Mac minis for iOS builds, or agents in a private network connect.

Verify: did it work?

  1. List nodes and status

    curl -s -u ravi:$JENKINS_TOKEN "http://localhost:8080/computer/api/json?tree=computer[displayName,offline,numExecutors]"
    

    What it does: Shows each node, if it is offline, and its executors.

    Output

    {"computer":[{"displayName":"Built-In Node","numExecutors":0,"offline":false},{"displayName":"agent1","numExecutors":2,"offline":false}]}
    
  2. Check the agent log

    Manage Jenkins > Nodes > agent1 > Log
    

    What it does: Shows the SSH connect steps.

    Output

    [SSH] Authentication successful.
    Agent successfully connected and online
    

When it is red 1

[SSH] Authentication failed.
Authentication failed.

Cause. The public key on the agent does not match the private key in Jenkins, or the username is wrong.

Fix, step by step

  1. Check the username is jenkins.
  2. Check JENKINS_AGENT_SSH_PUBKEY has the .pub key, not the private key.
  3. Recreate the agent container with the right key.

When it is red 2

Still waiting to schedule task
There are no nodes with the label linux-docker

Cause. No online agent has that label, or all executors are busy.

Fix, step by step

  1. Check the label spelling on the node.
  2. Check the agent is online.
  3. Add executors or another agent.

When it is red 3

java.io.IOException: Unexpected termination of the channel

Cause. The agent lost connection, often because it ran out of memory or the network dropped.

Fix, step by step

  1. Check free -m and dmesg on the agent.
  2. Give the agent more RAM or fewer executors.
  3. Reconnect the node.

Cleanup

  1. Remove the lab agent

    docker rm -f agent1
    

    What it does: The node shows offline; delete it in Manage Jenkins > Nodes if you do not need it.

    Output

    agent1
    

Ravindra Bagale's Tip

Controller mhanje mendu, agent mhanje haat. Controller var executor 0 theva. Label vaprun kaam pathva. Lakshat theva!

Practice tasks

Easy Count executors

Why: Executors decide how many builds run at once.

What to do: Start three builds at once with two executors.

How:
  1. Click Build Now three times fast.
  2. Watch Build Queue.

Check: Two run, one waits.

Medium Add a second label

Why: Labels let jobs ask for tools, not machine names.

What to do: Add the label maven to agent1 and use it.

How:
  1. Edit node labels.
  2. Change the Jenkinsfile.

Check: The build runs on agent1.

Hard Add cloud agents

Why: Fixed agents cost money when idle.

What to do: Install the Docker or Amazon EC2 plugin and make agents start on demand.

How:
  1. Configure a cloud.
  2. Run a job with that label.

Check: An agent starts, builds, and goes away.

Easy Say controller and agents in two lines

Why: If you can say it simply, you understand it. Juniors and interviewers want the short version first.

What to do: Write two short lines about controller and agents for a fresher who knows only Linux basics.

How:
  1. Write what problem it solves.
  2. Write the one command or menu you use for it.
  3. Read it aloud to a friend.

Check: A fresher understands it without asking a question.

Easy Start a fresh lab Jenkins

Why: Practice needs a throwaway Jenkins. If you break it, you delete it and start again.

What to do: Run Jenkins LTS in Docker with a named volume.

How:
  1. docker volume create jenkins_home
  2. docker run -d --name jenkins -p 8080:8080 -v jenkins_home:/var/jenkins_home jenkins/jenkins:lts-jdk17
  3. docker exec jenkins cat /var/jenkins_home/secrets/initialAdminPassword

Check: The Jenkins unlock page opens on localhost:8080.

Medium Break it on purpose

Why: You must know the red message by face. During an outage there is no time to read slowly.

What to do: Cause one error from the "When it is red" part of this lesson and fix it.

How:
  1. Follow the error section.
  2. Copy the exact message into your notes.
  3. Write the fix in one line.

Check: You fixed it using only the steps, without searching the web.

Medium Write a one-page runbook

Why: At 2 a.m. nobody remembers where a file lives. A short page saves the on-call person.

What to do: Write a runbook page for this lesson.

How:
  1. Title, when to use, exact command, how to check, how to undo.

Check: A teammate can follow it alone.

Medium Repeat it on a cloud VM

Why: A laptop is not a server. Real Jenkins runs on EC2 or a company VM.

What to do: Do the main steps of this lesson again on a small Ubuntu 22.04 EC2 instance.

How:
  1. Launch t3.small with 20 GB disk.
  2. Open port 22 only to your IP.
  3. Repeat the steps and compare the output.

Check: Same green output on the VM as on your laptop.

Hard Explain it like an interview

Why: Interviewers want real stories, not definitions.

What to do: Record a 60 second answer about this lesson.

How:
  1. Say the problem, the command you ran, and one error you hit.

Check: Your answer has a real command and a real error message.

Hard Draw the flow top to bottom

Why: A drawing shows who talks to whom and in what order.

What to do: Draw this lesson as boxes from top to bottom.

How:
  1. Start at the developer push, go through the controller and agent, end at the result.

Check: Each box matches a real thing you saw on screen.

Homework: try at home

Try at home

At home, create two agents with labels java and node. Write a Jenkinsfile with agent none where the Build stage runs on java and the UI stage runs on node. Check Console Output to prove where each stage ran.

Recap

  • The controller is the brain; agents do the work.
  • Set controller executors to 0.
  • Jobs ask for labels, not machine names.
  • SSH agents are started by the controller; inbound agents connect to it.
  • Per-stage Docker agents give each stage its own tools.

FAQ

Is "slave" still used?

No. Jenkins renamed it to agent in 2016. You still see it in old blogs.

How many executors per agent?

Start with one per CPU core, then tune by watching load.

Can the controller and agent be the same machine?

In a tiny lab yes. In a team, never.

Do agents need Jenkins installed?

No. Only Java and the small agent.jar.

Which port do inbound agents use?

TCP 50000, or 443 if you use WebSocket.

Interview questions

  1. Explain the Jenkins controller-agent architecture.

    The controller holds configuration and schedules builds. Agents connect to it and run build steps in their workspaces. This spreads load and isolates builds from the controller.

  2. Why should builds not run on the controller?

    Builds can run any code. On the controller they could read JENKINS_HOME secrets and slow down the UI.

  3. What are labels used for?

    To route jobs to agents with the right tools or OS, like linux, docker or windows.

  4. SSH versus inbound agents?

    SSH: controller connects to the agent. Inbound: agent connects to the controller, good behind firewalls.

  5. How do you scale Jenkins agents?

    Add static agents, or use cloud plugins (EC2, Kubernetes, Docker) to create agents on demand.

Quick quiz

Q1. What does the controller do?

Shows the UI, stores jobs and credentials, and schedules builds.

Q2. Why set controller executors to 0?

For security and speed: builds should not run on the machine holding all secrets.

Q3. What is an executor?

A slot for one build at a time on a node.

Q4. When do you use an inbound agent?

When the controller cannot reach the agent, but the agent can reach the controller.

Q5. What does agent none mean?

Each stage chooses its own agent.

Samajla ka?

Ravi Sir's Cards for this lesson

मराठी cards