본문으로 건너뛰기

2.5 CNPG-I 플러그인 구조

7.1과 7.2에서 Barman Cloud "플러그인"으로 백업과 WAL archive를 구성한다. 이 플러그인이 Operator의 일부인지, 별도 프로그램인지, 어떻게 서로 대화하는지를 이 절에서 정리한다. 이름은 CloudNativePG Interface, 줄여서 CNPG-I다. Operator 본체를 고치지 않고 기능을 덧붙이기 위한 gRPC 기반 확장 규격이며, Kubernetes의 Container Storage Interface(CSI)에서 착안했다.

본체에서 분리한 이유​

CloudNativePG 코드베이스가 커지면서 새 기능을 본체에 넣는 비용이 함께 커졌다. 플러그인 규격이 없던 시절에 본체에 없는 기능이 필요하면 프로젝트를 fork하거나 그 위에 별도 컴포넌트를 얹어야 했고, 둘 다 업그레이드를 늦추는 유지보수 부담이 됐다. CNPG-I는 클러스터 수명주기의 정해진 지점(백업, 복구, 하위 리소스 reconcile 등)에 안정된 gRPC 접점을 두어, 그 지점의 동작을 외부 프로그램이 대신하게 한다. 확장 대상은 Operator, 또는 PostgreSQL Pod 안의 인스턴스 매니저(2.3)다.

1.30에서 이 방향은 이미 정해져 있다. Operator에 내장된(in-tree) Barman Cloud 지원은 deprecated이고 제거 시점만 1.31로 미뤄져 있다. 하위 호환을 위해 Backup.spec.method의 기본값은 아직 barmanObjectStore지만, object store 백업의 권장되는 장기 경로는 플러그인이다.

배치와 통신 경로​

플러그인은 컨테이너 이미지로 패키징되며 두 가지 방법으로 Operator에 등록한다.

  • sidecar 컨테이너: Operator Deployment 안에 플러그인 컨테이너를 함께 넣는다. 플러그인은 Unix domain socket으로 gRPC 서버를 열고, 그 socket을 Operator 컨테이너와 공유하는 디렉토리(PLUGIN_SOCKET_DIR, 기본 /plugin)에 둔다. Operator 기동 시 한 번만 발견된다.
  • 독립 Deployment (권장): 플러그인을 별도 Deployment로 배포하고 Service 뒤에 TCP gRPC 엔드포인트를 둔다. Operator와 수명주기가 분리되어 배포와 확장을 따로 한다. Operator는 특정 label과 annotation이 붙은 Service를 감시해 플러그인을 동적으로 발견하므로 재시작이 필요 없다.

여기서 제어 경로와 데이터 경로를 구분해서 봐야 한다. 독립 Deployment 배치에서 제어 경로는 Operator와 플러그인 Deployment 사이의 gRPC다. 데이터 경로는 PostgreSQL Pod에서 object store로 가는 실제 바이트 흐름인데, 이는 Operator를 거치지 않는다.

데이터 경로가 어디서 실행되는지는 규격이 아니라 플러그인 구현이 정한다. Barman Cloud 플러그인을 예로 들면, base backup과 WAL archiving은 PostgreSQL Pod 안에서 함께 도는 sidecar 컨테이너가 실행한다. 백업을 standby에서 수행하면 그 standby Pod의 sidecar가 일한다. 이 구현에서는 "플러그인 Deployment"가 조정을 맡고 "플러그인 sidecar"가 데이터 전송을 수행한다.

발견과 mTLS​

독립 Deployment로 배포한 플러그인의 Service에는 두 표식이 필요하다.

항목값역할
label cnpg.io/pluginName플러그인 이름 (예: barman-cloud.cloudnative-pg.io)Operator가 이 label로 플러그인을 찾는다
annotation cnpg.io/pluginPortgRPC 포트어느 포트로 접속할지

네트워크를 타는 통신이므로 mTLS가 강제된다. 클라이언트(Operator)와 서버(플러그인) 인증서를 Kubernetes TLS Secret으로 만들고 Service annotation cnpg.io/pluginClientSecret, cnpg.io/pluginServerSecret으로 가리킨다. 공식 문서는 cert-manager로 발급하는 것을 권한다. Operator는 기본적으로 Service 이름으로 서버 인증서를 검증한다. 인증서의 DNS 이름이 Service 이름과 다르면 cnpg.io/pluginServerName annotation으로 검증 대상 이름을 바꾼다. 그 이름은 서버 인증서의 SAN에 있어야 한다.

apiVersion: v1
kind: Service
metadata:
name: barman-cloud
namespace: cnpg-system
labels:
cnpg.io/pluginName: barman-cloud.cloudnative-pg.io
annotations:
cnpg.io/pluginPort: "9090"
cnpg.io/pluginClientSecret: barman-cloud-client-tls
cnpg.io/pluginServerSecret: barman-cloud-server-tls
spec:
ports:
- port: 9090
targetPort: 9090
selector:
app: barman-cloud
노트

