Skip to content

Architecture overview

The homelab infra is split into four layers, each with its own tooling and its own repository (or set of repositories):

Layer Tooling Where it lives
Infrastructure provisioning Terraform / Terragrunt infra-as-code/
Cluster bootstrap Ansible + talosctl infra-as-code/homelab-bootsrap-k3s
Workload delivery (GitOps) ArgoCD + Helm/Kustomize platform-engineering/gitops.*
Applications Docker + each repo's own CI teupadel.com/, sara/

Compute is hybrid: the Kubernetes cluster runs on owned hardware (a mini PC plus Raspberry Pis, with one additional worker as a Proxmox VM for GPU), while the components that make more sense managed live on AWS — image registry (ECR), state backend (S3+DynamoDB), and secret storage (SSM Parameter Store). Proxmox also hosts workloads outside the cluster, such as the GitHub Actions self-hosted runner.

The three questions the architecture answers

"Where does the cluster run, and how does it exist?"Kubernetes Cluster (Talos)

"How does a request from the internet reach a Pod?"Networking & Ingress

"Where do the secrets an app uses at runtime come from, and how does CI authenticate without fixed credentials?"Secrets & Security

How the layers relate

flowchart LR
    tf["Terragrunt<br/>(iac.homelab-live-infra)"] -- "provisions" --> aws["AWS resources<br/>ECR · SSM · IAM/OIDC"]
    ansible["Ansible + talosctl<br/>(homelab-bootsrap-k3s)"] -- "bootstraps" --> talos["Talos cluster"]
    ansible -- "installs" --> argocd["ArgoCD"]
    argocd -- "discovers and syncs" --> gitopsrepos["gitops.* repos"]
    gitopsrepos -- "applies to cluster" --> talos
    aws -. "OIDC / ExternalSecret" .-> talos

Terragrunt and Ansible only run on a manual trigger or workflow_dispatch — there's no continuous reconciliation in those two layers. From ArgoCD onward, everything is continuously reconciled: any drift between what's in Git and what's running in the cluster gets reverted automatically (selfHeal: true).