How this repo uses pvc-plumber š§©
Audience: someone working in talos-argocd-proxmox who needs to add, classify, or debug a
backed-up PVC. Start with pvc-plumber-start-here.md for the concepts.
šļø Repository map (where everything lives)
flowchart TD
subgraph Infra["infrastructure/"]
PP["controllers/pvc-plumber/\n(operator: deployment, RBAC, CRB)"]
VS["storage/volsync/\n(VolSync chart + kopia-maintenance CronJob)"]
VBC["storage/volsync-backup-cluster/\n(ClusterExternalSecret + mover-backend MAP)"]
CNPG["database/cloudnative-pg/\n(Barman ā S3, NOT pvc-plumber)"]
end
subgraph Apps["my-apps/"]
APV["<category>/<app>/pvc.yaml\n(PVC + fuse labels + dataSourceRef)"]
ANS["<app>/namespace.yaml\n(managed-namespace label)"]
POSTHOG["development/posthog/\n(backup-exempt PVCs)"]
end
subgraph Argo["infrastructure/controllers/argocd/apps/"]
ENT["core-dependencies/pvc-plumber-app.yaml (Wave 2)"]
AS["appsets/my-apps-appset.yaml"]
end
OnePW[("1Password\nā External Secrets")] --> VBC
VBC -->|volsync-kopia-repository Secret| Apps
Thing
Path
pvc-plumber operator
infrastructure/controllers/pvc-plumber/ (Deployment, rbac-volsync-writer.yaml = the cluster-wide CRB)
VolSync + Kopia maintenance
infrastructure/storage/volsync/
Shared repo Secret + mover gate
infrastructure/storage/volsync-backup-cluster/ (ClusterExternalSecret, mover-backend MAP)
App PVCs
my-apps/<category>/<app>/pvc.yaml
Argo entrypoint
infrastructure/controllers/argocd/apps/core-dependencies/pvc-plumber-app.yaml (Wave 2)
CNPG databases
infrastructure/database/cloudnative-pg/ (Barman ā S3 ā never pvc-plumber)
PostHog exemption
my-apps/development/posthog/ (backup-exempt PVCs)
Docs
docs/
ā
How to add a new protected PVC (checklist)
flowchart LR
S1[1. PVC manifest\n+ dataSourceRef ā -dst] --> S2[2. namespace:\nmanaged-namespace=true]
S2 --> S3[3. PVC fuse labels:\nenabled + manage-volsync + tier]
S3 --> S4["4. ns has\nvolsync.backube/privileged-movers=true\n(ClusterES materializes repo Secret)"]
S4 --> S5[5. commit + Argo sync]
S5 --> S6[6. verify /audit = already-matches]
S6 --> S7[7. verify first backup Successful]
S7 --> S8[8. restore drill if data matters]
PVC manifest ā storageClassName: longhorn, argocd.argoproj.io/compare-options: ServerSideDiff=false, and dataSourceRef ā ReplicationDestination/<pvc>-dst if you want restore-on-recreate (you almost always do).
Namespace ā add pvc-plumber.io/managed-namespace: "true" and volsync.backube/privileged-movers: "true".
PVC fuse labels ā pvc-plumber.io/enabled: "true", pvc-plumber.io/manage-volsync: "true", pvc-plumber.io/tier: hourly|daily.
Repo Secret ā the volsync.backube/privileged-movers label makes ClusterExternalSecret/volsync-kopia-repository materialize volsync-kopia-repository in the namespace. Verify it exists.
Commit + sync.
Verify /audit shows already-matches / managed-by-pvc-plumber / stale=false.
Verify the first operator backup is Successful (or nextSyncTime is set).
Restore drill if the data matters ā see volsync-storage-recovery.md .
Canonical example to copy: my-apps/ai/open-webui/pvc.yaml. Helm-chart PVCs inject the dsr/labels via
Kustomize patches: (see my-apps/development/gitea/).
š§® How to classify a PVC
flowchart TD
P[New PVC] --> Q1{CNPG database\nvolume?}
Q1 -->|yes| CNPG[[Barman ā S3\nNEVER pvc-plumber]]
Q1 -->|no| Q2{PostHog /\ndisposable?}
Q2 -->|yes| EX[[backup-exempt]]
Q2 -->|no| Q3{Redis / cache /\nbroker?}
Q3 -->|yes| DEC[[backup-exempt\n(disposable)]]
Q3 -->|no| Q4{NFS / static\nexternal media?}
Q4 -->|yes| EXT[[usually exempt /\nbacked separately]]
Q4 -->|no| Q5{Regenerable cache\nthat's fine empty?}
Q5 -->|yes| EBD[[EMPTY_BY_DESIGN possible]]
Q5 -->|no| NORM[[normal app PVC ā\npvc-plumber managed]]
PVC kind
Decision
Normal app data (config, docs, uploads, SQLite)
pvc-plumber managed + dsr
CNPG database PVC
Barman ā S3 ā never pvc-plumber
PostHog (clickhouse/postgres/redis/kafka)
backup-exempt (disposable/rebuildable)
Redis / cache / broker
backup-exempt ā Redis is disposable
NFS / static media (immich originals, tubesync media)
usually exempt or backed separately
Pure regenerable cache
EMPTY_BY_DESIGN acceptable (no dsr)
š·ļø What the labels/annotations mean
Key
On
Meaning
pvc-plumber.io/managed-namespace: "true"
namespace
software write-gate ā operator may write RS/RD here
pvc-plumber.io/enabled: "true"
PVC
PVC opts in
pvc-plumber.io/manage-volsync: "true"
PVC
operator manages this PVC's VolSync objects
pvc-plumber.io/tier: hourly\|daily
PVC
backup cadence
volsync.backube/privileged-movers: "true"
namespace
ClusterES materializes the repo Secret here
restore-policy: strict\|best-effort
PVC
restore strictness convention
backup-exempt: "true"
PVC
deliberately not backed up
storage.vanillax.dev/backup-exempt-reason: "<why>"
PVC
FQ key required (bare key is silently ignored + CI-enforced)
ā What NOT to do
flowchart TD
N1[ā reintroduce Kyverno generation]
N2[ā hand-write new inline RS/RD\nunless intentionally temporary]
N3[ā migrate CNPG PVCs]
N4["ā assume backup == restore\n(prove with a drill)"]
N5[ā delete retained rollback PVs\nwithout approval]
N6[ā change Longhorn replica policy\nduring a restore drill]
No Kyverno ā it was removed 2026-05; the operator's reconciler does that job now.
No new inline RS/RD unless it's a deliberate, temporary bridge (the operator pattern is the default).
Never migrate CNPG PVCs ā Barman owns them.
Backup ā restore ā a backup you've never restored is a hypothesis. Run a drill for anything important.
Don't delete the 7 retained rollback PVs without per-PV approval.
Don't change Longhorn replicas/StorageClass mid-drill ā restore volumes come up degraded while rebuilding; that's expected.