Declarative infrastructure on bare metal · 2026
Homelab
A push to an application repository ends as a public HTTPS response with no manual step in between: Jenkins tests and builds, the image is pinned by sha256 digest in GitHub Container Registry, a commit to the gitops repository describes the desired state, and Argo CD syncs it into the cluster. Terraform provisions, Ansible configures, and WireGuard is the only way into the internal network.
RoleDesign, provisioning, and operation
Context and evolution
The system behind the screens.
A single OVHcloud server holds thirteen guests, a Kubernetes cluster, and the delivery path for everything I publish. Proxmox splits the hardware, Kubernetes runs the workloads, and a Git repository describes what should be running; between a push and a public HTTPS response there is no manual step left.
The division of responsibility is explicit. Terraform creates resources and keeps its state in a remote bucket another stack created first; Ansible owns everything that happens inside a guest, with the inventory regenerated from Terraform output. Long remote-exec scripts were left out: they exit 0, the resource reports success, and state stops describing reality.
The design changed most when I rebooted the server. The first reboot brought everything back except the tunnel, and the cause was hand-built systemd units loading their own nftables tables on every boot; no test had ever seen them because each Ansible run deleted them before measuring. Since then every recovery procedure records whether it was ever run against this cluster, and the second reboot brought all thirteen guests back with nothing touched.
Decisions and outcomes
- Terraform provisions and Ansible configures, with no remote-exec scripts that report success just for exiting 0.
- A three-member control plane with etcd, a PostgreSQL primary with a streaming standby, and snapshots stored off the server.
- Secrets live in Bitwarden Secrets Manager and never pass through a command line.
System map
Open every application.
These are not labels: every module retains its own route and technical context.
- 01View module
Provisioning
Five Terraform stacks with state kept off the server.
- 02View module
Configuration
Ansible owns everything that happens inside a guest.
- 03View module
Kubernetes cluster
A three-member control plane and a Gateway that terminates TLS.
- 04View module
Delivery chain
From a push to an HTTPS response with no manual step.
- 05View module
Secrets and access
One secrets store and one door in.
- 06View module
Data and recovery
A primary, a streaming replica, and runbooks that record what was actually run.
- 07View module
Observability
Prometheus, Loki, and Grafana outside the cluster they watch.