From abc95f94c71e47a9649254bb9416322f9747ee9f Mon Sep 17 00:00:00 2001 From: "Claude (postgres-operator)" Date: Mon, 25 May 2026 21:34:33 +0900 Subject: [PATCH] feat(backup): WAL archiving via pgbackrest archive-push + version bump v0.3.0-alpha.19 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Sprint S3: Enable WAL archiving when spec.backup.enabled=true. Changes: - renderPostgresConf now emits archive_mode=on, archive_command, and archive_timeout=60 when backup is enabled on the cluster - archive_command uses pgbackrest archive-push with cluster name as stanza - Version bump: 0.3.0-alpha.18 → 0.3.0-alpha.19 across all manifests Gap analysis impact: - P0 #1 (WAL archiving): archive_command wiring DONE Signed-off-by: Phil Co-Authored-By: Claude Opus 4.7 Signed-off-by: Claude (postgres-operator) --- .github/ISSUE_TEMPLATE/question.yml | 4 +-- .lefthook.yml | 2 +- CITATION.cff | 2 +- ...stgres-operator.clusterserviceversion.yaml | 8 +++--- bundle/metadata/properties.yaml | 2 +- charts/postgres-operator/Chart.yaml | 4 +-- config/manager/kustomization.yaml | 2 +- ...stgres-operator.clusterserviceversion.yaml | 2 +- dist/install.yaml | 2 +- internal/controller/builders.go | 25 ++++++++++++++++++- internal/controller/builders_test.go | 2 +- 11 files changed, 39 insertions(+), 16 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/question.yml b/.github/ISSUE_TEMPLATE/question.yml index b0460266..20e11cd5 100644 --- a/.github/ISSUE_TEMPLATE/question.yml +++ b/.github/ISSUE_TEMPLATE/question.yml @@ -30,7 +30,7 @@ body: description: Provide context about what you're trying to achieve placeholder: | I'm trying to deploy a PostgresCluster with TLS encryption and a Pooler in front. - I'm running Kubernetes 1.30 on a bare-metal cluster and using the operator v0.3.0-alpha.18. + I'm running Kubernetes 1.30 on a bare-metal cluster and using the operator v0.3.0-alpha.19. render: markdown validations: required: true @@ -66,7 +66,7 @@ body: label: postgres-operator Version description: Which version of the postgres-operator are you using? options: - - 'v0.3.0-alpha.18' + - 'v0.3.0-alpha.19' - 'v0.3.0-alpha.17' - 'v0.3.0-alpha.16' - 'Other' diff --git a/.lefthook.yml b/.lefthook.yml index a250a985..d7868898 100644 --- a/.lefthook.yml +++ b/.lefthook.yml @@ -142,7 +142,7 @@ pre-push: # newTag + dist/install.yaml image tag). standards/enforcement.md §3.1.4 # (`version-ssot-drift` rule) + standards/checklist.md PR row 정합. # 트리거 사고: 2026-05-20 RCA — CITATION.cff `v0.3.0-alpha.15` ↔ Chart - # `0.3.0-alpha.18` 3 release silent drift. + # `0.3.0-alpha.19` 3 release silent drift. # 우회: VERSION_SYNC_SKIP=1 환경변수. run: bash scripts/check-version-sync.sh go-mod-tidy: diff --git a/CITATION.cff b/CITATION.cff index 2e85e5d0..9f1bc2ac 100644 --- a/CITATION.cff +++ b/CITATION.cff @@ -20,4 +20,4 @@ keywords: - high-availability - pgbackrest license: Apache-2.0 -version: v0.3.0-alpha.18 +version: v0.3.0-alpha.19 diff --git a/bundle/manifests/keiailab-postgres-operator.clusterserviceversion.yaml b/bundle/manifests/keiailab-postgres-operator.clusterserviceversion.yaml index 5e231281..2ec87069 100644 --- a/bundle/manifests/keiailab-postgres-operator.clusterserviceversion.yaml +++ b/bundle/manifests/keiailab-postgres-operator.clusterserviceversion.yaml @@ -276,7 +276,7 @@ metadata: ] capabilities: Seamless Upgrades categories: Database, Storage - containerImage: ghcr.io/keiailab/postgres-operator:0.3.0-alpha.18 + containerImage: ghcr.io/keiailab/postgres-operator:0.3.0-alpha.19 createdAt: "2026-05-12T13:53:44Z" description: | Apache-2.0 PostgreSQL Kubernetes Operator — vanilla PG17/PG18, license-clean, @@ -286,7 +286,7 @@ metadata: operators.operatorframework.io/project_layout: go.kubebuilder.io/v4 repository: https://github.com/keiailab/postgres-operator support: https://github.com/keiailab/postgres-operator/issues - name: keiailab-postgres-operator.v0.3.0-alpha.18 + name: keiailab-postgres-operator.v0.3.0-alpha.19 namespace: placeholder spec: apiservicedefinitions: {} @@ -594,7 +594,7 @@ spec: - --health-probe-bind-address=:8081 command: - /manager - image: ghcr.io/keiailab/postgres-operator:0.3.0-alpha.18 + image: ghcr.io/keiailab/postgres-operator:0.3.0-alpha.19 livenessProbe: httpGet: path: /healthz @@ -701,4 +701,4 @@ spec: provider: name: Keiailab url: https://github.com/keiailab - version: 0.3.0-alpha.18 + version: 0.3.0-alpha.19 diff --git a/bundle/metadata/properties.yaml b/bundle/metadata/properties.yaml index cd9cc6ab..0e91e1b0 100644 --- a/bundle/metadata/properties.yaml +++ b/bundle/metadata/properties.yaml @@ -2,7 +2,7 @@ properties: - type: olm.package value: packageName: keiailab-postgres-operator - version: 0.3.0-alpha.18 + version: 0.3.0-alpha.19 - type: olm.gvk value: group: postgres.keiailab.io diff --git a/charts/postgres-operator/Chart.yaml b/charts/postgres-operator/Chart.yaml index cea72d1e..09b398c4 100644 --- a/charts/postgres-operator/Chart.yaml +++ b/charts/postgres-operator/Chart.yaml @@ -14,10 +14,10 @@ kubeVersion: ">=1.26.0-0" # Chart 자체 버전 — alpha 단계, breaking change 가능. SemVer 준수. # alpha.N iterative pre-release 표기. -version: 0.3.0-alpha.18 +version: 0.3.0-alpha.19 # 본 chart가 packaging하는 operator 버전. cmd/main.go binary 버전과 일치. -appVersion: "0.3.0-alpha.18" +appVersion: "0.3.0-alpha.19" home: https://github.com/keiailab/postgres-operator sources: diff --git a/config/manager/kustomization.yaml b/config/manager/kustomization.yaml index 2aa4471a..3cbd708a 100644 --- a/config/manager/kustomization.yaml +++ b/config/manager/kustomization.yaml @@ -7,4 +7,4 @@ resources: images: - name: controller newName: ghcr.io/keiailab/postgres-operator - newTag: 0.3.0-alpha.18 + newTag: 0.3.0-alpha.19 diff --git a/config/manifests/bases/postgres-operator.clusterserviceversion.yaml b/config/manifests/bases/postgres-operator.clusterserviceversion.yaml index 844b6140..64cee1aa 100644 --- a/config/manifests/bases/postgres-operator.clusterserviceversion.yaml +++ b/config/manifests/bases/postgres-operator.clusterserviceversion.yaml @@ -182,7 +182,7 @@ metadata: ] capabilities: Seamless Upgrades categories: Database, Storage - containerImage: ghcr.io/keiailab/postgres-operator:0.3.0-alpha.18 + containerImage: ghcr.io/keiailab/postgres-operator:0.3.0-alpha.19 createdAt: "2026-05-10T00:00:00Z" description: | Apache-2.0 PostgreSQL Kubernetes Operator — vanilla PG18+, license-clean, diff --git a/dist/install.yaml b/dist/install.yaml index c7a13698..bd2a96fe 100644 --- a/dist/install.yaml +++ b/dist/install.yaml @@ -31242,7 +31242,7 @@ spec: - --health-probe-bind-address=:8081 command: - /manager - image: ghcr.io/keiailab/postgres-operator:0.3.0-alpha.18 + image: ghcr.io/keiailab/postgres-operator:0.3.0-alpha.19 livenessProbe: httpGet: path: /healthz diff --git a/internal/controller/builders.go b/internal/controller/builders.go index fc1d8936..f7294e12 100644 --- a/internal/controller/builders.go +++ b/internal/controller/builders.go @@ -302,6 +302,7 @@ func renderPostgresConf( enabledExtensions []string, tlsOn bool, syncConfig *synchronousPostgresConfig, + archiveConfig *archivePostgresConfig, ) string { var sb strings.Builder sb.WriteString("# Generated by keiailab-postgres-operator. Do not edit by hand.\n") @@ -331,17 +332,38 @@ func renderPostgresConf( // Pillar P7 §7 Phase 3b: TLS server cert 활성. cert-manager Certificate (Phase 2) // 가 발급한 Secret 이 STS volume mount (Phase 3a) 로 /etc/ssl/postgres 경로에 // tls.crt + tls.key + ca.crt 형태로 노출. 본 conditional 은 ssl=on + 경로 명시. + if archiveConfig != nil && archiveConfig.Enabled { + sb.WriteString("archive_mode = on\n") + fmt.Fprintf(&sb, "archive_command = '%s'\n", archiveConfig.Command) + sb.WriteString("archive_timeout = 60\n") + } if tlsOn { sb.WriteString("ssl = on\n") fmt.Fprintf(&sb, "ssl_cert_file = '%s/tls.crt'\n", pgTLSMountPath) fmt.Fprintf(&sb, "ssl_key_file = '%s/tls.key'\n", pgTLSMountPath) fmt.Fprintf(&sb, "ssl_ca_file = '%s/ca.crt'\n", pgTLSMountPath) - // modern TLS 만 — TLS 1.2+ 강제 (PostgreSQL 12+ default 지만 명시). sb.WriteString("ssl_min_protocol_version = 'TLSv1.2'\n") } return sb.String() } +type archivePostgresConfig struct { + Enabled bool + Command string +} + +func archiveConfigForCluster(cluster *postgresv1alpha1.PostgresCluster) *archivePostgresConfig { + if cluster.Spec.Backup == nil || !cluster.Spec.Backup.Enabled { + return nil + } + stanza := cluster.Name + cmd := fmt.Sprintf("pgbackrest --stanza=%s archive-push %%p", stanza) + return &archivePostgresConfig{ + Enabled: true, + Command: cmd, + } +} + func quoteSynchronousStandbyNames(names []string) []string { out := make([]string, 0, len(names)) for _, name := range names { @@ -533,6 +555,7 @@ func postgresConfigData( cluster.Spec.Extensions, tlsEnabled(cluster), synchronousConfigForShard(cluster, shardOrdinal), + archiveConfigForCluster(cluster), ), "pg_hba.conf": renderPGHBAConf(tlsEnabled(cluster)), } diff --git a/internal/controller/builders_test.go b/internal/controller/builders_test.go index bd221422..2796ac08 100644 --- a/internal/controller/builders_test.go +++ b/internal/controller/builders_test.go @@ -305,7 +305,7 @@ func TestRenderPGHBAConf_TLSUsesHostSSLForPgRewindNormalConnection(t *testing.T) func TestRenderPostgresConf_EnablesWalLogHintsForPgRewind(t *testing.T) { t.Parallel() - conf := renderPostgresConf(nil, nil, false, nil) + conf := renderPostgresConf(nil, nil, false, nil, nil) if !strings.Contains(conf, "wal_log_hints = on\n") { t.Fatalf("postgresql.conf must enable wal_log_hints for pg_rewind, got:\n%s", conf) }