HOWTO – Bootstrap Jenkins Docker Agent on Control Node (ctrl-01)¶
Provision a Docker-based Jenkins inbound agent on ctrl-01 so pipeline workload executes off the controller.
This HOWTO uses JCasC to define the node and the jenkins_agents_docker role to run the tools-enabled
inbound agent container on the controller host.
Difficulty: Intermediate
Prerequisites: Jenkins controller deployed (via jenkins_controller), Docker Engine installed, and admin
credentials available via your secrets strategy.
Demo¶
No academy walkthrough recording is linked here yet.
- Source: View role on GitHub
Context¶
This HOWTO is used during the bootstrap / transition phase:
- Jenkins controller is already running on
ctrl-01. - RKE2 pod agents are not yet available (or are temporarily unavailable).
- You still need a governed agent runtime to execute platform pipelines.
It aligns with:
- ADR-0603 – Run Jenkins controller on control node; agents on RKE2
- ADR-0607 – Adopt CI agent tools image for Jenkins agents
Steps¶
1. Ensure the node exists via JCasC (no Script Console)¶
Define the ctrl-docker node in controller JCasC (recommended for hardened Jenkins). Example snippet:
jenkins:
nodes:
- permanent:
name: "ctrl-docker"
remoteFS: "/home/jenkins"
numExecutors: 1
mode: NORMAL
labelString: "ctrl-docker"
retentionStrategy: "always"
launcher:
inbound:
webSocket: false
Expected result:
- Jenkins starts cleanly (no JCasC boot failures).
- The node exists in Jenkins once the controller is up.
2. Run the inbound agent container on ctrl-01¶
Apply your playbook that includes hybridops.app.jenkins_agents_docker.
Example variables (hardened mode):
jenkins_agents_docker_manage_node: false
jenkins_agents_docker_agent_secret: "{{ vault_ctrl_docker_agent_secret }}"
jenkins_agents_docker_use_websocket: false
Run:
ansible-playbook -i <inventory> deployment/playbooks/bootstrap_jenkins_agents_docker_ctrl01.yml
Expected result:
- Docker container
jenkins-agent-ctrl-dockeris running. - Jenkins reports node
ctrl-dockeras online.
3. Prove workloads run on the agent (not the controller)¶
Use a simple pipeline targeting the label:
pipeline {
agent { label 'ctrl-docker' }
stages {
stage('validation') {
steps {
sh 'whoami'
sh 'terraform version | head -n 1'
sh 'docker version'
sh 'docker compose version'
}
}
}
}
Expected result:
- Stage executes on the agent node.
- Controller remains executor-less for normal operation.
Validation¶
- Container is running:
docker ps --format "table {{.Names}}\t{{.Status}}\t{{.Image}}" | rg 'jenkins-agent|jenkins-controller'
- Jenkins shows the node online (token example):
TOKEN="$(sudo sh -c 'tr -d "\n" </opt/jenkins/.secrets/admin_api_token')"
curl -g -sS -u "admin:${TOKEN}" "http://localhost:8080/computer/api/json?tree=computer[displayName,offline]" | head -c 800 && echo
Troubleshooting¶
-
Agent container restarts
Check container logs:docker logs --tail 200 jenkins-agent-ctrl-docker -
Node missing / JNLP endpoint returns 404
The node was not defined. Add the node via JCasC (recommended) or provide the secret out-of-band. -
Docker socket permissions
If mounting/var/run/docker.sock, ensure the agent container has the socket GID as a supplemental group.
References¶
- ADRs:
- ADR-0603 – Run Jenkins controller on control node; agents on RKE2
-
Roles:
-
Operations:
- Runbooks – Jenkins
Maintainer: HybridOps
License: MIT-0 for code, CC-BY-4.0 for documentation