From 1d9b7ec924334dbf16a74f83f5588d68eb2c5078 Mon Sep 17 00:00:00 2001 From: unkin-agent Date: Mon, 12 Oct 2026 00:25:41 +1100 Subject: [PATCH] Add mail namespace with Stalwart backing stores (#538) Stalwart needs a Postgres metadata store and an S3 blob store before it can be deployed into the new `mail` namespace. - add CNPG Cluster `stalwart-db` (db/owner `stalwart`, CNPG-minted `stalwart-db-app` creds) with barman backups to a dedicated `cnpg-mail` bucket and a nightly ScheduledBackup - add cephrgw Bucket `stalwart-blobs` with an owner user writing RW keys to `stalwart-blobs-s3` - add the au-syd1 overlay, platform ApplicationSet path and project destination Reviewed-on: https://git.unkin.net/unkin/argocd-apps/pulls/538 Co-authored-by: unkin-agent Co-committed-by: unkin-agent --- apps/base/mail/cnpg_backup.yaml | 40 ++++++ apps/base/mail/cnpg_cluster.yaml | 118 ++++++++++++++++++ apps/base/mail/kustomization.yaml | 9 ++ apps/base/mail/namespace.yaml | 5 + apps/base/mail/stalwart-blobs-bucket.yaml | 30 +++++ apps/overlays/au-syd1/mail/kustomization.yaml | 6 + argocd/applicationsets/platform.yaml | 1 + argocd/projects/platform.yaml | 2 + 8 files changed, 211 insertions(+) create mode 100644 apps/base/mail/cnpg_backup.yaml create mode 100644 apps/base/mail/cnpg_cluster.yaml create mode 100644 apps/base/mail/kustomization.yaml create mode 100644 apps/base/mail/namespace.yaml create mode 100644 apps/base/mail/stalwart-blobs-bucket.yaml create mode 100644 apps/overlays/au-syd1/mail/kustomization.yaml diff --git a/apps/base/mail/cnpg_backup.yaml b/apps/base/mail/cnpg_backup.yaml new file mode 100644 index 0000000..8b2b28d --- /dev/null +++ b/apps/base/mail/cnpg_backup.yaml @@ -0,0 +1,40 @@ +--- +apiVersion: ceph.unkin.net/v1alpha1 +kind: ObjectStoreUser +metadata: + name: cnpg-mail-backup + namespace: mail +spec: + displayName: "CNPG backup owner (mail)" + uid: cnpg-mail-backup + maxBuckets: 5 + secretName: cnpg-mail-backup-s3 + retainOnDelete: true +--- +apiVersion: ceph.unkin.net/v1alpha1 +kind: Bucket +metadata: + name: cnpg-mail + namespace: mail +spec: + placementTarget: ec + bucketName: cnpg-mail + ownerRef: cnpg-mail-backup + versioning: false + tags: + app: mail + purpose: cnpg-backup + retainOnDelete: true +--- +apiVersion: postgresql.cnpg.io/v1 +kind: ScheduledBackup +metadata: + name: cnpg-mail-nightly + namespace: mail +spec: + schedule: "0 20 4 * * *" + immediate: false + backupOwnerReference: self + method: barmanObjectStore + cluster: + name: stalwart-db diff --git a/apps/base/mail/cnpg_cluster.yaml b/apps/base/mail/cnpg_cluster.yaml new file mode 100644 index 0000000..86d7d09 --- /dev/null +++ b/apps/base/mail/cnpg_cluster.yaml @@ -0,0 +1,118 @@ +--- +# Stalwart metadata store. No bootstrap secret: CNPG mints stalwart-db-app +# (username/password/dbname/uri) for Stalwart to consume. +apiVersion: postgresql.cnpg.io/v1 +kind: Cluster +metadata: + name: stalwart-db + namespace: mail +spec: + affinity: + podAntiAffinityType: preferred + backup: + retentionPolicy: 30d + barmanObjectStore: + destinationPath: s3://cnpg-mail + endpointURL: https://s3.ceph.unkin.net + endpointCA: + name: vault-ca-cert + key: ca.crt + s3Credentials: + accessKeyId: + name: cnpg-mail-backup-s3 + key: AWS_ACCESS_KEY_ID + secretAccessKey: + name: cnpg-mail-backup-s3 + key: AWS_SECRET_ACCESS_KEY + serverName: stalwart-db + data: + compression: bzip2 + jobs: 2 + wal: + compression: zstd + maxParallel: 2 + bootstrap: + initdb: + database: stalwart + encoding: UTF8 + localeCType: C + localeCollate: C + owner: stalwart + enablePDB: true + enableSuperuserAccess: false + failoverDelay: 0 + imageName: ghcr.io/cloudnative-pg/postgresql:18.1-system-trixie + instances: 3 + logLevel: info + maxSyncReplicas: 0 + minSyncReplicas: 0 + monitoring: + customQueriesConfigMap: + - key: queries + name: cnpg-default-monitoring + disableDefaultQueries: false + enablePodMonitor: false + postgresql: + parameters: + archive_mode: "on" + archive_timeout: 5min + dynamic_shared_memory_type: posix + effective_cache_size: 256MB + full_page_writes: "on" + hot_standby_feedback: "on" + log_destination: csvlog + log_directory: /controller/log + log_filename: postgres + log_rotation_age: "0" + log_rotation_size: "0" + log_truncate_on_rotation: "false" + logging_collector: "on" + max_connections: "200" + max_parallel_workers: "16" + max_replication_slots: "16" + max_worker_processes: "16" + pg_stat_statements.max: "10000" + pg_stat_statements.track: top + shared_buffers: 128MB + shared_memory_type: mmap + ssl_max_protocol_version: TLSv1.3 + ssl_min_protocol_version: TLSv1.3 + wal_keep_size: 256MB + wal_level: logical + wal_log_hints: "on" + wal_receiver_timeout: 5s + wal_sender_timeout: 5s + shared_preload_libraries: + - pg_stat_statements + syncReplicaElectionConstraint: + enabled: false + primaryUpdateMethod: restart + primaryUpdateStrategy: unsupervised + probes: + liveness: + isolationCheck: + connectionTimeout: 1000 + enabled: true + requestTimeout: 1000 + replicationSlots: + highAvailability: + enabled: true + slotPrefix: _cnpg_ + synchronizeReplicas: + enabled: true + updateInterval: 30 + resources: + limits: + cpu: "1" + memory: 1Gi + requests: + cpu: 50m + memory: 512Mi + smartShutdownTimeout: 180 + startDelay: 3600 + stopDelay: 1800 + storage: + resizeInUseVolumes: true + size: 10Gi + storageClass: cephrbd-fast-delete + switchoverDelay: 3600 diff --git a/apps/base/mail/kustomization.yaml b/apps/base/mail/kustomization.yaml new file mode 100644 index 0000000..ebe64ef --- /dev/null +++ b/apps/base/mail/kustomization.yaml @@ -0,0 +1,9 @@ +--- +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization + +resources: + - cnpg_backup.yaml + - cnpg_cluster.yaml + - namespace.yaml + - stalwart-blobs-bucket.yaml diff --git a/apps/base/mail/namespace.yaml b/apps/base/mail/namespace.yaml new file mode 100644 index 0000000..2546ff2 --- /dev/null +++ b/apps/base/mail/namespace.yaml @@ -0,0 +1,5 @@ +--- +apiVersion: v1 +kind: Namespace +metadata: + name: mail diff --git a/apps/base/mail/stalwart-blobs-bucket.yaml b/apps/base/mail/stalwart-blobs-bucket.yaml new file mode 100644 index 0000000..050c6e8 --- /dev/null +++ b/apps/base/mail/stalwart-blobs-bucket.yaml @@ -0,0 +1,30 @@ +--- +# Stalwart S3 blob store. The owner user has read-write on its own bucket; the +# operator mints AWS_ACCESS_KEY_ID / AWS_SECRET_ACCESS_KEY / S3_ENDPOINT into +# stalwart-blobs-s3. +apiVersion: ceph.unkin.net/v1alpha1 +kind: ObjectStoreUser +metadata: + name: stalwart-blobs + namespace: mail +spec: + displayName: "Stalwart blob store owner" + uid: mail-stalwart-blobs + maxBuckets: 5 + secretName: stalwart-blobs-s3 + retainOnDelete: true +--- +apiVersion: ceph.unkin.net/v1alpha1 +kind: Bucket +metadata: + name: stalwart-blobs + namespace: mail +spec: + placementTarget: ec + bucketName: stalwart-blobs + ownerRef: stalwart-blobs + versioning: false + tags: + app: stalwart + purpose: blob-store + retainOnDelete: true diff --git a/apps/overlays/au-syd1/mail/kustomization.yaml b/apps/overlays/au-syd1/mail/kustomization.yaml new file mode 100644 index 0000000..970d31c --- /dev/null +++ b/apps/overlays/au-syd1/mail/kustomization.yaml @@ -0,0 +1,6 @@ +--- +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization + +resources: + - ../../../base/mail diff --git a/argocd/applicationsets/platform.yaml b/argocd/applicationsets/platform.yaml index 6a951e3..b0c9d3c 100644 --- a/argocd/applicationsets/platform.yaml +++ b/argocd/applicationsets/platform.yaml @@ -34,6 +34,7 @@ spec: - path: apps/overlays/*/jfrog - path: apps/overlays/*/k8up-system - path: apps/overlays/*/kanidm + - path: apps/overlays/*/mail - path: apps/overlays/*/netbox - path: apps/overlays/*/node-feature-discovery - path: apps/overlays/*/pdbmux diff --git a/argocd/projects/platform.yaml b/argocd/projects/platform.yaml index 011b942..a7e97fa 100644 --- a/argocd/projects/platform.yaml +++ b/argocd/projects/platform.yaml @@ -49,6 +49,8 @@ spec: server: https://kubernetes.default.svc - namespace: 'kanidm' server: https://kubernetes.default.svc + - namespace: 'mail' + server: https://kubernetes.default.svc - namespace: 'netbox' server: https://kubernetes.default.svc - namespace: 'node-feature-discovery'