CI/CD

Continuous integration and delivery for the home lab.


Overview

Four systems work together: GitHub Actions validates PRs and applies the non-Kubernetes stacks, Renovate keeps dependencies current, ArgoCD delivers Kubernetes manifests, and self-hosted runners in the cluster execute the workflows.

flowchart LR
    Dev((Developer)) -->|PR| GitHub[GitHub]
    Renovate[Renovate\nrenovate-operator] -->|PRs| GitHub

    subgraph CI["GitHub Actions (ARC runners on worker-07)"]
        Checks[Checks]
        Diff[ArgoCD Diff / Talos Diff /\nTerraform Plan]
        Apply[Talos Apply /\nTerraform Apply]
        Build[Build Docker Images]
    end

    GitHub --> Checks
    GitHub --> Diff
    GitHub -->|merge to main| Apply
    GitHub -->|merge to main| Build
    Build -->|push| GHCR[ghcr.io]
    GitHub -->|main branch| ArgoCD[ArgoCD]
    ArgoCD -->|sync| Cluster[Cluster]

Pipeline Components

GitHub Actions

WorkflowTriggerPurpose
ChecksEvery PR to mainactionlint and pre-commit (yamllint, whitespace, terraform fmt/tflint); the required status check
ArgoCD DiffPR touching kubernetes/**Render changed apps with drydock and comment the diff
Talos Diff / Talos ApplyPR / push touching talos/**topf apply --dry-run on PRs, topf apply on merge
Terraform Plan / Terraform ApplyPR / push touching terraform/{alexa,garrison-alexa,bootstrap,general}dflook plan and apply (AWS via OIDC)
Terraform UniFiPR / push touching terraform/unifi/**Plan and apply against the UniFi gateway
Build Docker ImagesPush touching docker/**, or manualNative multi-arch builds to ghcr.io/swibrow/<image>
Deploy DocsPush touching docs/**, site/** or images/**Build this site with Astro and publish it to GitHub Pages
krr-rightsize / rightsize-reportWeekly scheduleResource request PR and a rolling sizing issue
Deploy Status WorkerManualDeploy the status.wibrow.dev Cloudflare Worker

Details: GitHub Actions

Runners

Almost every job runs on home-ops, an Actions Runner Controller scale set in the cluster (kubernetes/apps/pitower/arc/). Runner pods are pinned to worker-07 (wibrow.dev/compute: "true"), and arm64 image builds use the home-ops-arm64 set on the Raspberry Pi workers.

Docker Builds

Images that cannot live in cloudsnacks/containers are built from docker/. Each image is built natively per architecture and merged into one manifest.

Details: Docker Builds

Renovate

Renovate runs in the cluster via renovate-operator, daily and on GitHub webhooks. Presets live in .renovate/.

  • Auto-merges patch updates, container and Helm digest/patch/minor updates, and GitHub Actions minor/patch updates
  • Excludes risky infrastructure (Cilium, Rook Ceph, CNPG, Talos, Envoy Gateway, cert-manager, OpenEBS) from auto-merge
  • Groups related packages (Cilium, Rook Ceph, Talos, ARC)

Details: Renovate

ArgoCD

ArgoCD delivers everything under kubernetes/. CI never applies Kubernetes manifests.

Details: ArgoCD Setup


Workflow Summary

EventActionResult
PR openedChecks, plus the diff/plan workflow for each changed stackLint results and diff comments on the PR
Merge with kubernetes/ changesArgoCD webhookApplications synced
Merge with talos/ changesTalos Applytopf apply across changed clusters
Merge with terraform/ changesTerraform Apply or Terraform UniFiStack applied
Merge with docker/ changesBuild Docker ImagesChanged images pushed to GHCR
Renovate finds an updatePRAuto-merged or awaits review