본문으로 건너뛰기
4.3 인스턴스 Pod 설정

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: 1Gi

Ephemeral 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: 1Gi
spec.ephemeralVolumeSourcespec.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: 1Gi

ConfigMap·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: 1Gi

PGCNPG_로 시작하는 이름, 그리고 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)에 걸쳐 흩뿌리려면 topologyKeytopology.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 전용 노드에만, 그리고 반드시 서로 다른 노드에 배치된다.

scheduling 세부 옵션은 Part V(스토리지와 리소스)에서 resource·storage와 함께 더 다룬다. 여기서는 인스턴스 Pod 조정의 한 축으로 배치 제어를 짚어 둔다.

Sidecar 주의점

Barman Cloud 플러그인처럼 WAL archiver를 native sidecar(restartPolicy: Always인 init container)로 주입하는 경우가 있다. Operator는 이런 sidecar가 붙도록 primary Pod를 in-place로 재생성해 archiving을 이어간다.

Istio 같은 service mesh의 sidecar 주입이 켜져 있으면, 기동 초반 네트워크가 잠시 불통이 되어 클러스터 초기화가 실패할 수 있다. 초기화 중 네트워킹 문제가 보이면 sidecar 주입을 끄고 다시 시도한다.

정리

  • projectedVolumeTemplate로 추가 파일을 /projected에 마운트
  • ephemeral volume은 기본 emptyDir, ephemeralVolumeSource로 저장소 교체 (Size limit과 동시 지정 불가)
  • env·envFrom으로 환경 변수 주입 — PG·CNPG_ 접두어와 일부 이름은 예약, 참조 대상 내용 변경은 수동 rollout 필요
  • affinity로 배치 제어 — 기본은 노드 분산(preferred), required로 강제, AZ 분산은 topologyKey 변경
  • service mesh sidecar 주입은 초기화 실패 원인이 될 수 있음

이것으로 Part IV를 마친다. 다음 Part에서는 스토리지와 리소스 관리를 다룬다.