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

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

이것으로 Part IV를 마친다.