5.4 Scheduling
Kubernetes scheduler는 Pod를 어느 노드에 올릴지 자동으로 정한다. 대개는 맡겨 두면 되지만, PostgreSQL 같은 데이터베이스는 배치에 신경 써야 한다. primary와 replica가 같은 노드에 몰려 있으면 그 노드 하나가 죽는 순간 클러스터 전체가 흔들린다. CloudNativePG는 .spec.affinity 아래에서 pod anti-affinity, nodeSelector, toleration을 설정해 이런 배치를 통제한다.
pod anti-affinity 기본 동작
CNPG는 별도 설정이 없어도 인스턴스를 서로 다른 노드에 나눠 배치하려 한다. 기본값은 다음과 같다.
enablePodAntiAffinity: truetopologyKey: kubernetes.io/hostnamepodAntiAffinityType: preferred
이 설정은 같은 클러스터의 인스턴스끼리 서로를 피하는 preferredDuringSchedulingIgnoredDuringExecution 규칙을 생성한다.
flowchart TD
subgraph N1[Node A]
P1[Primary Pod]
end
subgraph N2[Node B]
P2[Replica Pod]
end
subgraph N3[Node C]
P3[Replica Pod]
end
P1 -.anti-affinity.-> P2
P1 -.anti-affinity.-> P3
P2 -.anti-affinity.-> P3
preferred vs required
anti-affinity를 얼마나 강하게 강제할지가 podAntiAffinityType으로 갈린다.
| 유형 | 동작 | 위험 |
|---|---|---|
| preferred (기본) | 최대한 분산하되, 여의치 않으면 같은 노드에도 배치 | 없음 |
| required | 규칙을 강제해 조건을 못 맞추면 Pod를 pending으로 둠 | 자원 부족 시 pending 지속 |
required로 두면 노드가 부족할 때 Pod가 뜨지 못하고 계속 pending에 머문다. 특히 Cluster Autoscaler를 함께 쓸 때 주의해야 한다.
podAntiAffinityType: required는 “반드시 서로 다른 노드에"를 강제한다. 노드 수가 인스턴스 수보다 적거나 자원이 모자라면 Pod가 스케줄되지 못해 pending으로 남는다. 가용 노드 여유가 확실할 때만 required를 선택한다.가용 영역 단위 분산
클라우드 환경에서는 노드 단위보다 availability zone 단위로 분산하는 편이 낫다. topologyKey를 kubernetes.io/hostname 대신 topology.kubernetes.io/zone으로 바꾸면 Pod가 서로 다른 가용 영역에 흩어진다.
nodeSelector, taint, toleration
특정 노드에만 PostgreSQL을 올리려면 두 장치를 함께 쓴다.
- nodeSelector:
.spec.affinity아래에 key-value 라벨을 지정해, 그 라벨을 가진 노드에만 Pod를 배치한다. “여기에만 올려라"라는 조건이다. - taint·toleration: taint는 노드가 “특정 조건을 견디는(tolerate) Pod만 받겠다"고 거는 표식이고, toleration은 Pod가 그 taint를 견딘다는 선언이다. 데이터베이스 전용 노드를 만들어 다른 워크로드가 침범하지 못하게 할 때 쓴다.
flowchart TD
POD[PostgreSQL Pod] --> NS{nodeSelector<br/>라벨 일치?}
NS -->|아니오| SKIP[해당 노드 제외]
NS -->|예| TT{taint를<br/>tolerate?}
TT -->|아니오| SKIP
TT -->|예| PLACE[노드에 배치]
전용 노드에 클러스터를 격리하는 구성은 다음과 같다.
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 전용 노드에만 PostgreSQL을 올리고(nodeSelector + toleration), 인스턴스들을 서로 다른 노드에 강제 분산한다(required anti-affinity).
규칙 비활성화·커스터마이징
enablePodAntiAffinity: false로 두면 Operator가 만드는 anti-affinity 정책을 끈다. 기본 규칙을 보완하거나 대체하는 커스텀 규칙이 필요하면 additionalPodAffinity·additionalPodAntiAffinity를 쓴다. 아래 예시는 모든 클러스터를 통틀어 워커 노드당 PostgreSQL 인스턴스를 하나만 허용한다.
additionalPodAntiAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchExpressions:
- key: postgresql
operator: Exists
values: []
topologyKey: "kubernetes.io/hostname"additionalPodAntiAffinity는 CNPG가 자동 생성하는 규칙에 더해 적용된다. 기본 규칙을 완전히 대체하려면 enablePodAntiAffinity: false로 자동 규칙을 끈 뒤 커스텀 규칙만 남기는 편이 예측하기 쉽다.여기까지가 스토리지와 리소스 파트다. PVC와 WAL 볼륨 분리로 데이터를 안전하게 담고, requests/limits와 QoS로 자원을 확보하며, tablespace로 데이터를 나누고, affinity·taint로 Pod를 원하는 노드에 배치하는 흐름을 짚었다. 이 네 가지는 운영 환경 클러스터를 설계할 때 함께 맞물려 결정된다.