diff --git a/kubernetes/seed/RECOVERY.md b/kubernetes/RECOVERY.md similarity index 99% rename from kubernetes/seed/RECOVERY.md rename to kubernetes/RECOVERY.md index 67729aaa..057ee9d7 100644 --- a/kubernetes/seed/RECOVERY.md +++ b/kubernetes/RECOVERY.md @@ -135,7 +135,7 @@ Notes: On a real cold rebuild, Flux applies the edited `cluster.yaml` automatically (commit + push to the branch Flux tracks, or `flux reconcile kustomization -seed-authentik --with-source`). For a targeted manual recovery you can also +authentik --with-source`). For a targeted manual recovery you can also `kubectl apply -f cluster.yaml` directly. ```sh diff --git a/kubernetes/seed/authentik/barman-creds-externalsecret.yaml b/kubernetes/apps/authentik/barman-creds-externalsecret.yaml similarity index 100% rename from kubernetes/seed/authentik/barman-creds-externalsecret.yaml rename to kubernetes/apps/authentik/barman-creds-externalsecret.yaml diff --git a/kubernetes/seed/authentik/cluster.yaml b/kubernetes/apps/authentik/cluster.yaml similarity index 100% rename from kubernetes/seed/authentik/cluster.yaml rename to kubernetes/apps/authentik/cluster.yaml diff --git a/kubernetes/seed/authentik/hetzner-creds-externalsecret.yaml b/kubernetes/apps/authentik/hetzner-creds-externalsecret.yaml similarity index 100% rename from kubernetes/seed/authentik/hetzner-creds-externalsecret.yaml rename to kubernetes/apps/authentik/hetzner-creds-externalsecret.yaml diff --git a/kubernetes/apps/authentik/kustomization.yaml b/kubernetes/apps/authentik/kustomization.yaml index 0841014b..a3b18fb9 100644 --- a/kubernetes/apps/authentik/kustomization.yaml +++ b/kubernetes/apps/authentik/kustomization.yaml @@ -18,3 +18,13 @@ resources: - ldap-outpost-cert.yaml - ldap-outpost-lb.yaml - ldap-outpost-cnp.yaml + # ak-pg CNPG Postgres backend (moved here from the retired seed-authentik KS; + # each carries prune: disabled so ownership transferred without a teardown). + # authentik has no data PVCs — all state lives in ak-pg. This KS gains the + # infrastructure-cnpg-barman dep + CNPG Cluster healthCheckExprs (see + # clusters/homelab/authentik.yaml). + - cluster.yaml + - objectstore.yaml + - scheduled-backup.yaml + - barman-creds-externalsecret.yaml + - hetzner-creds-externalsecret.yaml diff --git a/kubernetes/seed/authentik/objectstore.yaml b/kubernetes/apps/authentik/objectstore.yaml similarity index 100% rename from kubernetes/seed/authentik/objectstore.yaml rename to kubernetes/apps/authentik/objectstore.yaml diff --git a/kubernetes/seed/authentik/scheduled-backup.yaml b/kubernetes/apps/authentik/scheduled-backup.yaml similarity index 100% rename from kubernetes/seed/authentik/scheduled-backup.yaml rename to kubernetes/apps/authentik/scheduled-backup.yaml diff --git a/kubernetes/bootstrap.sh b/kubernetes/bootstrap.sh index c5b3ec9f..0f912fe1 100755 --- a/kubernetes/bootstrap.sh +++ b/kubernetes/bootstrap.sh @@ -323,23 +323,24 @@ if phase_runs wait-apps; then return 1 } - # Per-app seed KSes (`seed-`) populate each CNPG database and - # each migrating PVC from legacy hosts. Each downstream `` KS - # gates only on its own `seed-`, so a slow seed (immich-library - # rsync at ~26 min) no longer blocks the unrelated apps. The per-app - # waits below absorb both the seed- runtime and the app rollout. + # Each app KS now owns its CNPG database (+ any data PVCs) directly — the + # per-app `seed-` KSes that used to bootstrap them were folded into the + # app KSes when the seed layer was retired. Each wait below gates on the app + # KS, whose readiness includes its CNPG cluster coming up (initdb on a fresh + # cluster; a cold-rebuild data restore is the separate RECOVERY.md runbook). + # Timeouts stay generous to cover first-time cluster bootstrap on fresh Ceph. # apps waits on infrastructure-ceph-cluster (Ceph mon/mgr/OSD bring-up # is genuinely 5–10 min on a fresh OSD-wiped cluster). wait_kustomization apps "apps" 90 wait_kustomization influxdb "InfluxDB (HR install + token Jobs)" 600 wait_kustomization woodpecker "Woodpecker CI (incl. wp-pg CNPG backend)" 600 - wait_kustomization authentik "Authentik (incl. ak-pg seed)" 600 + wait_kustomization authentik "Authentik (incl. ak-pg CNPG backend)" 600 wait_kustomization monitoring "kube-prometheus-stack (Loki + Prom + AM + Grafana)" 180 - wait_kustomization music-assistant "Music Assistant (incl. data seed)" 300 - wait_kustomization paperless "Paperless (incl. pprl-pg + data seed)" 600 + wait_kustomization music-assistant "Music Assistant (incl. data PVC)" 300 + wait_kustomization paperless "Paperless (incl. pprl-pg CNPG + data PVCs)" 600 wait_kustomization home-assistant "Home Assistant (HAOS backup → native restore)" 180 - wait_kustomization audiobookshelf "Audiobookshelf (incl. ~70 GiB library seed)" 900 - wait_kustomization immich "Immich (incl. ~26 min library-seed rsync)" 1800 + wait_kustomization audiobookshelf "Audiobookshelf (incl. library/metadata PVCs)" 900 + wait_kustomization immich "Immich (incl. im-pg CNPG + library PVC)" 1800 # Wait for cert-manager to finish issuing every Certificate. Kustomization # Ready only means the Ingress + Certificate manifests are applied; cert- diff --git a/kubernetes/clusters/homelab/authentik.yaml b/kubernetes/clusters/homelab/authentik.yaml index cdde1fbe..6eb5e39e 100644 --- a/kubernetes/clusters/homelab/authentik.yaml +++ b/kubernetes/clusters/homelab/authentik.yaml @@ -4,6 +4,9 @@ metadata: name: authentik namespace: flux-system spec: + # Owns the authentik app plus its ak-pg CNPG Cluster + ObjectStore + + # ScheduledBackup (folded in from the retired seed-authentik KS — the last of + # the seed layer). authentik has no data PVCs; all state lives in ak-pg. interval: 10m retryInterval: 1m timeout: 30m @@ -20,4 +23,9 @@ spec: - name: infrastructure - name: infrastructure-crds - name: infrastructure-ceph-cluster - - name: seed-authentik + - name: infrastructure-cnpg-barman + healthCheckExprs: + - apiVersion: postgresql.cnpg.io/v1 + kind: Cluster + failed: "has(status.phase) && status.phase.startsWith('Failed')" + current: "has(status.phase) && (status.phase == 'Cluster in healthy state' || status.readyInstances > 0)" diff --git a/kubernetes/clusters/homelab/seed-authentik.yaml b/kubernetes/clusters/homelab/seed-authentik.yaml deleted file mode 100644 index 3899db70..00000000 --- a/kubernetes/clusters/homelab/seed-authentik.yaml +++ /dev/null @@ -1,36 +0,0 @@ -apiVersion: kustomize.toolkit.fluxcd.io/v1 -kind: Kustomization -metadata: - name: seed-authentik - namespace: flux-system -spec: - # Per-app slice of the former monolithic `seed` KS — owns the ak-pg - # CNPG Cluster, ObjectStore, and ScheduledBackup. NOTE: the Cluster - # bootstraps via `initdb`, so a cold rebuild comes up with an EMPTY DB - # — barman WAL+base backups (now on Hetzner s3://renner-uno-k8s-cnpg/ak-pg, - # not the decommissioned Garage) are archived but not auto-restored. - # Restoring on rebuild is a manual `initdb`→`recovery` swap; see the - # runbook at kubernetes/seed/RECOVERY.md (issue #190). - # The legacy pg_dump→pg_restore seed Job from authentik-db-1 was - # dropped in 52452e0. The downstream `authentik` KS depends only on this. - interval: 10m - retryInterval: 2m - timeout: 30m - sourceRef: - kind: GitRepository - name: flux-system - path: ./kubernetes/seed/authentik - prune: true - wait: true - # decryption block dropped 2026-07-14: path is sops-free — secrets come - # from OpenBao via ESO (MIGRATION-sops-openbao.md). - dependsOn: - - name: infrastructure - - name: infrastructure-crds - - name: infrastructure-ceph-cluster - - name: infrastructure-cnpg-barman - healthCheckExprs: - - apiVersion: postgresql.cnpg.io/v1 - kind: Cluster - failed: "has(status.phase) && status.phase.startsWith('Failed')" - current: "has(status.phase) && (status.phase == 'Cluster in healthy state' || status.readyInstances > 0)" diff --git a/kubernetes/e2e-test.sh b/kubernetes/e2e-test.sh index 8af151a9..a753d4f5 100755 --- a/kubernetes/e2e-test.sh +++ b/kubernetes/e2e-test.sh @@ -107,7 +107,7 @@ check "3 nodes Ready" \ echo "=== Flux Kustomizations ===" for ks in flux-system infrastructure infrastructure-crds infrastructure-ceph-cluster \ - seed-authentik influxdb \ + influxdb \ apps authentik paperless audiobookshelf woodpecker immich; do check "kustomization/$ks Ready" \ bash -c "kubectl -n flux-system get kustomization $ks \ diff --git a/kubernetes/seed/authentik/kustomization.yaml b/kubernetes/seed/authentik/kustomization.yaml deleted file mode 100644 index b85e5b63..00000000 --- a/kubernetes/seed/authentik/kustomization.yaml +++ /dev/null @@ -1,8 +0,0 @@ -apiVersion: kustomize.config.k8s.io/v1beta1 -kind: Kustomization -resources: - - barman-creds-externalsecret.yaml - - hetzner-creds-externalsecret.yaml - - objectstore.yaml - - cluster.yaml - - scheduled-backup.yaml diff --git a/opentofu/object_storage.tf b/opentofu/object_storage.tf index f73e8405..2e0ac753 100644 --- a/opentofu/object_storage.tf +++ b/opentofu/object_storage.tf @@ -88,7 +88,7 @@ locals { # re-upload. Cap noncurrent-version retention to match the retention # window the app layer already enforces, so old S3 versions don't outlive # the backups that superseded them by more than that window: - # - CNPG ObjectStore retentionPolicy: "30d" (kubernetes/seed/*/objectstore.yaml) + # - CNPG ObjectStore retentionPolicy: "30d" (kubernetes/apps/*/objectstore.yaml) # - Velero Schedule ttl: 720h0m0s = 30d (kubernetes/infrastructure/post-crds/velero-schedules.yaml) # renner-uno-k8s-secrets and renner-uno-tfstate hold small, low-churn # objects (kubeconfig/talosconfig, tfstate) with no existing retention