CloudNativePG 1.29: Image Catalog과 ServiceAccount 통합으로 Kubernetes PostgreSQL 운영의 경계를 다시 그은 방법
요약
CloudNativePG는 PostgreSQL을 Kubernetes-native 방식으로 운영하는 오픈소스 오퍼레이터다. 2026년 3월 31일 릴리스된 1.29.0은 두 가지 구조적 변화를 중심으로 한다. 첫째, Image Catalog — 컨테이너 이미지 메타데이터를 별도 CR(Custom Resource)로 추상화해, PostgreSQL 확장 플러그인을 운영자 주도로 설치하고 클러스터 업그레이드 경로를 선언적으로 관리한다. 둘째, ServiceAccount 레퍼런스 — 클러스터 Pod가 사용하는 Kubernetes ServiceAccount를 교체 가능하게 하여 AWS IRSA·Azure Workload Identity 같은 클라우드 IAM 연동을 CloudFormation 없이 구현한다. 이 두 기능은 Kubernetes 위에서 PostgreSQL의 플랫폼 신뢰성을 높이려는 1.x 로드맵의 핵심 축이다.
배경
PostgreSQL on Kubernetes의 세 가지 운영 과제
클라우드 네이티브 데이터베이스 운영에서 PostgreSQL을 Kubernetes에 올릴 때 반복되는 과제가 세 가지 있다.
① 확장 플러그인 관리
PostgreSQL의 강점 중 하나는 pgvector, pg_cron, timescaledb 같은 풍부한 확장 생태계다. 그러나 확장을 설치하려면 해당 공유 라이브러리(.so 파일)가 컨테이너 이미지 안에 있어야 한다. 관리자가 직접 Dockerfile을 빌드하거나 커뮤니티 이미지를 찾아 쓰는 방식은 버전 추적이 어렵고, 마이너 PostgreSQL 업그레이드 시 확장 호환성을 수동으로 검증해야 한다.
② 클라우드 IAM 연동
클라우드 스토리지(AWS S3, Azure Blob, GCS)에 백업하거나 Secrets Manager에서 암호를 읽으려면 Pod에 적절한 클라우드 자격증명이 있어야 한다. 기존에는 환경변수나 Kubernetes Secret에 액세스 키를 주입하는 방식이 일반적이었는데, IRSA(IAM Roles for Service Accounts)·Workload Identity 같은 단기 토큰 기반 메커니즘으로 전환하려면 Pod의 ServiceAccount를 직접 지정해야 한다.
③ 동적 접근 제어
pg_hba.conf는 클라이언트 IP·사용자·데이터베이스 조합으로 연결을 허용 또는 거부하는 PostgreSQL의 접근 제어 파일이다. Kubernetes 환경에서는 Pod IP가 런타임에 변한다. 고정 IP 대신 Kubernetes Pod 셀렉터 기반으로 pg_hba.conf 규칙을 정의하고 싶어도, 1.28까지는 직접 IP CIDR을 적어야 했다.
CloudNativePG 아키텍처
오퍼레이터와 Instance Manager
CloudNativePG는 두 개의 Go 바이너리로 동작한다.
- Operator: Kubernetes control plane에서 실행되는 컨트롤러.
Cluster,Backup,ScheduledBackup,ImageCatalog같은 CRD를 감시하고, StatefulSet 없이 직접 Pod를 생성·관리한다. StatefulSet를 쓰지 않는 이유는 PostgreSQL primary/standby 역할이 동적으로 바뀌기 때문이다. - Instance Manager: 각 PostgreSQL Pod 내부에서 PID 1로 동작하는 사이드카 프로세스.
postgresql.conf,pg_hba.conf,pg_ident.conf를 런타임에 렌더링하고, 헬스체크·WAL archiving·PostgreSQL 재시작을 조율한다.
Streaming Replication과 Lease 기반 Failover
Primary Pod는 WAL(Write-Ahead Log)을 Standby Pod에 스트리밍한다. Failover 시나리오에서 split-brain(두 Pod 모두 primary를 주장하는 상황)을 막기 위해 CloudNativePG는 Kubernetes Lease 오브젝트를 씬다. Primary의 Instance Manager는 주기적으로 Lease를 갱신하고, Operator는 Lease 만료를 감지해 Standby 중 하나를 새 Primary로 선출한다. 이 메커니즘은 외부 DCS(Distributed Configuration Store)가 필요 없다.
Barman Cloud 백업
barman-cloud-wal-archive와 barman-cloud-backup을 통해 WAL과 기본 백업이 오브젝트 스토리지로 전송된다. 복구는 barman-cloud-restore로 이루어지며, PITR(Point-in-Time Recovery)까지 지원된다.
1.29의 주요 변화
Image Catalog: 확장 생태계의 새 진입점
Image Catalog는 두 가지 새 CRD를 도입한다.
ImageCatalog: 네임스페이스 범위. 해당 네임스페이스의Cluster만 참조 가능.ClusterImageCatalog: 클러스터 범위. 모든 네임스페이스의Cluster가 참조 가능.
각 CRD는 PostgreSQL major version별로 컨테이너 이미지를 목록화한다.
apiVersion: postgresql.cnpg.io/v1
kind: ClusterImageCatalog
metadata:
name: extensions-pgvector
spec:
images:
- major: 16
image: ghcr.io/cloudnative-pg/postgresql-pgvector:16-latest
- major: 17
image: ghcr.io/cloudnative-pg/postgresql-pgvector:17-latestCluster CR에서는 spec.imageCatalogRef로 이 카탈로그를 참조한다.
spec:
imageCatalogRef:
apiGroup: postgresql.cnpg.io
kind: ClusterImageCatalog
name: extensions-pgvector
postgresql:
parameters:
shared_preload_libraries: "pgvector"이 구조의 핵심은 관심사 분리다. 인프라 팀이 조직 표준 확장 이미지를 ClusterImageCatalog에 등록하면, 개발팀은 해당 카탈로그 이름만 참조한다. PostgreSQL 마이너 버전 패치 시에는 카탈로그의 이미지 태그만 업데이트하면 되고, Cluster CR을 건드리지 않아도 다음 롤링 업데이트에서 반영된다.
커뮤니티는 이 생태계를 지원하기 위해 postgres-extensions-containers 프로젝트를 공개했다. ghcr.io/cloudnative-pg/postgresql-pgvector, postgresql-pg_cron, postgresql-pg_partman 등 주요 확장의 공식 이미지를 제공하며, major/minor PostgreSQL 버전별 이미지를 자동 빌드한다.
이미지 빌드·검증
(major 16/17/18 매핑)
imageCatalogRef 참조
→ Pod 생성
(Cluster CR 무변경)
자동 반영
ServiceAccount 레퍼런스: 클라우드 IAM 연동
1.29 이전에는 CloudNativePG가 각 Cluster마다 ServiceAccount를 자동 생성했다. 이름·어노테이션을 커스텀할 방법이 없어, AWS EKS의 IRSA나 Azure AKS의 Workload Identity를 쓰려면 Helm 포스트훅으로 어노테이션을 덮어쓰는 편법이 필요했다.
1.29는 spec.serviceAccountTemplate을 도입한다.
spec:
serviceAccountTemplate:
metadata:
annotations:
eks.amazonaws.com/role-arn: arn:aws:iam::123456789012:role/cnpg-backup-role이 어노테이션 하나로 EKS가 Pod에 단기 AWS 토큰을 주입하고, Barman Cloud가 그 토큰으로 S3에 직접 백업을 쓸 수 있다. 액세스 키를 Kubernetes Secret에 저장하지 않아도 된다.
podSelectorRefs: 동적 pg_hba.conf
spec.postgresql.pg_hba 필드는 원래 고정 문자열 배열이었다. 1.29는 podSelectorRefs 필드를 추가해 Kubernetes Pod 셀렉터를 pg_hba.conf 규칙에 연결한다.
spec:
postgresql:
podSelectorRefs:
- name: app-pods
namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: myapp
podSelector:
matchLabels:
app: myappOperator는 이 셀렉터로 매칭되는 Pod의 IP를 동적으로 수집해 pg_hba.conf에 삽입한다. 새 애플리케이션 Pod가 뜨거나 재스케줄되어 IP가 바뀌어도 접근 제어가 자동 유지된다.
PgBouncer Advanced TLS 및 보안 수정
1.29는 Pooler(PgBouncer) 리소스에 고급 TLS 옵션을 추가했다. 클라이언트→PgBouncer, PgBouncer→PostgreSQL 양쪽에 각각 다른 TLS 설정을 적용할 수 있다.
CVE-2026-44477도 이번 릴리스에서 패치됐다. 특정 조건에서 Instance Manager가 인증서 없이 연결을 수락하는 버그로, 1.27.x와 1.28.x 사용자는 1.29.0으로 업그레이드를 권고받는다.
1.29 주요 기능 요약
| 기능 | 설명 | 대상 |
|---|---|---|
ImageCatalog / ClusterImageCatalog | 확장 이미지를 카탈로그 CR로 분리 관리 | 인프라·DBA 팀 |
spec.serviceAccountTemplate | Pod ServiceAccount 어노테이션 커스텀, IRSA·Workload Identity 지원 | 클라우드 환경 |
podSelectorRefs | Pod 셀렉터 기반 pg_hba.conf 동적 생성 | 멀티테넌트 클러스터 |
| PgBouncer Advanced TLS | 클라이언트·서버 TLS 분리 설정 | 보안 요건 |
| CVE-2026-44477 패치 | 인증서 검증 우회 버그 수정 | 전 버전 사용자 |
| PostgreSQL 18 Beta 지원 | PostgreSQL 18 Beta 컨테이너 실험적 지원 | 얼리어답터 |
운영 고려 사항
Image Catalog 전환 전략
기존 spec.imageName으로 이미지를 직접 지정하던 Cluster를 Image Catalog 방식으로 전환할 때는 단계적 접근이 안전하다. 먼저 현재 쓰는 이미지와 동일한 이미지를 가리키는 ClusterImageCatalog를 생성하고, Cluster의 imageCatalogRef를 업데이트한다. imageName과 imageCatalogRef는 공존할 수 없으므로 전환 시 imageName 필드를 제거해야 한다.
ServiceAccount 이전 주의점
serviceAccountTemplate을 처음 추가하면 Operator가 기존 ServiceAccount를 삭제하고 새로 생성한다. 이 과정에서 짧은 재시작이 발생할 수 있다. 변경 전 kubectl get sa -n <namespace> 결과를 백업해두고, IAM 바인딩이 새 ServiceAccount 이름과 일치하는지 확인한다.
podSelectorRefs 적용 범위
1.29에서 podSelectorRefs는 pg_hba.conf의 host 레코드만 생성한다. hostssl, hostnossl, local 레코드는 여전히 spec.postgresql.pg_hba 배열로 직접 써야 한다. 두 방식을 혼용할 수 있으며, podSelectorRefs로 생성된 규칙은 배열 뒤에 붙는다.
Open question:
podSelectorRefs는 현재 Pod IP를 폴링 방식으로 수집한다. Pod 교체 주기가 매우 빠른(수 초 단위) 환경에서 pg_hba.conf가 얼마나 빠르게 갱신되는지, Operator 레코드 주기와의 격차가 실제 연결 실패로 이어지는지 검증된 데이터가 없다.
Open question: Image Catalog가 참조하는 컨테이너 이미지에서
.so충돌이 발생할 때(예: 서로 다른 확장이 동일 라이브러리 버전을 필요로 하지만 다른 빌드로 제공하는 경우), CloudNativePG 레벨에서 의존성을 검증하는 메커니즘이 없다. 현재는 이미지 빌드 단계에서 해결해야 한다.
관련 도구
Patroni, Stolon과의 차이
Patroni와 Stolon은 etcd·Consul·ZooKeeper 같은 외부 DCS에 의존해 leader election을 수행한다. CloudNativePG는 Kubernetes Lease를 사용하므로 외부 DCS가 없어도 된다. 대신 Kubernetes API 서버의 가용성에 의존한다.
Crunchy Postgres Operator
Crunchy Data의 PGO도 비슷한 Kubernetes-native 접근이지만, CRD 설계 철학이 다르다. CloudNativePG는 단일 Cluster CR로 Primary·Standby를 모두 선언하는 반면, PGO는 PostgresCluster 내부에 여러 인스턴스 집합을 정의한다. Image Catalog에 대응하는 기능은 PGO 5.x에 없고, 이미지 관리는 postgresVersion 필드와 커스텀 이미지 직접 지정 방식을 쓴다.
CNPG-I (Plugin Interface)
1.29와 같은 시기에 CNPG-I(CloudNativePG Plugin Interface) 스펙이 공개됐다. 서드파티가 Operator 코드를 포크하지 않고 Webhook·백업 드라이버·WAL 전송 플러그인을 붙일 수 있는 확장 지점이다. 현재는 얼리 프리뷰 상태다.
References
- CloudNativePG 1.29.0 릴리스 노트: https://cloudnative-pg.io/releases/cloudnative-pg-1-29.0-released/
- CloudNativePG Image Catalog 공식 문서: https://cloudnative-pg.io/docs/1.29/image_catalog/
- CNPG Recipe #26: Extension Image Catalogs (Gabriele Bartolini, 2026-08): https://gabrielebartolini.it/articles/2026/08/cnpg-recipe-26-extension-image-catalogs/
- postgres-extensions-containers GitHub: https://github.com/cloudnative-pg/postgres-extensions-containers
- CloudNativePG GitHub 릴리스: https://github.com/cloudnative-pg/cloudnative-pg/releases/tag/v1.29.0
- Barman Cloud 문서: https://www.pgbarman.org/documentation/
- CVE-2026-44477 어드바이저리: https://cloudnative-pg.io/blog/security-advisory-cve-2026-44477/