Basically this is what this website is sitting on.
| .forgejo/workflows | ||
| adrs | ||
| apps | ||
| charts | ||
| .gitignore | ||
| .sops.yaml | ||
| README.md | ||
| renovate.json | ||
GitOps source of truth for my own self-hosted Kubernetes cluster, deployed and reconciled by ArgoCD.
How it works
apps/— one ArgoCDApplicationmanifest per workload. Most point at a local chart (path: charts/<name>,targetRevision: HEAD); a few (e.g.ingress-nginx) reference an upstream chart directly.charts/— thin local Helm charts, one per app. Each wraps a single upstream chart as adependencies:entry in itsChart.yaml, pinned to a specific version, with cluster-specific config invalues.yaml.secrets.yamlfiles alongsidevalues.yamlhold credentials, encrypted with SOPS using anagekey (see.sops.yaml). ArgoCD decrypts them in-cluster via argocd-helm-secrets.adrs/— architecture decision records for non-obvious infra calls.
Setting up from scratch
-
Bootstrap ArgoCD itself, including the SOPS-aware
repo-serverimage — seecharts/argocd/Chart.yaml(a RancherHelmChartresource if using k3s, otherwise installargo-cdvia the equivalent values). -
Generate an age key and give it to ArgoCD, so it can decrypt
secrets.yamlfiles:age-keygen -o age.key kubectl -n argocd create secret generic sops-age --from-file=age.keyMount it into
argocd-repo-server(volume +SOPS_AGE_KEY_FILEenv var — already wired up if you used theargocdchart above). -
Add the public half of that key to
.sops.yamlso future secrets are encrypted for it. -
Apply the Application manifests:
kubectl apply -f apps/ -RArgoCD takes over from here — each
Applicationsyncs its chart automatically.
Adding a new app
- Create
charts/<name>/with aChart.yaml(upstream chart as a dependency) andvalues.yaml. - Encrypt any secrets into
charts/<name>/secrets.yamlwithsops -e. - Add an
Applicationmanifest underapps/. - Commit — ArgoCD does the rest.