GitOps

Nothing gets kubectl apply’d by hand. ArgoCD watches git and makes the cluster match it.

Two repos

  • homelab_k3s is the how: cluster bootstrap and the ArgoCD root applications.
  • homelab_kube-apps is the what: every manifest that runs on the cluster.

Renovate opens most of the pull requests in homelab_kube-apps. Splitting the repos keeps those version bumps away from the deployment wiring.

App of apps

Three root applications point ArgoCD at the different layers:

root_application_core.yaml   # core components (Helm charts)
root_application_prod.yaml   # ApplicationSet over apps/*/overlays/prod
root_application_dev.yaml    # ApplicationSet over apps/*/overlays/dev

The prod and dev roots are ApplicationSets with a git directory generator. Adding an app means adding a folder and committing it. No wiring changes are needed.

App layout

Every app uses the same Kustomize structure:

apps/<app>/
├── base/               # deployment, service, pvc
└── overlays/
    ├── prod/           # patches, ingressroute, vaultsecret
    └── dev/            # optional

Apps started out as Helm charts I wrote myself. For apps I own, Kustomize turned out simpler: plain YAML, no templating to debug, and Renovate can bump image tags directly. I wrote about the move here.

Core components

Platform pieces are thin wrapper charts around upstream Helm charts, with my values next to them:

Component Purpose
Traefik Ingress
cert-manager Let’s Encrypt certificates via Cloudflare DNS
Longhorn Replicated block storage
CloudNative-PG PostgreSQL operator
Vault Secrets Operator Syncs secrets from OpenBao
Prometheus In-cluster metrics, federated outward
Alloy Pod and node logs to Loki
Gitea runners CI runners inside the cluster
Reloader, Descheduler Restart on config change, rebalance pods

The homelab page reads this list straight from the repo every time the site is built.

Renovate

Renovate runs on a schedule against every infrastructure repo. Out of the box it tracks Helm charts, container images and OpenTofu providers. Custom regex managers also track binaries that Ansible installs, like Gitea, Loki, Garage and even PaperMC builds for the Minecraft server. Minor and patch updates merge automatically, and major versions wait for review.