flux(seed): split monolithic seed KS into per-app seed-<app> KSes
ci/woodpecker/manual/rebuild-k8s Pipeline failed
ci/woodpecker/cron/e2e Pipeline failed
ci/woodpecker/cron/security-scan Pipeline was successful

Each `<app>` KS now dependsOn its own `seed-<app>` instead of the
shared `seed` KS, so a slow sub-tree (immich-library-seed at ~26m)
no longer blocks unrelated apps. Audiobookshelf / paperless /
music-assistant / Authentik unblock at their own seed-Job
completion (T+~13–17 vs T+~38–39 in pipeline #884).

Old `seed` KS is suspended + prune:false during the migration
window so SSA-driven ownership transfer to the new KSes doesn't
risk pruning Cluster CRs (which are not prune:disabled-annotated).
A follow-up commit deletes seed.yaml + seed/kustomization.yaml.

bootstrap.sh wait-apps drops the monolithic `wait_kustomization
seed`; per-app waits absorb the seed runtime (immich 1800s,
audiobookshelf 900s, paperless/authentik 600s, music-assistant
300s) and a `seed-influxdb` wait (600s) covers the InfluxDB HR
+ token Jobs since InfluxDB has no separate top-level KS.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-06 07:46:44 +02:00
co-authored by Claude Opus 4.7
parent b4eaa5e2e4
commit bfc885762c
13 changed files with 216 additions and 36 deletions
+14 -14
View File
@@ -286,22 +286,22 @@ if phase_runs wait-apps; then
return 1
}
# The seed phase populates every CNPG database and every migrating
# PVC from legacy hosts before any app Kustomization reconciles.
# Wall-clock dominated by immich-library-seed (~250 GiB rsync over
# LAN, ~30-45 min). Every app KS dependsOn `seed`, so the per-app
# waits below should be near-instant once seed lands Ready.
wait_kustomization seed "Seed phase (DB + PVC populate from legacy)" 1440
# Per-app seed KSes (`seed-<app>`) populate each CNPG database and
# each migrating PVC from legacy hosts. Each downstream `<app>` KS
# gates only on its own `seed-<app>`, 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-<app> runtime and the app rollout.
# 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 authentik "Authentik" 60
wait_kustomization monitoring "kube-prometheus-stack (Loki + Prom + AM + Grafana)" 180
wait_kustomization music-assistant "Music Assistant" 60
wait_kustomization paperless "Paperless" 60
wait_kustomization home-assistant "Home Assistant (HAOS backup → native restore)" 180
wait_kustomization audiobookshelf "Audiobookshelf" 60
wait_kustomization immich "Immich" 60
wait_kustomization apps "apps" 90
wait_kustomization seed-influxdb "InfluxDB seed (HR install + token Jobs)" 600
wait_kustomization authentik "Authentik (incl. ak-pg seed)" 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 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 for cert-manager to finish issuing every Certificate. Kustomization
# Ready only means the Ingress + Certificate manifests are applied; cert-
@@ -23,4 +23,4 @@ spec:
- name: infrastructure
- name: infrastructure-crds
- name: infrastructure-ceph-cluster
- name: seed
- name: seed-audiobookshelf
+1 -1
View File
@@ -21,4 +21,4 @@ spec:
- name: infrastructure
- name: infrastructure-crds
- name: infrastructure-ceph-cluster
- name: seed
- name: seed-authentik
+1 -1
View File
@@ -23,4 +23,4 @@ spec:
- name: infrastructure
- name: infrastructure-crds
- name: infrastructure-ceph-cluster
- name: seed
- name: seed-immich
@@ -23,4 +23,4 @@ spec:
- name: infrastructure
- name: infrastructure-crds
- name: infrastructure-ceph-cluster
- name: seed
- name: seed-music-assistant
+1 -1
View File
@@ -23,4 +23,4 @@ spec:
- name: infrastructure
- name: infrastructure-crds
- name: infrastructure-ceph-cluster
- name: seed
- name: seed-paperless
@@ -0,0 +1,30 @@
apiVersion: kustomize.toolkit.fluxcd.io/v1
kind: Kustomization
metadata:
name: seed-audiobookshelf
namespace: flux-system
spec:
# Per-app slice of the former monolithic `seed` KS — owns the
# audiobookshelf library/metadata PVCs and the rsync seed Job from the
# legacy audiobookshelf VM. The downstream `audiobookshelf` KS depends
# only on this, so it's no longer blocked by the slowest sibling
# (immich-library-seed at ~26m).
interval: 10m
retryInterval: 2m
# ~5m observed for 70.5 GiB rsync; buffer for cold cache / network.
timeout: 1h
sourceRef:
kind: GitRepository
name: flux-system
path: ./kubernetes/seed/audiobookshelf
prune: true
wait: true
decryption:
provider: sops
secretRef:
name: sops-age
dependsOn:
- name: infrastructure
- name: infrastructure-crds
- name: infrastructure-ceph-cluster
- name: infrastructure-cnpg-barman
@@ -0,0 +1,33 @@
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, ScheduledBackup, and the pg_dump→pg_restore
# seed Job from authentik-db-1.srv.renner.uno. 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:
provider: sops
secretRef:
name: sops-age
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)"
@@ -0,0 +1,35 @@
apiVersion: kustomize.toolkit.fluxcd.io/v1
kind: Kustomization
metadata:
name: seed-immich
namespace: flux-system
spec:
# Per-app slice of the former monolithic `seed` KS — owns the im-pg
# CNPG Cluster, ObjectStore, ScheduledBackup, the pg_restore seed Job,
# and the long library-seed rsync (~250 GiB, the wall-time pole of
# the rebuild). Only the downstream `immich` KS gates on this; other
# apps are no longer blocked by it.
interval: 10m
retryInterval: 2m
# Long enough for the worst-case immich-library rsync (~30–45 min).
timeout: 4h
sourceRef:
kind: GitRepository
name: flux-system
path: ./kubernetes/seed/immich
prune: true
wait: true
decryption:
provider: sops
secretRef:
name: sops-age
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)"
@@ -0,0 +1,28 @@
apiVersion: kustomize.toolkit.fluxcd.io/v1
kind: Kustomization
metadata:
name: seed-influxdb
namespace: flux-system
spec:
# Per-app slice of the former monolithic `seed` KS — owns the InfluxDB
# HelmRelease itself plus the legacy-token + ha-token bootstrap Jobs.
# InfluxDB has no separate top-level app KS; this is its full lifecycle
# owner during the migration window.
interval: 10m
retryInterval: 2m
timeout: 30m
sourceRef:
kind: GitRepository
name: flux-system
path: ./kubernetes/seed/influxdb
prune: true
wait: true
decryption:
provider: sops
secretRef:
name: sops-age
dependsOn:
- name: infrastructure
- name: infrastructure-crds
- name: infrastructure-ceph-cluster
- name: infrastructure-cnpg-barman
@@ -0,0 +1,28 @@
apiVersion: kustomize.toolkit.fluxcd.io/v1
kind: Kustomization
metadata:
name: seed-music-assistant
namespace: flux-system
spec:
# Per-app slice of the former monolithic `seed` KS — owns the
# music-assistant data PVC and the ssh+tar seed Job from the legacy
# music-assistant LXC. The downstream `music-assistant` KS depends
# only on this.
interval: 10m
retryInterval: 2m
timeout: 30m
sourceRef:
kind: GitRepository
name: flux-system
path: ./kubernetes/seed/music-assistant
prune: true
wait: true
decryption:
provider: sops
secretRef:
name: sops-age
dependsOn:
- name: infrastructure
- name: infrastructure-crds
- name: infrastructure-ceph-cluster
- name: infrastructure-cnpg-barman
@@ -0,0 +1,33 @@
apiVersion: kustomize.toolkit.fluxcd.io/v1
kind: Kustomization
metadata:
name: seed-paperless
namespace: flux-system
spec:
# Per-app slice of the former monolithic `seed` KS — owns the pprl-pg
# CNPG Cluster, ObjectStore, ScheduledBackup, the pg_restore seed Job,
# and the data/media rsync seed Job from paperless.srv.renner.uno.
# The downstream `paperless` KS depends only on this.
interval: 10m
retryInterval: 2m
timeout: 30m
sourceRef:
kind: GitRepository
name: flux-system
path: ./kubernetes/seed/paperless
prune: true
wait: true
decryption:
provider: sops
secretRef:
name: sops-age
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)"
+10 -17
View File
@@ -4,21 +4,22 @@ metadata:
name: seed
namespace: flux-system
spec:
# Migration phase: pulls data from legacy hosts into in-cluster CNPG
# databases and PVCs so app Kustomizations can reconcile against
# populated state. Lives between infrastructure and apps. Removed
# entirely once all services have cut over from legacy.
# **Deprecated.** Split into per-app `seed-<app>` KSes so a slow
# sub-tree (immich-library-seed at ~26m) no longer blocks unrelated
# apps. This object is kept only so its inventory can be pruned
# cleanly by a follow-up commit; until then it's suspended and
# prune-disabled so resources whose ownership has migrated to the
# new KSes aren't torn down.
suspend: true
interval: 10m
retryInterval: 2m
# Long enough to cover the slowest seed (immich library: ~250 GiB
# rsync over LAN ~ 30-45 min) plus all the smaller seeds in parallel.
timeout: 4h
timeout: 5m
sourceRef:
kind: GitRepository
name: flux-system
path: ./kubernetes/seed
prune: true
wait: true
prune: false
wait: false
decryption:
provider: sops
secretRef:
@@ -28,11 +29,3 @@ spec:
- name: infrastructure-crds
- name: infrastructure-ceph-cluster
- name: infrastructure-cnpg-barman
# kstatus already handles Job (succeeded == 1) by default. CNPG Cluster
# readiness needs an explicit expression because kstatus doesn't know
# the Cluster CRD's status semantics.
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)"