Professional Services CI/CD & Release Automation

A Jenkins pipeline that builds & ships to a 10-node, multi-OS fleet

One push to main compiles a native binary on Ubuntu, Fedora, FreeBSD, Solaris, and OpenBSD — in parallel — archives one artifact per platform, deploys the mainline build to every host, and leaves a tagged GitHub release ready to publish. The whole fabric — the controller, the agents, and their build toolchains — is stood up with idempotent Ansible playbooks, not by hand.

Back to Professional Services
10
Build agents
5
Operating systems
5 min
Push→build scan
1‑cmd
Release from a green build

What it is

A single Jenkins controller (gemini, an Ubuntu 24.04 VM) orchestrates a fleet of ten build agents spanning five operating-system families. The flagship job, ascii-monitor, is a multibranch pipeline: Jenkins indexes the GitHub repository, and every branch or pull request runs the Jenkinsfile committed at that exact revision — so a build is always the newest code on its branch, and pull-request builds are isolated from the mainline.

Because the controller lives on a private LAN that GitHub cannot reach, the trigger is a periodic repository scan (every five minutes) rather than an inbound webhook. Indexing is cheap — it only starts a build when a head commit has actually moved — so the interval is simply the worst-case push-to-build latency, not wasted work.

The pipeline at a glance

Jenkins multibranch CI/CD pipeline A push to main triggers a five-minute periodic scan on the Jenkins controller, which indexes the branch, runs the Jenkinsfile, fans a build matrix out across ten nodes on five operating systems, archives one binary per node, deploys the mainline build to each host, and produces a GitHub release. git push → main beknar/ascii-monitor Periodic scan controller gemini · H/5 * * * * Branch indexing checkout Jenkinsfile @ commit Matrix build fan out Matrix fan-out — every node runs the same gmake, archives one native binary abba Linux · Ubuntu · apt calibri Linux · Ubuntu · apt gabriel Linux · Ubuntu · apt zariel Linux · Ubuntu LXC taroo Linux · Fedora · dnf lulu FreeBSD · pkg jindi FreeBSD · vnet jail jindi2 FreeBSD · vnet jail phoenix Solaris · OpenJDK 25 hornet OpenBSD · JDK 21 Each cell: gmake → archive ascii-monitor-${NODE}. Per-OS flags live in the repo Makefile, so the command is identical everywhere. Checksums group exactly by toolchain — proof every host received its correct native build. Deploy → /usr/local/bin main only · atomic install on the same node GitHub release gh release create · one binary per OS
The ascii-monitor multibranch pipeline: trigger → index → parallel matrix build → archive → mainline deploy → release.

How a change becomes a release

  1. Push to main. No manual step — the controller picks it up on its next scan.
  2. Periodic scan (every 5 min). Jenkins re-indexes the repo; a moved head commit queues a build (shown as BranchIndexingCause).
  3. Checkout the pinned Jenkinsfile. The pipeline definition always comes from the commit being built.
  4. Matrix build. The job fans out over all ten nodes (agent { label "${NODE}" }) and runs the identical gmake on each.
  5. Archive. Each cell archives its own native binary (ascii-monitor-${NODE_NAME}).
  6. Deploy — mainline only. A when { branch 'main' } stage installs each cell's binary into /usr/local/bin on the same host, via an atomic cp+mv (no "text file busy", no cross-node copying). PR builds compile and archive but never overwrite a live binary.
  7. Cut a release. A green main build already holds a full set of per-OS artifacts, so a release just publishes them: gh release create tags the exact built commit and attaches each binary.

Privilege model, verified before it shipped. Seven agents connect as a sudo-capable user; the two FreeBSD jails connect as root (one has no sudo at all). The deploy step escalates only when it isn't already root, so a single stage works unchanged across every OS in the fleet.

The Ansible playbooks behind the pipeline

The CI fabric itself is infrastructure as code. Three idempotent Ansible playbooks stand up and maintain everything the pipeline depends on — run them against one box or the whole fleet and the result is the same every time:

PlaybookRole in the pipelineWhat it installs
install-jenkins-controllerStands up the controller (gemini)Java 21, the official Jenkins LTS apt repo, the jenkins package, service on :8080
install-jenkins-clientPrepares every build agentA Java JDK to run the agent + git for SCM checkouts (OS-correct package per host)
install-build-toolsGives agents a uniform build toolchainC/C++, CMake, make/gmake, and C# (.NET on Linux, Mono on FreeBSD)

Each playbook groups hosts by package manager and runs the OS-appropriate module — the apt module on Ubuntu, dnf on Fedora, and the raw module via pkg on FreeBSD (the jails have no Python) — so a single command covers a deliberately heterogeneous fleet. The full write-up of all six fleet playbooks, with topology diagrams, is on the dedicated Ansible page.

Read the Ansible playbooks write-up

Need a pipeline that ships safely, every time?

Repeatable builds, tested before they deploy, on whatever mix of platforms you run — let's talk.