공식 문서 본문에는 label 이름이 cnpg.io/plugin으로 적힌 곳이 있지만, 같은 문서의 예제와 Cluster spec.plugins 설명, 실제 Barman Cloud 플러그인 매니페스트는 모두 cnpg.io/pluginName을 쓴다. 이 노트는 cnpg.io/pluginName을 따른다.

1.30부터 Operator는 플러그인 Service 뒤의 EndpointSlices를 감시한다. 플러그인 이미지를 올려 Pod가 교체되면 그 변화를 감지해, 해당 플러그인을 쓰는 모든 Cluster를 곧바로 reconcile한다. 주기적 resync를 기다리지 않고 새 Pod와 대화를 시작한다는 뜻이다.

Cluster에서 켜기​

플러그인은 Cluster의 .spec.plugins 목록으로 켠다. name은 sidecar 방식이면 socket 파일 이름, Deployment 방식이면 Service의 cnpg.io/pluginName label 값이다. parameters는 플러그인마다 다르며 그 플러그인의 문서를 따른다. WAL archive를 맡길 플러그인에는 isWALArchiver: true를 준다.

apiVersion: postgresql.cnpg.io/v1
kind: Cluster
metadata:
name: cluster-example
spec:
instances: 3
plugins:
- name: barman-cloud.cloudnative-pg.io
enabled: true
isWALArchiver: true
parameters:
barmanObjectName: minio-store
storage:
size: 1Gi

플러그인은 다른 자리에서도 등장한다. Backup.spec.method: plugin은 이 플러그인으로 base backup을 뜨라는 뜻이고(7.1), 복구 시 externalClusters[].plugin은 원본 archive를 이 플러그인으로 읽으라는 뜻이다(7.3). 플러그인이 자체 CRD를 가져오는 경우도 있다. Barman Cloud의 ObjectStore(barmancloud.cnpg.io)가 그 예로, Cluster는 parameters.barmanObjectName으로 이를 참조한다(2.2).

운영에서 달라지는 것​

플러그인은 Operator와 별도로 배포되는 워크로드다. 이 사실이 몇 가지 운영 조건을 만든다.

  • 가용성이 분리된다. 제어 경로와 데이터 경로가 따로 고장난다. 플러그인 Deployment가 내려가면 Operator는 새 백업을 위임할 곳이 없다. 데이터 경로 쪽, 즉 Barman Cloud 구현에서 인스턴스 Pod의 sidecar가 object store에 닿지 못하면 archive_command가 실패해 primary에 WAL이 쌓인다. 플러그인 Deployment와 sidecar 모두 PostgreSQL Pod처럼 감시 대상이다.
  • 버전이 둘이다. Operator 버전과 플러그인 버전을 각각 관리하고, 플러그인 문서가 요구하는 최소 Operator 버전을 지킨다. Barman Cloud 플러그인은 1.26 이상을 요구하고 1.27 이상을 권한다.
  • 권한 경계가 생긴다. 플러그인 Deployment는 자기 ServiceAccount로 동작하고, sidecar는 PostgreSQL Pod의 권한 안에서 object store 자격 증명(ObjectStore가 참조하는 Secret)을 쓴다. 자격 증명은 Operator가 아니라 데이터 경로 쪽에 있다.
  • 재시작 없이 갱신된다. 위에서 본 EndpointSlices 감시 덕에 플러그인 업그레이드는 Operator 재시작을 요구하지 않는다.

알려진 플러그인​

CNPG-I 프로젝트 저장소가 목록을 관리한다. 1.30 시점 기준이며 바뀔 수 있다.

플러그인성격용도
Barman Cloud CNPG-I Plugin공식object store 백업, WAL archive, 복구, PITR
CNPG-I Hello World공식 예제플러그인 개발 참고용
Scale-to-Zero Plugin (Xata)제3자유휴 Cluster를 자동 hibernation

제3자 플러그인은 CloudNativePG 프로젝트가 유지보수나 보안을 보증하지 않는다. 규격 저장소(cnpg-i)는 아직 Experimental로 표기되어 있다. 그와 별개로 Barman Cloud 플러그인은 CloudNativePG 프로젝트가 직접 관리하는 공식 컴포넌트이고 1.30 문서가 권장하는 object store 백업 경로다. 규격의 상태와 플러그인의 지원 상태는 따로 확인한다.

정리​

  • CNPG-I는 Operator 본체를 고치지 않고 수명주기의 정해진 지점을 외부 프로그램에 위임하는 gRPC 규격이다. 1.30에서 object store 백업은 이 경로가 정식이다.
  • 권장 배치는 독립 Deployment다. Service의 cnpg.io/pluginName label과 cnpg.io/pluginPort annotation으로 발견되고, mTLS로 통신하며, 1.30부터 Pod 교체를 EndpointSlices로 감지한다.
  • 제어는 Operator와 플러그인 Deployment 사이의 gRPC다. 데이터 경로는 구현이 정하며, Barman Cloud는 PostgreSQL Pod 안 sidecar에서 object store로 직접 보낸다.
  • Cluster에서는 .spec.plugins로 켜고, Backup의 method: plugin과 externalClusters의 plugin에서 다시 만난다. 플러그인의 가용성과 버전은 Operator와 따로 관리한다.