Add Docker Agent To Jenkins

Add Docker Agent To Jenkins

Reading time1 min
#DevOps#CI/CD#Cloud#Docker#Jenkins#Containers

How to Integrate Docker Agents into Jenkins for Scalable CI/CD

Resource contention and environment drift undermine classic Jenkins installations as projects grow. Relying on static agents or the controller node tends to create unmanageable snowflakes and bottlenecks. Containerized Jenkins agents—instantiated via Docker—offer a deterministic, fast, and reproducible execution environment for every build job.


Problem: Snowflake Agents & Controller Overload

Default Jenkins architectures run builds on the controller or pre-provisioned agents. Anyone who's operated a large CI/CD system knows the headache: failed jobs due to mismatched dependencies, stale toolchains, and overloaded VMs. Jenkins builds need isolation—both from each other and from the host.

Critical Question:
How do you deliver scalable, stateless Jenkins agents, each with the toolset required, without operational sprawl?


Solution: Dockerized Jenkins Agents

Jenkins, with the Docker Plugin (1.3.x+) and Docker Pipeline Plugin (1.26.x+), employs Docker as a Cloud, spinning up disposable build agents. Each container gets only what it needs and nothing more. Edit your cloud configuration, define custom agent images, and connect pipelines to labeled pools.

Benefits

  • Reproducibility: Consistent images for consistent results.
  • Scalability: Agents spawn on demand; infrastructure scales as pipelines grow.
  • Isolation: Build runs in its own namespace—minimizing side effects.

Prerequisite: Jenkins Host Docker Integration

Your Jenkins master or primary worker must have Docker Engine installed, typically v20.10+ for current plugin compatibility. Docker socket (/var/run/docker.sock) must be accessible to the Jenkins process.

On Ubuntu 22.04 LTS:

sudo apt-get update
sudo apt-get install -y docker.io
sudo usermod -aG docker jenkins
# Restart Jenkins to apply group changes
sudo systemctl restart jenkins

Note: Exposing the Docker socket to Jenkins is convenient, but not entirely without security trade-offs. Evaluate access controls.


Step 1: Install Jenkins Plugins

Install via Manage Jenkins → Manage Plugins:

PluginMinimal VersionPurpose
Docker plugin1.3.xManage Docker hosts/providers
Docker Pipeline plugin1.26.xContainer step orchestration in pipelines

Plugins must match Jenkins core minimum requirements. Known breakage occurs with certain LTS/Core/Plugin combinations—validate plugin compatibility prior to upgrade in production.


Step 2: Configure Docker as a Cloud Provider

Open Manage Jenkins → Configure System.
Under Clouds, Add a new cloud → Docker. Minimum required fields:

FieldExample Value
Docker Host URIunix:///var/run/docker.sock
Agent templatesCustom configuration per agent image

Agent Template Example:

  • Labels: docker-agent
  • Docker Image: jenkins/inbound-agent:latest or a hard-pinned version (e.g., 2.426.0-jdk17)
  • Remote FS Root: /home/jenkins
  • Instance Cap: 4 (tune to avoid resource exhaustion)
  • Launch Method: Inbound agent via JNLP
  • Container Cap: Default 10, adjust for cluster size

For images from a private registry, add Docker registry credentials.

Gotcha:
Failed launches with log line

Cannot run program "docker": error=2, No such file or directory

usually means the Jenkins process can't reach the Docker socket or binary—validate both paths and permissions.


Step 3: Create a Custom Agent Image

Generic agents limit reproducibility. Instead, tailor an image for your stack. Example: a Maven/Node.js-capable agent.

Sample Dockerfile:

FROM jenkins/inbound-agent:2.426.0-jdk17

USER root
RUN apt-get update \
 && apt-get install -y maven nodejs npm git \
 && rm -rf /var/lib/apt/lists/*
USER jenkins

Build and push:

docker build -t registry.example.com/devops/jenkins-agent-mvn-node:2024.06 .
docker push registry.example.com/devops/jenkins-agent-mvn-node:2024.06

Insert the image name into your agent template.

Always build/test agent images locally before using in CI.
Known issue: apt-get installs can bloat images; for runtimes, prefer base images (like node:slim) if size becomes problematic.


Step 4: Pipeline: Assigning Agents by Label

Direct pipeline jobs to containers matching your label, e.g., docker-agent.

pipeline {
  agent { label 'docker-agent' }
  stages {
    stage('Build') {
      steps {
        sh 'mvn -B clean verify'
      }
    }
    stage('Test') {
      steps {
        sh 'npm test'
      }
    }
  }
}

Jenkins instantiates ephemeral agents as needed. Tear-down is automatic.


Alternative Approach: Ephemeral Containers per Step

For lightweight cases, orchestrate containers using the Pipeline docker.image block without agent templates/clouds.

pipeline {
  agent any
  stages {
    stage('Quick Maven Build') {
      steps {
        script {
          docker.image('maven:3.9.6-eclipse-temurin-17').inside {
            sh 'mvn clean install'
          }
        }
      }
    }
  }
}

This spins up a throwaway Maven container for the step—no agent lifecycle, just isolated execution.

Limitation: not a full Jenkins agent; no workspace persistence between steps.


Best Practices

  • Pin image versions. Avoid latest to ensure reproducibility and avoid unexpected toolchain breakage.
  • Resource caps: Set Docker and Jenkins agent template caps to prevent runaway parallelism consuming all system RAM/CPU.
  • Build cache optimization: Use multi-stage Dockerfiles and cache common layers.
  • Label granularity: Avoid a single label for all Docker agents; segment by language or tool (e.g., nodejs-agent, python-agent).
  • Monitoring: Enable container/containerd metrics. Sudden spikes often indicate load misconfiguration or a runaway job.

Non-Obvious Tip

For GPU workloads or privileged builds (e.g., Android), set the container template’s “Docker command line arguments” field:

--gpus all --privileged

Execution will silently fail if the host OS/kernel is missing driver support. Always validate node capabilities.


Known Issue

When using “Launch agent by connecting it to the controller”, network policies or firewall rules must allow inbound JNLP traffic (default: TCP/50000, but often needs to be tunneled or proxied in cloud environments).


Jenkins with Dockerized agents transitions CI bottoms from snowflake to cattle. Containers enforce environment parity, clean execution, and rapid scaling when config-managed properly. Tune templates, pin images, monitor Docker host resource limits, and validate agent logs for failed launches or permission issues. Robust build infrastructure emerges through small, careful iterations—not magic.