4.3 인스턴스 Pod 설정
CloudNativePG는 Cluster 선언만으로 인스턴스 Pod를 알아서 만들지만, 실제 운영에서는 이 Pod에 손을 대야 할 때가 많다. 파일을 추가로 마운트하거나, 환경 변수를 넣거나, 어느 노드에 어떻게 배치할지 정하는 일이다. 이 절에서는 인스턴스 Pod를 조정하는 주요 방법을 살펴본다.
flowchart TD
CLUSTER["Cluster spec"]
PROJ["projectedVolume<br/>파일 마운트"]
EPH["ephemeralVolume<br/>임시 저장소"]
ENV["env·envFrom<br/>환경 변수"]
SCHED["affinity<br/>배치 제어"]
POD["인스턴스 Pod"]
CLUSTER --> PROJ --> POD
CLUSTER --> EPH --> POD
CLUSTER --> ENV --> POD
CLUSTER --> SCHED --> POD
Projected volume: 파일 마운트
spec.projectedVolumeTemplate로 임의의 파일을 Pod의 /projected 아래에 마운트할 수 있다. 추가 데이터 파일이 필요한 PostgreSQL 기능이나 extension에 유용하다.
apiVersion: postgresql.cnpg.io/v1
kind: Cluster
metadata:
name: cluster-example-projected-volumes
spec:
instances: 3
projectedVolumeTemplate:
sources:
- secret:
name: sample-secret
items:
- key: tls.crt
path: certificate/tls.crt
- key: tls.key
path: certificate/tls.key
storage:
size: 1GiEphemeral volume: 임시 저장소
CloudNativePG는 내부 작업에 ephemeral volume을 사용한다. Pod 수명 동안만 존재하는 저장소다. 기본은 emptyDir이며 spec.ephemeralVolumesSizeLimit으로 상한을 조정한다. 다른 저장소 소스가 필요하면 spec.ephemeralVolumeSource로 덮어쓴다.
apiVersion: postgresql.cnpg.io/v1
kind: Cluster
metadata:
name: cluster-example-ephemeral-volume-source
spec:
instances: 3
ephemeralVolumeSource:
volumeClaimTemplate:
spec:
accessModes: ["ReadWriteOnce"]
storageClassName: "scratch-storage-class"
resources:
requests:
storage: 1Gispec.ephemeralVolumeSource와 spec.ephemeralVolumesSizeLimit.temporaryData를 동시에 지정할 수는 없다. POSIX 공유 메모리를 동적으로 쓰는 PostgreSQL이라면 spec.ephemeralVolumesSizeLimit.shm으로 shared memory 상한을 따로 잡는다.환경 변수: env·envFrom
시스템 동작을 바꾸는 환경 변수를 넣을 수 있다. 예를 들어 LDAP 설정용 LDAPCONF나 시간대 TZ 같은 것이다.
값을 직접 넣는 env:
apiVersion: postgresql.cnpg.io/v1
kind: Cluster
metadata:
name: cluster-example
spec:
instances: 3
env:
- name: TZ
value: Australia/Sydney
storage:
size: 1GiConfigMap·Secret에서 통째로 가져오는 envFrom:
apiVersion: postgresql.cnpg.io/v1
kind: Cluster
metadata:
name: cluster-example
spec:
instances: 3
envFrom:
- configMapRef:
name: config-map-name
- secretRef:
name: secret-name
storage:
size: 1GiPG나 CNPG_로 시작하는 이름, 그리고 POD_NAME·NAMESPACE·CLUSTER_NAME은 예약되어 있어 admission 단계에서 거부된다.
env·envFrom 자체를 바꾸면 rolling update가 트리거된다. 다만 참조한 Secret·ConfigMap의 내용이 바뀐 것은 Operator가 감지하지 못하므로, 그때는 수동으로 Pod rollout을 걸어야 반영된다.
배치 제어: affinity·nodeSelector·tolerations
인스턴스 Pod를 어느 노드에 어떻게 흩뿌릴지는 spec.affinity에서 정한다. CloudNativePG는 기본적으로 인스턴스를 서로 다른 노드에 배치하려 한다. 한 노드가 죽어도 클러스터 전체가 함께 내려가지 않게 하기 위함이다.
기본 설정은 다음과 같다.
affinity:
enablePodAntiAffinity: true # 기본값
topologyKey: kubernetes.io/hostname # 기본값
podAntiAffinityType: preferred # 기본값podAntiAffinityType은 분리의 강도다.
preferred— 가능하면 다른 노드에, 여의치 않으면 같은 노드도 허용 (기본)required— 반드시 다른 노드에. 노드가 부족하면 Pod가 pending으로 남는다
여러 가용 영역(AZ)에 걸쳐 흩뿌리려면 topologyKey를 topology.kubernetes.io/zone으로 바꾼다.
더 세밀한 규칙이 필요하면 additionalPodAffinity·additionalPodAntiAffinity로 직접 지정한다.
additionalPodAntiAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchExpressions:
- key: postgresql
operator: Exists
values: []
topologyKey: "kubernetes.io/hostname"nodeSelector는 특정 label을 가진 노드로만 배치를 제한하고, tolerations는 taint가 걸린 노드에도 배치할 수 있게 한다. PostgreSQL 전용 노드 풀에 격리하는 운영 예는 다음과 같다.
affinity:
enablePodAntiAffinity: true
topologyKey: kubernetes.io/hostname
podAntiAffinityType: required
nodeSelector:
node-role.kubernetes.io/postgres: ""
tolerations:
- key: node-role.kubernetes.io/postgres
operator: Exists
effect: NoSchedule이렇게 하면 인스턴스는 postgres 전용 노드에만, 그리고 반드시 서로 다른 노드에 배치된다.
Sidecar 주의점
Barman Cloud 플러그인처럼 WAL archiver를 native sidecar(restartPolicy: Always인 init container)로 주입하는 경우가 있다. Operator는 이런 sidecar가 붙도록 primary Pod를 in-place로 재생성해 archiving을 이어간다.
정리
projectedVolumeTemplate로 추가 파일을/projected에 마운트- ephemeral volume은 기본
emptyDir,ephemeralVolumeSource로 저장소 교체 (Size limit과 동시 지정 불가) env·envFrom으로 환경 변수 주입 —PG·CNPG_접두어와 일부 이름은 예약, 참조 대상 내용 변경은 수동 rollout 필요affinity로 배치 제어 — 기본은 노드 분산(preferred),required로 강제, AZ 분산은topologyKey변경- service mesh sidecar 주입은 초기화 실패 원인이 될 수 있음
이것으로 Part IV를 마친다. 다음 Part에서는 스토리지와 리소스 관리를 다룬다.