From c759481ea6005f719425e5eacb62840d19984565 Mon Sep 17 00:00:00 2001 From: Story Crater Bot <19826264+Riotpiaole@users.noreply.github.com> Date: Mon, 20 Jul 2026 08:22:53 -0700 Subject: [PATCH] =?UTF-8?q?refactor(argocd):=20replace=20wave/layer/phase?= =?UTF-8?q?=20schemes=20with=20two-phase=20bootstrap=20+=20app-of-apps=20a?= =?UTF-8?q?nd=20document=20both=20CD=20scopes=20=E2=80=94=20fixes=20self-h?= =?UTF-8?q?osted-git=20chicken-egg=20and=20stale=20paths?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- k8s/argocd/apps/05-networking.yaml | 43 ++++++ k8s/argocd/apps/10-storage-observability.yaml | 135 ++++++++++++++++++ k8s/argocd/apps/20-logging.yaml | 87 +++++++++++ k8s/argocd/apps/30-security.yaml | 102 +++++++++++++ k8s/argocd/apps/40-data.yaml | 23 +++ k8s/argocd/apps/50-messaging.yaml | 111 ++++++++++++++ k8s/argocd/apps/60-applications.yaml | 107 ++++++++++++++ k8s/argocd/bootstrap/BOOTSTRAP.md | 116 +++++++++++++++ k8s/argocd/bootstrap/cnpg-operator.yaml | 2 +- k8s/argocd/bootstrap/forgejo.yaml | 8 +- k8s/argocd/projects/homelab-project.yaml | 12 +- k8s/argocd/root/homelab-root.yaml | 28 ++++ k8s/argocd/root/kustomization.yaml | 13 +- 13 files changed, 774 insertions(+), 13 deletions(-) create mode 100644 k8s/argocd/apps/05-networking.yaml create mode 100644 k8s/argocd/apps/10-storage-observability.yaml create mode 100644 k8s/argocd/apps/20-logging.yaml create mode 100644 k8s/argocd/apps/30-security.yaml create mode 100644 k8s/argocd/apps/40-data.yaml create mode 100644 k8s/argocd/apps/50-messaging.yaml create mode 100644 k8s/argocd/apps/60-applications.yaml create mode 100644 k8s/argocd/bootstrap/BOOTSTRAP.md create mode 100644 k8s/argocd/root/homelab-root.yaml diff --git a/k8s/argocd/apps/05-networking.yaml b/k8s/argocd/apps/05-networking.yaml new file mode 100644 index 0000000..46f7a6a --- /dev/null +++ b/k8s/argocd/apps/05-networking.yaml @@ -0,0 +1,43 @@ +# Wave 0 — networking policies layered on the Cilium CNI + CoreDNS that the +# cluster bootstrap already installed (substrate). These are raw manifests only. +apiVersion: argoproj.io/v1alpha1 +kind: Application +metadata: + name: cilium-policy + namespace: argocd + annotations: + argocd.argoproj.io/sync-wave: "0" +spec: + project: homelab + source: + repoURL: http://forgejo.riotpiao.com:3000/riotpiao.com/homelab.git + targetRevision: main + path: k8s/bootstrap/cilium + destination: + server: https://kubernetes.default.svc + namespace: kube-system + syncPolicy: + automated: + prune: true + selfHeal: true +--- +apiVersion: argoproj.io/v1alpha1 +kind: Application +metadata: + name: coredns-config + namespace: argocd + annotations: + argocd.argoproj.io/sync-wave: "0" +spec: + project: homelab + source: + repoURL: http://forgejo.riotpiao.com:3000/riotpiao.com/homelab.git + targetRevision: main + path: k8s/bootstrap/coredns + destination: + server: https://kubernetes.default.svc + namespace: kube-system + syncPolicy: + automated: + prune: true + selfHeal: true diff --git a/k8s/argocd/apps/10-storage-observability.yaml b/k8s/argocd/apps/10-storage-observability.yaml new file mode 100644 index 0000000..76364fd --- /dev/null +++ b/k8s/argocd/apps/10-storage-observability.yaml @@ -0,0 +1,135 @@ +# Wave 1 — MinIO (operator + tenant), Longhorn policy, Prometheus stack. +# Helm charts pull from public repos; values come from the git repo via a +# second "ref: values" source (ArgoCD multi-source pattern). +apiVersion: argoproj.io/v1alpha1 +kind: Application +metadata: + name: minio-operator + namespace: argocd + annotations: + argocd.argoproj.io/sync-wave: "1" +spec: + project: homelab + sources: + - repoURL: https://charts.min.io/ + chart: operator + targetRevision: "*" + helm: + valueFiles: + - $values/k8s/infrastructure/minio/minio-operator-values.yaml + - repoURL: http://forgejo.riotpiao.com:3000/riotpiao.com/homelab.git + targetRevision: main + ref: values + destination: + server: https://kubernetes.default.svc + namespace: storage + syncPolicy: + automated: + prune: true + selfHeal: true + syncOptions: + - CreateNamespace=true +--- +# Tenant + buckets + replication are raw CRs (MinIO Tenant CRD from operator). +apiVersion: argoproj.io/v1alpha1 +kind: Application +metadata: + name: minio-tenant + namespace: argocd + annotations: + argocd.argoproj.io/sync-wave: "1" +spec: + project: homelab + source: + repoURL: http://forgejo.riotpiao.com:3000/riotpiao.com/homelab.git + targetRevision: main + path: k8s/infrastructure/minio + destination: + server: https://kubernetes.default.svc + namespace: storage + syncPolicy: + automated: + prune: true + selfHeal: true + syncOptions: + - CreateNamespace=true +--- +# Longhorn itself is substrate (bootstrap-installed); this app manages only its +# ServiceMonitor / policy manifests. +apiVersion: argoproj.io/v1alpha1 +kind: Application +metadata: + name: longhorn-config + namespace: argocd + annotations: + argocd.argoproj.io/sync-wave: "1" +spec: + project: homelab + source: + repoURL: http://forgejo.riotpiao.com:3000/riotpiao.com/homelab.git + targetRevision: main + path: k8s/infrastructure/longhorn + destination: + server: https://kubernetes.default.svc + namespace: longhorn-system + syncPolicy: + automated: + prune: true + selfHeal: true +--- +apiVersion: argoproj.io/v1alpha1 +kind: Application +metadata: + name: prometheus + namespace: argocd + annotations: + argocd.argoproj.io/sync-wave: "1" +spec: + project: homelab + sources: + - repoURL: https://prometheus-community.github.io/helm-charts + chart: kube-prometheus-stack + targetRevision: "*" + helm: + valueFiles: + - $values/k8s/platform/monitoring/prometheus-values.yaml + - repoURL: http://forgejo.riotpiao.com:3000/riotpiao.com/homelab.git + targetRevision: main + ref: values + destination: + server: https://kubernetes.default.svc + namespace: monitoring + syncPolicy: + automated: + prune: true + selfHeal: true + syncOptions: + - CreateNamespace=true + - ServerSideApply=true +--- +apiVersion: argoproj.io/v1alpha1 +kind: Application +metadata: + name: blackbox-exporter + namespace: argocd + annotations: + argocd.argoproj.io/sync-wave: "1" +spec: + project: homelab + sources: + - repoURL: https://prometheus-community.github.io/helm-charts + chart: prometheus-blackbox-exporter + targetRevision: "~11" + helm: + valueFiles: + - $values/k8s/platform/monitoring/blackbox-exporter-values.yaml + - repoURL: http://forgejo.riotpiao.com:3000/riotpiao.com/homelab.git + targetRevision: main + ref: values + destination: + server: https://kubernetes.default.svc + namespace: monitoring + syncPolicy: + automated: + prune: true + selfHeal: true diff --git a/k8s/argocd/apps/20-logging.yaml b/k8s/argocd/apps/20-logging.yaml new file mode 100644 index 0000000..fbd5fdb --- /dev/null +++ b/k8s/argocd/apps/20-logging.yaml @@ -0,0 +1,87 @@ +# Wave 2 — Loki / Grafana / Promtail (Grafana Helm charts). +# NOTE: loki-values / grafana-values reference secrets (S3 creds, admin password) +# that helmfile used to inject via --set. Under ArgoCD these come from the +# *.enc.yaml SOPS files in the same dir via the SOPS plugin — verify the plugin +# is configured before first sync, or these will render with empty secrets. +apiVersion: argoproj.io/v1alpha1 +kind: Application +metadata: + name: loki + namespace: argocd + annotations: + argocd.argoproj.io/sync-wave: "2" +spec: + project: homelab + sources: + - repoURL: https://grafana.github.io/helm-charts + chart: loki + targetRevision: "*" + helm: + valueFiles: + - $values/k8s/platform/logging/loki-values.yaml + - repoURL: http://forgejo.riotpiao.com:3000/riotpiao.com/homelab.git + targetRevision: main + ref: values + destination: + server: https://kubernetes.default.svc + namespace: logging + syncPolicy: + automated: + prune: true + selfHeal: true + syncOptions: + - CreateNamespace=true +--- +apiVersion: argoproj.io/v1alpha1 +kind: Application +metadata: + name: grafana + namespace: argocd + annotations: + argocd.argoproj.io/sync-wave: "2" +spec: + project: homelab + sources: + - repoURL: https://grafana.github.io/helm-charts + chart: grafana + targetRevision: "*" + helm: + valueFiles: + - $values/k8s/platform/logging/grafana-values.yaml + - repoURL: http://forgejo.riotpiao.com:3000/riotpiao.com/homelab.git + targetRevision: main + ref: values + destination: + server: https://kubernetes.default.svc + namespace: logging + syncPolicy: + automated: + prune: true + selfHeal: true +--- +apiVersion: argoproj.io/v1alpha1 +kind: Application +metadata: + name: promtail + namespace: argocd + annotations: + argocd.argoproj.io/sync-wave: "2" +spec: + project: homelab + sources: + - repoURL: https://grafana.github.io/helm-charts + chart: promtail + targetRevision: "*" + helm: + valueFiles: + - $values/k8s/platform/logging/promtail-values.yaml + - repoURL: http://forgejo.riotpiao.com:3000/riotpiao.com/homelab.git + targetRevision: main + ref: values + destination: + server: https://kubernetes.default.svc + namespace: logging + syncPolicy: + automated: + prune: true + selfHeal: true diff --git a/k8s/argocd/apps/30-security.yaml b/k8s/argocd/apps/30-security.yaml new file mode 100644 index 0000000..07fb1a6 --- /dev/null +++ b/k8s/argocd/apps/30-security.yaml @@ -0,0 +1,102 @@ +# Wave 3 — Vault + Authentik (identity), plus IAM raw jobs and the Forgejo +# runner. Authentik/Vault values reference SOPS-managed secrets (see *.enc.yaml +# in k8s/security/iam) resolved by the ArgoCD SOPS plugin at sync time. +apiVersion: argoproj.io/v1alpha1 +kind: Application +metadata: + name: vault + namespace: argocd + annotations: + argocd.argoproj.io/sync-wave: "3" +spec: + project: homelab + sources: + - repoURL: https://helm.releases.hashicorp.com + chart: vault + targetRevision: "*" + helm: + valueFiles: + - $values/k8s/security/iam/vault-values.yaml + - repoURL: http://forgejo.riotpiao.com:3000/riotpiao.com/homelab.git + targetRevision: main + ref: values + destination: + server: https://kubernetes.default.svc + namespace: iam + syncPolicy: + automated: + prune: true + selfHeal: true + syncOptions: + - CreateNamespace=true +--- +apiVersion: argoproj.io/v1alpha1 +kind: Application +metadata: + name: authentik + namespace: argocd + annotations: + argocd.argoproj.io/sync-wave: "3" +spec: + project: homelab + sources: + - repoURL: https://charts.goauthentik.io + chart: authentik + targetRevision: "*" + helm: + valueFiles: + - $values/k8s/security/iam/authentik-values.yaml + - repoURL: http://forgejo.riotpiao.com:3000/riotpiao.com/homelab.git + targetRevision: main + ref: values + destination: + server: https://kubernetes.default.svc + namespace: iam + syncPolicy: + automated: + prune: true + selfHeal: true +--- +# Raw IAM manifests: key-rotation cronjob + authentik migration job. +apiVersion: argoproj.io/v1alpha1 +kind: Application +metadata: + name: iam-jobs + namespace: argocd + annotations: + argocd.argoproj.io/sync-wave: "3" +spec: + project: homelab + source: + repoURL: http://forgejo.riotpiao.com:3000/riotpiao.com/homelab.git + targetRevision: main + path: k8s/security/iam + destination: + server: https://kubernetes.default.svc + namespace: iam + syncPolicy: + automated: + prune: true + selfHeal: true +--- +# Forgejo runner (local chart). Forgejo itself is Phase 0 (bootstrap). +apiVersion: argoproj.io/v1alpha1 +kind: Application +metadata: + name: forgejo-runner + namespace: argocd + annotations: + argocd.argoproj.io/sync-wave: "3" +spec: + project: homelab + source: + repoURL: http://forgejo.riotpiao.com:3000/riotpiao.com/homelab.git + targetRevision: main + path: k8s/security/ci-cd/charts/forgejo-runner + destination: + server: https://kubernetes.default.svc + namespace: cicd + syncPolicy: + automated: + prune: true + selfHeal: true diff --git a/k8s/argocd/apps/40-data.yaml b/k8s/argocd/apps/40-data.yaml new file mode 100644 index 0000000..899c50f --- /dev/null +++ b/k8s/argocd/apps/40-data.yaml @@ -0,0 +1,23 @@ +# Wave 4 — Database schemas + init jobs. The CNPG operator and the ddb-cluster +# itself are Phase 0 (bootstrap); this app manages the additional schemas and +# the one-shot init job that seed databases for Authentik / Temporal / Vault. +apiVersion: argoproj.io/v1alpha1 +kind: Application +metadata: + name: data-schemas + namespace: argocd + annotations: + argocd.argoproj.io/sync-wave: "4" +spec: + project: homelab + source: + repoURL: http://forgejo.riotpiao.com:3000/riotpiao.com/homelab.git + targetRevision: main + path: k8s/data + destination: + server: https://kubernetes.default.svc + namespace: ddb + syncPolicy: + automated: + prune: true + selfHeal: true diff --git a/k8s/argocd/apps/50-messaging.yaml b/k8s/argocd/apps/50-messaging.yaml new file mode 100644 index 0000000..e5d82c7 --- /dev/null +++ b/k8s/argocd/apps/50-messaging.yaml @@ -0,0 +1,111 @@ +# Wave 5 — Kafka (Strimzi operator + cluster CR), Redis, and the SQS-like +# queue services. Strimzi/Redis are public Helm charts; kafka-cluster/queue-crd/ +# management-service are local charts (rendered from their own Chart.yaml). +apiVersion: argoproj.io/v1alpha1 +kind: Application +metadata: + name: strimzi-operator + namespace: argocd + annotations: + argocd.argoproj.io/sync-wave: "5" +spec: + project: homelab + source: + repoURL: https://strimzi.io/charts/ + chart: strimzi-kafka-operator + targetRevision: 0.46.0 + helm: + releaseName: strimzi-operator + destination: + server: https://kubernetes.default.svc + namespace: sqs + syncPolicy: + automated: + prune: true + selfHeal: true + syncOptions: + - CreateNamespace=true +--- +apiVersion: argoproj.io/v1alpha1 +kind: Application +metadata: + name: kmsvc-redis + namespace: argocd + annotations: + argocd.argoproj.io/sync-wave: "5" +spec: + project: homelab + source: + repoURL: https://charts.bitnami.com/bitnami + chart: redis + targetRevision: 20.6.0 + destination: + server: https://kubernetes.default.svc + namespace: sqs + syncPolicy: + automated: + prune: true + selfHeal: true +--- +apiVersion: argoproj.io/v1alpha1 +kind: Application +metadata: + name: kafka-cluster + namespace: argocd + annotations: + argocd.argoproj.io/sync-wave: "6" +spec: + project: homelab + source: + repoURL: http://forgejo.riotpiao.com:3000/riotpiao.com/homelab.git + targetRevision: main + path: k8s/applications/sqs/charts/kafka-cluster + destination: + server: https://kubernetes.default.svc + namespace: sqs + syncPolicy: + automated: + prune: true + selfHeal: true +--- +apiVersion: argoproj.io/v1alpha1 +kind: Application +metadata: + name: queue-crd + namespace: argocd + annotations: + argocd.argoproj.io/sync-wave: "6" +spec: + project: homelab + source: + repoURL: http://forgejo.riotpiao.com:3000/riotpiao.com/homelab.git + targetRevision: main + path: k8s/applications/sqs/charts/queue-crd + destination: + server: https://kubernetes.default.svc + namespace: sqs + syncPolicy: + automated: + prune: true + selfHeal: true +--- +apiVersion: argoproj.io/v1alpha1 +kind: Application +metadata: + name: management-service + namespace: argocd + annotations: + argocd.argoproj.io/sync-wave: "7" +spec: + project: homelab + source: + repoURL: http://forgejo.riotpiao.com:3000/riotpiao.com/homelab.git + targetRevision: main + path: k8s/applications/sqs/charts/management-service + destination: + server: https://kubernetes.default.svc + namespace: sqs + syncPolicy: + automated: + prune: true + selfHeal: true diff --git a/k8s/argocd/apps/60-applications.yaml b/k8s/argocd/apps/60-applications.yaml new file mode 100644 index 0000000..bcb116c --- /dev/null +++ b/k8s/argocd/apps/60-applications.yaml @@ -0,0 +1,107 @@ +# Wave 8 — end-user workloads: Temporal, Portainer, and the two network +# helpers (cloudflared tunnel, duckdns updater) that are already running. +# Experimental dirs (llm, forge, dev-tools, shadowsocks) are intentionally +# NOT included yet — add them here once they're production-ready. +apiVersion: argoproj.io/v1alpha1 +kind: Application +metadata: + name: temporal + namespace: argocd + annotations: + argocd.argoproj.io/sync-wave: "8" +spec: + project: homelab + sources: + - repoURL: https://go.temporal.io/helm-charts + chart: temporal + targetRevision: "*" + helm: + valueFiles: + - $values/k8s/applications/temporal/temporal-values.yaml + - repoURL: http://forgejo.riotpiao.com:3000/riotpiao.com/homelab.git + targetRevision: main + ref: values + destination: + server: https://kubernetes.default.svc + namespace: temporal + syncPolicy: + automated: + prune: true + selfHeal: true + syncOptions: + - CreateNamespace=true +--- +apiVersion: argoproj.io/v1alpha1 +kind: Application +metadata: + name: portainer + namespace: argocd + annotations: + argocd.argoproj.io/sync-wave: "8" +spec: + project: homelab + sources: + - repoURL: https://portainer.github.io/k8s/ + chart: portainer + targetRevision: "*" + helm: + valueFiles: + - $values/k8s/applications/portainer/portainer-values.yaml + - repoURL: http://forgejo.riotpiao.com:3000/riotpiao.com/homelab.git + targetRevision: main + ref: values + destination: + server: https://kubernetes.default.svc + namespace: dashboard + syncPolicy: + automated: + prune: true + selfHeal: true + syncOptions: + - CreateNamespace=true +--- +apiVersion: argoproj.io/v1alpha1 +kind: Application +metadata: + name: cloudflared + namespace: argocd + annotations: + argocd.argoproj.io/sync-wave: "8" +spec: + project: homelab + source: + repoURL: http://forgejo.riotpiao.com:3000/riotpiao.com/homelab.git + targetRevision: main + path: k8s/applications/cloudflared + destination: + server: https://kubernetes.default.svc + namespace: cloudflared + syncPolicy: + automated: + prune: true + selfHeal: true + syncOptions: + - CreateNamespace=true +--- +apiVersion: argoproj.io/v1alpha1 +kind: Application +metadata: + name: duckdns + namespace: argocd + annotations: + argocd.argoproj.io/sync-wave: "8" +spec: + project: homelab + source: + repoURL: http://forgejo.riotpiao.com:3000/riotpiao.com/homelab.git + targetRevision: main + path: k8s/applications/duckdns + destination: + server: https://kubernetes.default.svc + namespace: duckdns + syncPolicy: + automated: + prune: true + selfHeal: true + syncOptions: + - CreateNamespace=true diff --git a/k8s/argocd/bootstrap/BOOTSTRAP.md b/k8s/argocd/bootstrap/BOOTSTRAP.md new file mode 100644 index 0000000..67a39c9 --- /dev/null +++ b/k8s/argocd/bootstrap/BOOTSTRAP.md @@ -0,0 +1,116 @@ +# Cluster bootstrap & CD — two scopes + +The GitOps repo is hosted on the cluster's own Forgejo, so ArgoCD cannot pull it +until Forgejo exists. There are two distinct workflows — pick the one that +matches your situation. + +``` +Scope 1 — from scratch cold cluster, nothing running yet → full bootstrap +Scope 2 — iterating CD cluster + Forgejo + ArgoCD are up → just git push +``` + +--- + +## Scope 1 — Cluster from scratch (cold bootstrap) + +Strict ordering, because each layer depends on the previous one existing. + +``` +Talos + Cilium CNI Terraform (nodes) — cluster reachable +Substrate cert-manager, ingress-nginx, reloader — Terraform helm_releases + Longhorn, ArgoCD — imperative install +Phase 0 (git-independent) CNPG + ddb-cluster + redis + Forgejo — manual, below +Seed git push repo into Forgejo +Phase 1 app-of-apps root — ArgoCD deploys the rest +``` + +Run every command from a local checkout with `KUBECONFIG` pointed at the cluster. + +### Phase 0 — bootstrap Forgejo and its data plane (git-independent) + +```bash +# 1. CNPG operator (public Helm) + its CRDs. +kubectl apply -f k8s/argocd/bootstrap/cnpg-operator.yaml +argocd app sync cnpg-operator +# CNPG ships CRDs in the chart's crds/ folder, which ArgoCD's helm-template does +# NOT install. If the ddb-cluster apply below fails with "no matches for kind +# Cluster", install them once: +# kubectl apply --server-side -f \ +# https://raw.githubusercontent.com/cloudnative-pg/cloudnative-pg/release-1.24/releases/cnpg-1.24.1.yaml + +# 2. Namespaces first. cicd MUST be labelled privileged (DinD/runner needs it); +# the Forgejo app deliberately does NOT create it. +kubectl create namespace ddb --dry-run=client -o yaml | kubectl apply -f - +kubectl create namespace cicd --dry-run=client -o yaml | kubectl apply -f - +kubectl label namespace cicd pod-security.kubernetes.io/enforce=privileged --overwrite + +# 3. Postgres cluster + Forgejo database + Redis (raw manifests, local checkout). +kubectl apply -f k8s/data/ddb-cluster.yaml +kubectl apply -f k8s/data/forgejo-database.yaml +kubectl apply -f k8s/security/ci-cd/forgejo-redis.yaml + +# 4. Copy the CNPG-generated app password into cicd (Secrets are ns-scoped). +kubectl get secret ddb-cluster-app -n ddb -o yaml \ + | sed 's/namespace: ddb/namespace: cicd/' \ + | kubectl apply -n cicd -f - + +# 5. Forgejo (public Helm, values inlined — git-independent). +kubectl apply -f k8s/argocd/bootstrap/forgejo.yaml +argocd app sync forgejo +``` + +### Seed + Phase 1 + +```bash +# 6. Push this repo to the freshly-created Forgejo so Phase 1 has a source. +git remote add forgejo http://forgejo.riotpiao.com:3000/riotpiao.com/homelab.git +git push forgejo main + +# 7. Deploy everything else from git — one sync brings up the whole cluster. +kubectl apply -f k8s/argocd/projects/homelab-project.yaml # AppProject +kubectl apply -k k8s/argocd/root # app-of-apps root +argocd app sync homelab-root +``` + +`homelab-root` renders every Application under `k8s/argocd/apps/` and syncs them +in sync-wave order (networking → storage/observability → logging → security → +data → messaging → applications). + +--- + +## Scope 2 — Iterating CD (day-2, cluster already up) + +The app-of-apps and its children already exist and reconcile from Forgejo. To +change anything, you do NOT re-run the bootstrap — you just push: + +```bash +# edit manifests under k8s/** +git add -A && git commit -m "..." +git push # to Forgejo main (origin) +# ArgoCD auto-syncs (child apps have syncPolicy.automated); to force it: +argocd app sync homelab-root +``` + +- Adding a new service = add an Application manifest under `k8s/argocd/apps/` + and its manifests under the path it references, then push. The app-of-apps + picks it up on next sync. +- Changing a Helm value = edit the values file the Application points at + (`$values/...`), push. +- Forgejo itself is Phase-0 / bootstrap (manual sync only) — a bad CI commit + must not be able to break the system CI depends on. + +--- + +## Notes / prerequisites + +- **Secrets:** several values files (loki S3, grafana admin, authentik, vault) + expect secrets that helmfile used to inject via `--set`. Under ArgoCD these + come from the `*.enc.yaml` SOPS files via the ArgoCD SOPS plugin — confirm the + plugin is configured before syncing waves 2–3, or those charts render with + empty secrets. +- **Substrate** (cert-manager, ingress-nginx, reloader) is installed by Terraform + as bootstrap Helm releases, not ArgoCD. Cilium CNI, Longhorn, and ArgoCD + itself are cluster-bootstrap installs. +- **Single storage node:** only `talos-cp-1` runs workloads/storage, so stateful + services are single-instance (`ddb-cluster` = 1). See the repo `USAGE.md` and + root `CLAUDE.md` topology section. diff --git a/k8s/argocd/bootstrap/cnpg-operator.yaml b/k8s/argocd/bootstrap/cnpg-operator.yaml index ce70bcf..df75e8c 100644 --- a/k8s/argocd/bootstrap/cnpg-operator.yaml +++ b/k8s/argocd/bootstrap/cnpg-operator.yaml @@ -10,7 +10,7 @@ spec: source: repoURL: https://cloudnative-pg.github.io/charts chart: cloudnative-pg - targetRevision: "*" + targetRevision: "~0.20" destination: server: https://kubernetes.default.svc namespace: ddb diff --git a/k8s/argocd/bootstrap/forgejo.yaml b/k8s/argocd/bootstrap/forgejo.yaml index 28987cc..4d36c0a 100644 --- a/k8s/argocd/bootstrap/forgejo.yaml +++ b/k8s/argocd/bootstrap/forgejo.yaml @@ -140,7 +140,11 @@ spec: server: https://kubernetes.default.svc namespace: cicd syncPolicy: - syncOptions: - - CreateNamespace=true + # NO CreateNamespace — cicd must be pre-created and labelled + # pod-security.kubernetes.io/enforce=privileged (DinD/runner needs it); + # ArgoCD's CreateNamespace would make it with the cluster-default baseline. + # The Phase 0 runbook creates+labels cicd before this app is applied. + # # NO automated sync — Forgejo is what CI uses to push commits; auto-sync # would let a bad CI commit break the system CI depends on. Manual only. + syncOptions: [] diff --git a/k8s/argocd/projects/homelab-project.yaml b/k8s/argocd/projects/homelab-project.yaml index 77cc44f..33eb9a6 100644 --- a/k8s/argocd/projects/homelab-project.yaml +++ b/k8s/argocd/projects/homelab-project.yaml @@ -11,9 +11,19 @@ metadata: spec: description: Homelab GitOps — single-repo, in-cluster destinations only sourceRepos: - - https://forgejo.riotpiao.com/riotpiao.com/homelab.git + - http://forgejo.riotpiao.com:3000/riotpiao.com/homelab.git + # Public Helm chart repos referenced by k8s/argocd/apps/* and bootstrap/* - https://cloudnative-pg.github.io/charts - https://dl.gitea.com/charts/ + - https://charts.min.io/ + - https://prometheus-community.github.io/helm-charts + - https://grafana.github.io/helm-charts + - https://helm.releases.hashicorp.com + - https://charts.goauthentik.io + - https://strimzi.io/charts/ + - https://charts.bitnami.com/bitnami + - https://go.temporal.io/helm-charts + - https://portainer.github.io/k8s/ destinations: - server: https://kubernetes.default.svc namespace: "*" diff --git a/k8s/argocd/root/homelab-root.yaml b/k8s/argocd/root/homelab-root.yaml new file mode 100644 index 0000000..f195081 --- /dev/null +++ b/k8s/argocd/root/homelab-root.yaml @@ -0,0 +1,28 @@ +# Phase 1 entry point — the app-of-apps root. +# Apply once (kubectl apply -k k8s/argocd/root) then sync it; it renders every +# Application manifest under k8s/argocd/apps/ and those deploy the whole cluster +# in sync-wave order. Requires Forgejo to be serving the repo (Phase 0 first). +apiVersion: argoproj.io/v1alpha1 +kind: Application +metadata: + name: homelab-root + namespace: argocd + annotations: + argocd.argoproj.io/sync-wave: "0" +spec: + project: homelab + source: + repoURL: http://forgejo.riotpiao.com:3000/riotpiao.com/homelab.git + targetRevision: main + path: k8s/argocd/apps + directory: + recurse: false + destination: + server: https://kubernetes.default.svc + namespace: argocd + syncPolicy: + automated: + prune: true + selfHeal: true + syncOptions: + - CreateNamespace=true diff --git a/k8s/argocd/root/kustomization.yaml b/k8s/argocd/root/kustomization.yaml index ac0078d..b93f41a 100644 --- a/k8s/argocd/root/kustomization.yaml +++ b/k8s/argocd/root/kustomization.yaml @@ -3,13 +3,8 @@ kind: Kustomization metadata: name: homelab-root -# Root Application orchestration -# Includes all layer Applications in order (sync-wave) - +# Phase 1 app-of-apps entry point. +# `kubectl apply -k k8s/argocd/root` creates the homelab-root Application, which +# then renders every child under k8s/argocd/apps/ and deploys the cluster. resources: - - ../apps/layer-1-infrastructure.yaml - - ../apps/layer-2-bootstrap.yaml - - ../apps/layer-3-platform.yaml - - ../apps/layer-4-security.yaml - - ../apps/layer-5-applications.yaml - - ../apps/layer-6-data.yaml + - homelab-root.yaml