Learn how to connect a second AWS EC2 instance as a Jenkins agent, run pipelines in parallel, and keep your Jenkins controller fast.

tags: aws, jenkins, devops, cicd

When I first set up Jenkins on an AWS EC2 instance, everything ran on that one server: pulling code, building Docker images, running tests, and deploying. It worked for small labs, but as soon as I ran two or three jobs together, the server became slow and builds started waiting in the queue.

The fix is simple and very common in real DevOps teams: use Jenkins agents. In this article I explain what agents are, why they help, and how to connect a second EC2 instance as a Jenkins agent step by step.

What is a Jenkins Controller and an Agent?

Jenkins has two types of machines:

  • Controller (formerly "master"): the main Jenkins server. It hosts the web UI, stores job configuration, manages credentials, and schedules builds.
  • Agent (formerly "slave"): a separate machine that actually runs the build steps. The controller sends work to it.

Simple way to remember it: the controller is the manager who assigns tasks, and the agents are the workers who do them.

Why Use Agents? (The Problem with a Single Server)

Problem on a single Jenkins server How agents solve it
Builds queue up when many jobs run together Jobs run in parallel on different agents
Heavy builds (Docker, tests) slow down the Jenkins UI The controller stays light and responsive
One server holds all tools (Java, Docker, Node, Maven) Each agent can have its own tools
A broken build can affect the Jenkins server itself Builds are isolated on separate machines
Hard to scale Add more EC2 agents when you need more capacity

A good practice is to run zero or very few builds on the controller and let agents do the heavy work.

Architecture

 GitHub (code) | v +-----------------------+ | Jenkins Controller | EC2 #1 (port 8080) | (UI, jobs, schedule) | +-----------------------+ | | SSH SSH v v +--------------+ +--------------+ | Agent EC2 #2 | | Agent EC2 #3 | | label: docker| | label: test | +--------------+ +--------------+ 

The controller connects to each agent over SSH (port 22) and runs the build steps there.

Prerequisites

  • A running Jenkins controller on an EC2 instance (http://<Controller-IP>:8080)
  • A second EC2 instance for the agent (Amazon Linux 2023 or Ubuntu, t2.micro or t3.small is enough for practice)
  • Both instances in the same VPC (using private IPs is the best practice)
  • A key pair (.pem file) to log in to the agent

Step 1: Launch the Agent EC2 Instance

  1. Go to EC2 → Launch Instance
  2. Name it jenkins-agent-1
  3. Choose the same AMI and VPC as your controller
  4. In the Security Group, allow SSH (port 22) from the controller's security group (not from the whole internet)
  5. Launch the instance

Tip: allowing port 22 only from the controller's security group is safer than opening it to 0.0.0.0/0.

Step 2: Install Java and Tools on the Agent

Connect to the agent instance and install Java, because Jenkins needs it to run its agent process.

# Amazon Linux 2023 sudo dnf update -y sudo dnf install java-17-amazon-corretto -y java -version 

Install any tools your pipeline needs. For example, Docker and Git:

sudo dnf install git docker -y sudo systemctl enable --now docker sudo usermod -aG docker ec2-user 

Create a working folder for Jenkins:

mkdir -p /home/ec2-user/jenkins-agent 

Step 3: Add SSH Credentials in Jenkins

The controller needs a way to log in to the agent.

  1. Go to Manage Jenkins → Credentials → System → Global credentials → Add Credentials
  2. Kind: SSH Username with private key
  3. ID: agent-ssh-key
  4. Username: ec2-user (use ubuntu for Ubuntu)
  5. Private Key: choose Enter directly and paste the content of your .pem file
  6. Click Create

Never store keys inside a Jenkinsfile or a Git repository.

Step 4: Add the Agent Node in Jenkins

  1. Go to Manage Jenkins → Nodes → New Node
  2. Name: agent-1, select Permanent Agent, click Create
  3. Fill in the settings:
Setting Value
Number of executors 2 (how many builds can run at once)
Remote root directory /home/ec2-user/jenkins-agent
Labels docker linux
Usage Use this node as much as possible
Launch method Launch agents via SSH
Host Agent's private IP
Credentials agent-ssh-key
Host Key Verification Strategy Non-verifying (for practice) or Known hosts file (better)
  1. Click Save
  2. Open the node page and check that the status shows "Agent successfully connected and online"

Note: Labels are very useful. They let a job choose which type of agent it needs.

Step 5: Stop Running Builds on the Controller

Go to Manage Jenkins → Nodes → Built-In Node → Configure and set Number of executors to 0.

Now all builds are forced to run on agents, and your Jenkins UI stays fast.

Step 6: Use the Agent in a Declarative Pipeline

Tell the pipeline which agent to use with the agent { label '...' } block.

pipeline { agent { label 'docker' } stages { stage('Checkout') { steps { git branch: 'main', url: 'https://github.com/myuser/cloudcart.git' } } stage('Build Docker Image') { steps { sh 'docker build -t myuser/cloudcart:latest .' } } stage('Verify') { steps { sh 'hostname && whoami && docker images' } } } post { success { echo 'Build finished on the agent!' } failure { echo 'Build failed. Check the console output.' } } } 

Run the job and open the Console Output. You will see a line like Running on agent-1 in /home/ec2-user/jenkins-agent/workspace/.... That confirms the build ran on the agent, not on the controller.

Bonus: different agents for different stages

pipeline { agent none stages { stage('Build') { agent { label 'docker' } steps { sh 'docker build -t myapp .' } } stage('Test') { agent { label 'linux' } steps { sh 'echo Running tests...' } } } } 

Common Problems and Fixes

Problem Likely cause and fix
Agent shows offline Check that Java is installed on the agent and port 22 is open from the controller's security group
Permission denied (publickey) Wrong username or wrong private key in the Jenkins credential
docker: permission denied Add the user to the docker group (sudo usermod -aG docker ec2-user) and reconnect the agent
Job stays in queue: "waiting for next available executor" The label in the Jenkinsfile does not match the node label
Connection timeout The controller and agent are in different VPCs or the security group rule is missing

Cost-Saving Tips on AWS

  • Use small instances (t3.small) for agents, since builds are short-lived
  • Stop the agent instance when you are not practicing, to avoid charges
  • Use private IPs to avoid data transfer costs between instances
  • For automatic scaling, explore the Amazon EC2 plugin for Jenkins. It launches agents on demand and terminates them when the build is finished

Best Practices

  • Keep the controller light: 0 executors on the built-in node
  • Use labels (docker, linux, test) to match jobs to the right agents
  • Allow SSH only from the controller's security group
  • Store keys in Jenkins Credentials, never in code
  • Keep agent tools (Java, Docker, Git) updated
  • Monitor agent disk space, since Docker images can fill it quickly

Conclusion

Moving from a single Jenkins server to a controller plus agents setup is one of the easiest ways to make your CI/CD faster and more reliable. Builds run in parallel, the Jenkins UI stays responsive, and you can add more EC2 agents whenever your workload grows.

If you already have Jenkins running on EC2, try launching one more instance today, connect it as an agent, and run your pipeline on it. It takes less than 30 minutes and teaches you how real-world CI/CD is scaled.

Author: Vishal Patil
LinkedIn: vishalpatil-devops-aws
GitHub: VishalPatil-DevOps-AWS

vishalcloudjourney