4.3 인스턴스 Pod 설정
CloudNativePG는 Cluster 선언만으로 인스턴스 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_ 접두어와 일부 이름은 예약되어 있고, 참조한 Secret·ConfigMap의 내용만 바뀐 경우는 수동 rollout이 필요하다. 배치는 affinity로 제어한다. 기본은 노드 분산(preferred)이고, required로 강제하거나 topologyKey를 바꿔 AZ 단위로 흩는다.
이것으로 Part IV를 마친다.