A modern Jenkins plugin for dynamic agent provisioning on Docker Swarm clusters.
This plugin is a modern replacement for the abandoned docker-swarm-plugin (last updated February 2021, 54+ unresolved issues).
| Feature | swarm-agents-cloud | docker-swarm-plugin |
|---|---|---|
| Last Update | 2025 (active) | 2021 (abandoned) |
| Open Issues | — | 54+ |
| Java Version | 21+ | 8+ |
| Jenkins Version | 2.528.3+ | Outdated |
| WebSocket Connection | ✅ | ❌ |
| JCasC Support | ✅ Full | ❌ |
| REST API | ✅ Full CRUD | ❌ |
| Prometheus Metrics | ✅ | ❌ |
| Docker Secrets/Configs | ✅ | ❌ |
| Template Inheritance | ✅ | ❌ |
| Rate Limiting | ✅ | ❌ |
| Health Checks | ✅ | ❌ |
| Pipeline DSL | ✅ swarmAgent {} |
❌ |
| Audit Logging | ✅ | ❌ |
| Orphan Cleanup | ✅ Automatic | ❌ |
| Dark Theme Dashboard | ✅ | ❌ |
| TLS Support | ✅ Working | |
| XSS Vulnerabilities | ✅ Fixed |
- Modern Stack — Java 21, WebSocket, current Jenkins API
- DevOps-Ready — JCasC, REST API, Prometheus, Pipeline DSL
- Security — TLS, Secrets, Input Validation
- Reliability — Rate Limiting, Retry with Backoff, Health Checks, Orphan Cleanup
- Active Support — Regular updates vs abandoned project
- Dynamic Agent Provisioning — Automatically creates Docker Swarm services on demand
- WebSocket Support — Modern agent connection (no inbound TCP ports required)
- TLS/SSL Authentication — Full Docker TLS certificate support
- Configuration as Code — Complete JCasC compatibility
- Resource Management — CPU/memory limits and reservations per template
- Health Checks — Configurable container health monitoring
- Secrets & Configs — Docker Swarm secrets and configs integration
- Rate Limiting — Built-in provisioning rate limits (thundering herd protection)
- Dashboard — Real-time cluster monitoring at
/swarm-dashboard - REST API — Programmatic management at
/swarm-api - Template Inheritance — Inherit settings from parent templates (
inheritFrom) - Prometheus Metrics —
/swarm-api/prometheusendpoint - Audit Logging — Track all provisioning events
- Pipeline DSL — Native
swarmAgentstep for Jenkinsfiles - Retry with Backoff — Automatic exponential backoff on failures
- Orphan Cleanup — Automatic cleanup of stale services
- Jenkins 2.528.3 or newer (see Jenkins Java requirements for Java version)
- Docker Swarm cluster (
docker swarm init)
- Go to Manage Jenkins → Clouds
- Click New cloud → Docker Swarm Agents Cloud
- Configure:
- Docker Host:
tcp://your-swarm-manager:2376 - Credentials: Docker Server Credentials (for TLS)
- Max Concurrent Agents: Limit total agents
- Docker Host:
jenkins:
clouds:
- swarmAgentsCloud:
name: "docker-swarm"
dockerHost: "tcp://swarm-manager:2376"
credentialsId: "docker-tls-creds"
maxConcurrentAgents: 10
jenkinsUrl: "http://jenkins:8080/"
swarmNetwork: "jenkins-agents"
templates:
- name: "maven"
image: "jenkins/inbound-agent:latest"
labelString: "maven docker"
remoteFs: "/home/jenkins/agent"
numExecutors: 2
maxInstances: 5
cpuLimit: "2.0"
memoryLimit: "4g"
connectionTimeoutSeconds: 300
idleTimeoutMinutes: 30| Field | Description | Default |
|---|---|---|
name |
Template identifier | Required |
image |
Docker image | jenkins/inbound-agent:latest |
labelString |
Jenkins labels (space-separated) | — |
remoteFs |
Agent working directory | /home/jenkins/agent |
numExecutors |
Executors per agent | 1 |
maxInstances |
Max containers from template | 5 |
cpuLimit |
CPU limit (e.g., "2.0") | — |
memoryLimit |
Memory limit (e.g., "4g") | — |
cpuReservation |
CPU reservation | — |
memoryReservation |
Memory reservation | — |
| Field | Description |
|---|---|
privileged |
Run with elevated privileges |
oneShot |
Terminate the agent after a single completed build (requires numExecutors=1) |
user |
Run as specific user (e.g., "1000:1000") |
hostname |
Container hostname |
entrypoint |
Custom container entrypoint |
disableContainerArgs |
Don't pass args to entrypoint |
capAdd / capAddString |
Linux capabilities to add (requires Docker Engine 20.10+ / API 1.41+) |
capDrop / capDropString |
Linux capabilities to drop (requires Docker Engine 20.10+ / API 1.41+) |
dnsServersString |
Custom DNS servers |
templates:
- name: "base"
image: "jenkins/inbound-agent:latest"
cpuLimit: "2.0"
memoryLimit: "4g"
connectionTimeoutSeconds: 300
- name: "maven"
inheritFrom: "base"
labelString: "maven docker"
environmentVariables:
- key: "MAVEN_OPTS"
value: "-Xmx1g"Set oneShot: true on a template to make agents self-destruct immediately after a single
completed build, instead of being kept alive for the idle-timeout window. Useful when each
build needs a guaranteed-clean filesystem and process state (security-sensitive jobs,
workloads that leak temporary state, etc.).
templates:
- name: "ephemeral-build"
image: "jenkins/inbound-agent:latest"
labelString: "ephemeral"
numExecutors: 1 # Must be 1 with oneShot=true
oneShot: true
idleTimeoutMinutes: 1 # Fallback for the rare "agent connected but no build dispatched" caseTrade-offs:
- Each build pays the full container provisioning cost (image pull + agent connection handshake), adding tens of seconds to queue time.
numExecutorsmust be1. The form rejectsoneShot=truecombined withnumExecutors > 1because the one-shot retention strategy terminates the agent after the first completed build, which would abort any other build still running on a second executor.- If a parent template (referenced via
inheritFrom) hasoneShot: true, child templates inherit it and cannot disable it (same OR-merge asprivileged).
capAdd / capDrop propagate Linux capabilities to the agent container's
TaskSpec.ContainerSpec. Docker Engine 20.10 (API 1.41) or newer is required — older
Engine versions silently ignore these fields.
templates:
- name: "net-admin-agent"
image: "jenkins/inbound-agent:latest"
capAdd:
- "CAP_NET_ADMIN"
capDrop:
- "CAP_CHOWN"The newline-separated string form (capAddString) is also accepted for compatibility
with existing docker-swarm-plugin configurations.
templates:
- name: "with-secrets"
secrets:
- secretName: "my-secret"
fileName: "secret.txt"
targetPath: "/run/secrets"Support for pulling images from private Docker registries when launching agents.
Supported Registries:
- Docker Hub (public and private repositories)
- Google Container Registry (gcr.io)
- AWS Elastic Container Registry (ECR)
- GitHub Container Registry (ghcr.io)
- Azure Container Registry (azurecr.io)
- Any private registry with username/password authentication
Setup Steps:
-
Create Credentials in Jenkins:
- Go to Manage Jenkins → Credentials
- Add Username with password credentials for your registry
- Note the credentials ID
-
Configure Template:
- In template configuration, select credentials from Registry Credentials dropdown
- Plugin automatically detects registry from image name
Configuration as Code Example:
jenkins:
clouds:
- swarmAgentsCloud:
name: "docker-swarm"
templates:
- name: "private-agent"
image: "myregistry.com/jenkins-agent:latest"
registryCredentialsId: "docker-registry-creds"
labelString: "private docker"UI Configuration: Navigate to template settings → Registry Credentials dropdown → Select your credentials
Template Inheritance: Registry credentials can be inherited from parent templates:
templates:
- name: "base-private"
image: "myregistry.com/base:latest"
registryCredentialsId: "docker-registry-creds"
- name: "maven-private"
inheritFrom: "base-private"
image: "myregistry.com/maven:latest"
# Inherits registryCredentialsId from base-privateAdd custom hostname-to-IP mappings to container's /etc/hosts file, equivalent to Docker's --add-host flag.
Use Cases:
- Local development and testing
- Custom DNS resolution for internal services
- Database and service aliases
Format: hostname:IP (one entry per line, supports IPv4 and IPv6)
Configuration as Code Example:
templates:
- name: "agent-with-hosts"
image: "jenkins/inbound-agent:latest"
extraHosts:
- "database.local:10.0.0.50"
- "internal-registry:192.168.1.100"
- "api.internal:172.16.0.10"UI Configuration:
Navigate to template settings → Extra Hosts textarea → Enter hostname:IP pairs (one per line)
Example:
myhost:192.168.1.1
database:10.0.0.5
registry.local:172.16.0.20
Template Inheritance: Extra hosts are merged when using template inheritance:
templates:
- name: "base"
extraHosts:
- "shared-db:10.0.0.1"
- name: "maven"
inheritFrom: "base"
extraHosts:
- "maven-repo:192.168.1.50"
# Container will have both extra hosts entriesValidation:
- Automatic validation of IP addresses (IPv4 and IPv6)
- Hostname format checking
- Clear error messages for invalid entries
The swarmAgent directive is registered with the Pipeline Syntax → Declarative
Directive Generator → agent, so the new plugin is a drop-in replacement for
classic docker-swarm-plugin usage:
pipeline {
agent {
swarmAgent {
cloud 'docker-swarm'
template 'maven'
label 'maven java'
}
}
stages {
stage('Build') {
steps { sh 'mvn clean package' }
}
}
}If only one Docker Swarm cloud is configured, cloud may be omitted. The label
defaults to the referenced template's labelString when not given. Inline
configuration without a template is also supported:
pipeline {
agent {
swarmAgent {
image 'jenkins/inbound-agent:alpine'
label 'docker'
cpuLimit '2.0'
memoryLimit '4g'
}
}
stages { ... }
}pipeline {
agent none
stages {
stage('Build') {
steps {
swarmAgent(cloud: 'docker-swarm', template: 'maven') {
sh 'mvn clean package'
}
}
}
}
}When the plugin provisions an inbound agent, it passes Jenkins connection details to the container in two parallel ways so most images "just work":
- Environment variables (always set):
JENKINS_URL,JENKINS_AGENT_NAME,JENKINS_SECRET,JENKINS_AGENT_WORKDIRJENKINS_WEB_SOCKET=true(WebSocket inbound protocol)- Aliases for compatibility:
JNLP_URL,JENKINS_JNLP_URL,DOCKER_SWARM_PLUGIN_JENKINS_AGENT_JNLP_URL,DOCKER_SWARM_PLUGIN_JENKINS_AGENT_SECRET
- Command-line args (positional):
[<JENKINS_URL>, <SECRET>, <AGENT_NAME>], appended to the image'sENTRYPOINT.
templates:
- name: default
image: "jenkins/inbound-agent:alpine" # or :latest, :jdk21, ...
labelString: "docker"jenkins/inbound-agent ships with ENTRYPOINT ["/usr/local/bin/jenkins-agent"] that
accepts the positional args correctly — no extra configuration needed.
If your image has no ENTRYPOINT (or one that does not understand the
url secret name argument convention), the positional args become the container's whole
command. Docker will then try to exec the URL as a binary and fail with:
OCI runtime create failed: ... exec: "https://<jenkins>/": no such file or directory
Two equivalent fixes — pick whichever fits your image:
Option A — let the plugin set a real ENTRYPOINT (entrypoint: takes a free-form
command, args are skipped):
templates:
- name: custom
image: "my-registry/my-agent:1.2.3"
entrypoint: "/usr/local/bin/my-startup.sh"Option B — use env vars only (the image must read $JENKINS_URL, $JENKINS_SECRET,
$JENKINS_AGENT_NAME itself):
templates:
- name: custom
image: "my-registry/my-agent:1.2.3"
disableContainerArgs: true # skip positional [url, secret, name] argsdisableContainerArgs is the safest default for slim or non-standard images.
Base URL: http://jenkins/swarm-api/
| Method | Endpoint | Description |
|---|---|---|
| GET | /clouds |
List all clouds |
| GET | /cloud?name=X |
Cloud details |
| GET | /templates?cloud=X |
List templates |
| GET | /template?cloud=X&name=Y |
Template details |
| GET | /agents?cloud=X |
List agents |
| GET | /prometheus |
Prometheus metrics |
| GET | /audit?cloud=X |
Audit log |
| POST | /provision?cloud=X&template=Y |
Provision agent |
| PUT | /template |
Update template |
Access at http://jenkins/swarm-dashboard/
- Cluster health overview
- Node status and resources
- Active services list
- Dark theme support
http://jenkins/swarm-api/prometheus
Metrics: swarm_agents_total, swarm_agents_active, swarm_nodes_total, swarm_memory_total_bytes, etc.
Manage Jenkins → System Log → Add logger io.jenkins.plugins.swarmcloud with level FINE
| Error | Solution |
|---|---|
| "Unsupported protocol scheme: https" | Use tcp:// not https:// |
OCI runtime create failed: ... exec: "https://...": no such file or directory |
Image has no ENTRYPOINT. Use jenkins/inbound-agent, set entrypoint: on the template, or set disableContainerArgs: true. See Image Requirements. The plugin also surfaces a HINT: line in the build log on this failure. |
| "Connection refused" | Check Docker API is exposed |
| "TLS handshake failed" | Configure Docker Server Credentials |
| "This node is not a swarm manager" | Run docker swarm init |
git clone https://github.com/jenkinsci/swarm-agents-cloud-plugin.git
cd swarm-agents-cloud-plugin
mvn clean package -DskipTests
# Result: target/swarm-agents-cloud.hpiSee CONTRIBUTING.md
MIT License — see LICENSE