Practical Homelab CI/CD: From Bare Metal to GitOps in Your Home

Practical Homelab CI/CD: From Bare Metal to GitOps in Your Home

If your home lab is just a NAS with a few VMs and a GPIO-powered toy, you’re leaving serious leverage on the table. The real payoff in a homelab isn’t “cool tech” for its own sake; it’s a reproducible, self-hosted automation stack that lets you ship software the way you want—on your terms, without depending on cloud bills, flaky CI runners, or vendor lock-ins. In this guide I’ll lay out a practical blueprint for a self-hosted CI/CD and DevOps stack you can actually build in a weekend, with hardware you already own or can reasonably source, and with enough guardrails to keep it sane as you scale.

Hook: The moment you stop shipping code to a cloud CI you don’t fully control and start running it in a self-hosted, GitOps-driven cluster, your home lab stops being a collection of experiments and becomes a reliable “production-like” platform you can trust for everyday projects. Yes, it’s possible. Yes, it’s worth it.

1) Start with a sane plan, not a shiny kit

  • Define your goals. Do you want automated builds, tested deployments, and a single source of truth for your infrastructure? Or do you want a dev space that can also run personal apps with repeatable deploys? Write down 3 must-haves (e.g., GitOps, self-hosted runners, and a reliable backup strategy).
  • Inventory your hardware. A modest but solid setup can be 2–4 nodes (one master, one or more runners/agents), with 16–32 GB RAM per node if you can swing it. If you’re starting with Raspberry Pis, know they’re great for learning but less forgiving for large workloads; plan accordingly.
  • Network topology matters. A dedicated management network (VLAN or separate NICs) helps keep your control plane responsive. You’ll want a stable DNS entry for your cluster (internal and optional external), and a TLS termination path for services you expose.

2) Choose a robust, practical base: Proxmox + k3s

Why this pairing? Proxmox gives you clean virtualization, snapshots, and easy clustering. k3s is a lightweight Kubernetes distribution that plays nicely in homelabs and runs well on small VMs or bare-metal nodes.

  • Setup outline:
  • Install Proxmox on your servers/nodes.
  • Create 2–4 VMs with a modest amount of RAM (e.g., 2–4 GB for light nodes, 4–8 GB for heavier nodes) and a couple of vCPUs each. Put them on a dedicated storage pool if possible.
  • For each VM, install k3s. On the first node, install the server; on the others, join as agents.
  • Verify with kubectl get nodes and kubectl cluster-info.
  • Example (very high level):
  • On the first node:
  • curl -sfL https://get.k3s.io | sh -
  • On a joining node (you’ll get a token from the server):
  • curl -sfL https://get.k3s.io | K3S_URL=https://<server-ip>:6443 K3S_TOKEN=<token> sh -
  • Tooling to consider inside the cluster:
  • containerd as runtime (default in k3s)
  • kubectl available via the kubeconfig from the master

3) A lightweight GitOps stack: Argo CD + Helm/Kustomize

GitOps—treating the cluster state as code—lets you automate deployments from Git repos. Argo CD is a practical, well-supported controller that watches a repo and applies manifests to the cluster.

  • Install Argo CD in the cluster:
  • kubectl create namespace argocd
  • kubectl apply -n argocd -f https://raw.githubusercontent.com/argoproj/argo-cd/stable/manifests/install.yaml
  • Expose the API server (via LoadBalancer/Ingress or port-forward for initial setup) and login using the admin password.
  • Connect a repo:
  • Point Argo CD to a repo containing manifests for apps you want to deploy (Helm charts or Kustomize overlays).
  • Create an App in Argo CD that references the target namespace and the repo/path.
  • Why Helm/Kustomize?
  • Helm makes templating painless for multi-env deployments.
  • Kustomize keeps overlays simple and decouples environment-specific changes.
  • Day-to-day workflow:
  • Push a change to your git repo (e.g., a HelmValue override or a Kustomize patch).
  • Argo CD detects drift and applies it automatically; you get a clean audit trail in Git and in Argo CD.
  • You can configure automated health checks and automated rollbacks.

4) Self-hosted CI runners: pragmatic, not experimental

Your CI should not rely on a cloud runner you don’t control. A dedicated self-hosted runner (or a small pool) in your homelab can handle builds, tests, and artifact creation. A simple, practical approach is to run a few runners as Kubernetes pods or as VMs.

  • Options:
  • GitHub Actions self-hosted runners (best if you’re already in the GitHub ecosystem).
  • Drone CI or GitLab CI runners if you prefer open-source CI and you’re hosting GitLab in your cluster or on a nearby VM.
  • Self-hosted runner in Kubernetes (example quick pattern):
  • Use a Deployment that runs a runner container image; use a Kubernetes job to trigger builds. If you need full isolation, pin each runner to a dedicated node.
  • Pros: consistent environment, ephemeral runners, scalable as your workloads grow.
  • Cons: you’ll want resource limits and auto-scaling policies to avoid runaway bills on your own hardware.
  • Practical steps:
  • Create a namespace, then deploy a runner with a static label, e.g., "ci-runner".
  • Register the runner with your CI system using a token (GitHub Actions provides registration tokens for self-hosted runners).
  • Limit concurrency per project to avoid starving other workloads.
  • Cache dependencies locally on the runner to reduce build times.
  • Example pattern:
  • A GitHub Actions workflow checks in code, triggers a self-hosted runner, runs tests, builds a container image, pushes to a registry, and updates the GitOps repo for deployment.

5) A self-hosted image registry and artifact storage

You’ll want a private registry for your built images and artifacts, ideally with TLS and access control. Harbor is a polished option, but a simpler approach is to run a Docker Registry in a VM or as a Kubernetes deployment with authentication. For a production-ish taste, add a small content store (e.g., S3-compatible storage) for backups and artifact storage.

  • Simple registry on Kubernetes:
  • Use a basic registry deployment with Ingress for TLS and a simple auth mechanism (htpasswd-based) or OAuth if you want more complexity.
  • Better option for larger environments:
  • Harbor with TLS, user roles, and image replication. It’s heavier but worth it if you’re storing many images and need robust security.
  • Registry tips:
  • Enable TLS (Let’s Encrypt or a self-signed cert for internal use).
  • Enable content trust or signature verification if you’re security-conscious.
  • Set up a small retention policy so you don’t accumulate old images forever.

6) Observability and reliability: Prometheus, Grafana, and logs

A healthy DevOps stack needs visibility. A pragmatic observability suite for a homelab is Prometheus + Grafana for metrics, Loki for logs, and a lightweight alerting story.

  • Prometheus:
  • Use the Prometheus Operator or kube-prometheus for a sane default installation in Kubernetes.
  • Scrape node metrics, kube-state-m metrics, and application metrics from your apps.
  • Grafana:
  • Ship dashboards for cluster health, deployment status, and application metrics.
  • Set up alerting rules (e.g., deploy failures, high error rate) that can notify you via email or Slack.
  • Loki:
  • Centralize logs in a cost-effective way; use promtail to ship logs from pods.
  • Practical tips:
  • Don’t add 100 dashboards day one; start with a few vital panels: cluster health, CI/CD pipeline status, failing pods, and registry usage.
  • Use dashboards as a continuous improvement tool, not a status badge.

7) Storage, backups, and disaster recovery

Homelabs fail fast if your data isn’t backed up or recoverable. A pragmatic plan uses a mix of durable