From 9ca0b6cb0ddcfb9c5e724595cd420639f40860da Mon Sep 17 00:00:00 2001 From: Konstantin Renner Date: Fri, 24 Apr 2026 20:16:26 +0200 Subject: [PATCH] feat(coder-pg): wire barman-cloud plugin + daily backup MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The CNPG instance manager's reconcile loop blocks on "Unknown plugin: barman-cloud.cloudnative-pg.io" when a Cluster omits a plugin declaration, which in turn prevents TLS cert loading on the status endpoint and leaves the pod stuck 0/1 Ready. Match the house pattern (authentik-db, paperless-db, immich-db): - Declare the plugin in Cluster spec with barmanObjectName: coder-pg-store - ObjectStore coder-pg-store → s3://k8s-cnpg/coder-pg on Garage (nas-1) - Daily base backup at 02:30 UTC with immediate first backup - barman-cloud-creds reused from authentik-db (same Garage creds, namespace rewritten to coder) Co-Authored-By: Claude Opus 4.7 (1M context) --- kubernetes/apps/coder/barman-creds.sops.yaml | 25 ++++++++++++++++ kubernetes/apps/coder/kustomization.yaml | 3 ++ kubernetes/apps/coder/objectstore.yaml | 30 ++++++++++++++++++++ kubernetes/apps/coder/postgres.yaml | 8 ++++++ kubernetes/apps/coder/scheduled-backup.yaml | 21 ++++++++++++++ 5 files changed, 87 insertions(+) create mode 100644 kubernetes/apps/coder/barman-creds.sops.yaml create mode 100644 kubernetes/apps/coder/objectstore.yaml create mode 100644 kubernetes/apps/coder/scheduled-backup.yaml diff --git a/kubernetes/apps/coder/barman-creds.sops.yaml b/kubernetes/apps/coder/barman-creds.sops.yaml new file mode 100644 index 00000000..5043d5c6 --- /dev/null +++ b/kubernetes/apps/coder/barman-creds.sops.yaml @@ -0,0 +1,25 @@ +apiVersion: v1 +kind: Secret +metadata: + name: barman-cloud-creds + namespace: coder +type: Opaque +stringData: + ACCESS_KEY_ID: ENC[AES256_GCM,data:SjcYDpvy5SVXK/4/EGzIb5UjEqZTZ5sYB0E=,iv:mFfBZmdEi+Yj4HqMhZZ7NSS1dHwniYZKocJYElw00uw=,tag:4scsORHe7NAgbbg2fA2kNA==,type:str] + ACCESS_SECRET_KEY: ENC[AES256_GCM,data:095NGZvte1IA7E1dOmOxq9zzRbIXr3gR7c5ousfoo4+LH7kmu+Ea8HM89FaJ/HuPnM5R79D7kHi8d8HY1KPeuA==,iv:vN+Y2Ei6RflaXz04knl9kF4HYv0sN7DyUafgbO7lFd0=,tag:+VvivaaVxEubcyczED1yrw==,type:str] + REGION: ENC[AES256_GCM,data:RZXJfMo4,iv:ZQ68sunCV3103rjoYN2YhPBUNb2knJSFy10y73hv8po=,tag:SBK4KFoZEYSkGkbkIHwapA==,type:str] +sops: + age: + - recipient: age1yqjvqkwwwxdj7mr546zfs5ckzuwndp69ya2n2drd4vypwns8w4ys04qfy3 + enc: | + -----BEGIN AGE ENCRYPTED FILE----- + YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBYN2xiZmVGVmRmMWtGTE5H + QkN6R2tqS1orVWl1MWNMN0ZDbHB3dDVBWW0wCjJYY0FQNWRtT3lXZnI2dlJxUDdU + UndOd3hKYUwxdUxHUTZROGQzRC9XWUEKLS0tIDZGVFdYSGxrbVN2M2dROFFuRnhr + TW1aNW9kbWlCd1E0Mk5TL2VUdXhNc3MK7dx8WmafY6o6AArqkadsW8FpTTmjIMkd + ztPsFiFl0bHbgrpK6F2o0vDKd0RHhMkDGf8iFlpAAcmMJJBAjhw35A== + -----END AGE ENCRYPTED FILE----- + lastmodified: "2026-04-20T21:02:22Z" + mac: ENC[AES256_GCM,data:28S0BF/0Ixap+H6rV0FIWGVBfgqqJWNbmsDXi6a9g1CiNLK4tOdW/ACeohLqJrkWQKGZzPEwCtbl3FCk6z+t8s9ZwBjeGmh5E8eQnjfss+AEZTeLE1Xij9lI8kL0S+RXV3uMLiFU/ks3BmFziZBErj/MUyXnDNhw0n1VpRODcC4=,iv:1shlhwzkkF4E1JVQpLBzw8kAUk4RfGpbnvGufh5TDD4=,tag:uT8J+MXCXhU6MFhgqTDJKQ==,type:str] + encrypted_regex: ^(data|stringData)$ + version: 3.10.2 diff --git a/kubernetes/apps/coder/kustomization.yaml b/kubernetes/apps/coder/kustomization.yaml index 40438ba8..a1e971c3 100644 --- a/kubernetes/apps/coder/kustomization.yaml +++ b/kubernetes/apps/coder/kustomization.yaml @@ -3,5 +3,8 @@ kind: Kustomization resources: - secret.sops.yaml - le-staging-ca.yaml + - barman-creds.sops.yaml + - objectstore.yaml - postgres.yaml + - scheduled-backup.yaml - helmrelease.yaml diff --git a/kubernetes/apps/coder/objectstore.yaml b/kubernetes/apps/coder/objectstore.yaml new file mode 100644 index 00000000..48498d65 --- /dev/null +++ b/kubernetes/apps/coder/objectstore.yaml @@ -0,0 +1,30 @@ +--- +apiVersion: barmancloud.cnpg.io/v1 +kind: ObjectStore +metadata: + name: coder-pg-store + namespace: coder +spec: + configuration: + destinationPath: s3://k8s-cnpg/coder-pg + endpointURL: https://s3.nas-1.renner.uno + s3Credentials: + accessKeyId: + name: barman-cloud-creds + key: ACCESS_KEY_ID + secretAccessKey: + name: barman-cloud-creds + key: ACCESS_SECRET_KEY + # Garage requires an explicit region — without it boto3's + # HeadBucket call (used by barman-cloud-check-wal-archive during + # CNPG bootstrap.recovery) returns 400 Bad Request. + region: + name: barman-cloud-creds + key: REGION + wal: + compression: gzip + encryption: AES256 + data: + compression: gzip + encryption: AES256 + retentionPolicy: "30d" diff --git a/kubernetes/apps/coder/postgres.yaml b/kubernetes/apps/coder/postgres.yaml index 2239223f..adf14d4a 100644 --- a/kubernetes/apps/coder/postgres.yaml +++ b/kubernetes/apps/coder/postgres.yaml @@ -9,6 +9,14 @@ spec: storage: storageClass: ceph-block size: 10Gi + # The Barman Cloud plugin drives both WAL archiving and + # scheduled base backups to Garage on nas-1 (bucket k8s-cnpg). + # See objectstore.yaml for the destination config. + plugins: + - name: barman-cloud.cloudnative-pg.io + isWALArchiver: true + parameters: + barmanObjectName: coder-pg-store bootstrap: initdb: database: coder diff --git a/kubernetes/apps/coder/scheduled-backup.yaml b/kubernetes/apps/coder/scheduled-backup.yaml new file mode 100644 index 00000000..8099f386 --- /dev/null +++ b/kubernetes/apps/coder/scheduled-backup.yaml @@ -0,0 +1,21 @@ +--- +# Daily base backup at 02:30 UTC (aligned with the existing PBS +# client schedule at 02:00). `immediate: true` triggers the first +# backup as soon as this CR is applied. WAL archiving runs +# continuously (see postgres.yaml spec.plugins[].isWALArchiver). +# backupOwnerReference=self so Backups are cleaned up when this +# schedule is deleted. +apiVersion: postgresql.cnpg.io/v1 +kind: ScheduledBackup +metadata: + name: coder-pg-daily + namespace: coder +spec: + schedule: "0 30 2 * * *" + immediate: true + backupOwnerReference: self + cluster: + name: coder-pg + method: plugin + pluginConfiguration: + name: barman-cloud.cloudnative-pg.io -- 2.54.0