Skip to content

HOWTO – Bootstrap Jenkins Controller on Control Node

Deploy the Jenkins controller on the control node as the long-lived CI control plane. The result is a jenkins-controller service with pinned plugins, Configuration as Code loaded from /opt/jenkins/jenkins_home/casc_configs/, and controller executors disabled for steady-state operation.

Difficulty: Intermediate Prerequisites: SSH access to the control node, Ansible control machine, and a secrets method (Ansible Vault / AKV / CI variables) to provide the initial admin password.


Demo

No academy walkthrough recording is linked here yet.

Context

Use this HOWTO when the control node is ready, Docker is available, and Jenkins needs to become the stable entry point for platform pipelines without also becoming the build worker.

This guide fits the standard HybridOps Jenkins placement model:

  • the controller stays on the control node
  • build execution moves to agents
  • a Docker bootstrap agent is temporary, while RKE2 agents are the preferred steady-state target

This HOWTO is aligned to:


Steps

1. Confirm baseline and connectivity

  1. Confirm Ansible connectivity:

    ansible ctrl_nodes -m ping -i <inventory>
    
  2. Confirm OS facts (optional):

    ansible ctrl_nodes -m setup -a 'filter=ansible_distribution*' -i <inventory>
    

Expected result:

  • Ping succeeds.
  • Target OS matches your platform baseline.

2. Apply Docker Engine baseline (ADR-0608)

Apply the Docker Engine baseline role to ensure Docker Engine and the Compose v2 plugin are present and healthy.

Example playbook:

- name: Bootstrap Docker Engine baseline on control node
  hosts: ctrl_nodes
  become: true
  gather_facts: true

  collections:
    - hybridops.common

  roles:
    - role: hybridops.common.docker_engine
      vars:
        docker_engine_users:
          - "{{ ansible_user | default('root') }}"

Run:

ansible-playbook -i <inventory> deployment/playbooks/bootstrap_docker_ctrl01.yml

Expected result on the control node:

docker version
docker compose version

3. Deploy the Jenkins controller (ADR-0603)

Provide the admin password via your secret method (Vault/AKV/CI vars). Example vars:

jenkins_admin_username: "admin"
jenkins_admin_password: "{{ vault_jenkins_admin_password }}"
jenkins_enable_healthcheck: true

# Bootstrap/lab only: enable a single executor to run trivial jobs before agents exist.
jenkins_controller_num_executors: 1

Example playbook:

- name: Bootstrap Jenkins controller on control node
  hosts: ctrl_nodes
  become: true
  gather_facts: true

  collections:
    - hybridops.app

  roles:
    - role: hybridops.app.jenkins_controller

Run:

ansible-playbook -i <inventory> deployment/playbooks/bootstrap_jenkins_ctrl01.yml

Expected result:

  • Container jenkins-controller is running.
  • HTTP endpoint responds on the configured port.
  • JCasC files are rendered under the controller home and loaded at startup.

4. Validate readiness

  1. Container status:

    docker ps --format "table {{.Names}}\t{{.Status}}\t{{.Image}}" | rg 'jenkins-controller'
    
  2. HTTP endpoint:

    curl -sS -o /dev/null -w "HTTP=%{http_code}\n" http://localhost:8080/login
    
  3. JCasC rendered files:

    sudo ls -la /opt/jenkins/jenkins_home/casc_configs/
    
  4. Controller executor policy:

  5. Bootstrap: jenkins_controller_num_executors: 1 (temporary)

  6. Standard: set back to 0 once agents are configured

Validation

Consider this complete when:

  • Docker baseline is installed and verified (docker + docker compose).
  • Jenkins controller container is healthy and stable.
  • JCasC is loading (no Configuration as Code boot failures in logs).
  • You can authenticate to /whoAmI/api/json using admin credentials.

Suggested run-record capture:

  • docker ps output
  • docker logs --tail 200 jenkins-controller
  • HTTP probe output (curl -I / status codes)
  • The rendered casc_configs/ directory listing

Troubleshooting

  • Controller restart loop / JCasC boot failure Inspect logs and validate the rendered YAML:

    docker logs --tail 200 jenkins-controller sudo sed -n '1,200p' /opt/jenkins/jenkins_home/casc_configs/00-controller.yaml

  • Permissions errors under JENKINS_HOME Ensure ownership matches the container user:

    sudo chown -R 1000:1000 /opt/jenkins/jenkins_home

  • Endpoint never becomes healthy Increase memory (jenkins_memory) and re-check logs.


References


License: MIT-0 for code, CC-BY-4.0 for documentation