스케줄러는 기본적으로 파드를 알아서 배치합니다. 하지만 "캐시 파드는 웹 파드와 같은 노드에 붙여라" 또는 "DB 복제본 3개는 서로 다른 노드에 흩어라" 같은 요구가 생기면 직접 제어해야 합니다. 이때 쓰는 게 **Pod Affinity(같이 두기)**와 **Pod Anti-Affinity(떨어뜨리기)**입니다. 노드 라벨이 아니라 다른 파드의 위치를 기준으로 스케줄링한다는 점이 핵심입니다.
required vs preferred
| 종류 | 의미 | 충족 못 하면 |
|---|---|---|
requiredDuringScheduling... | 반드시 만족 | 파드가 Pending 상태로 대기 |
preferredDuringScheduling... | 가능하면 만족 | 무시하고 그냥 배치 |
required는 강제라 조건을 못 채우면 영영 안 뜹니다. preferred는 점수 가중치(weight)일 뿐이라 안전합니다. 운영에서 대부분의 분산 요구는 preferred로 충분합니다.
같이 두기 — Affinity
캐시를 웹 파드와 같은 노드에 두는 예시입니다.
spec:
affinity:
podAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchLabels:
app: web
topologyKey: kubernetes.io/hostname
topologyKey가 핵심입니다. kubernetes.io/hostname이면 "같은 노드", topology.kubernetes.io/zone이면 "같은 가용영역"을 기준으로 묶습니다.
떨어뜨리기 — Anti-Affinity
DB 복제본이 서로 다른 노드에 흩어지게 합니다. 한 노드가 죽어도 전부 같이 죽지 않게요.
spec:
affinity:
podAntiAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 100
podAffinityTerm:
labelSelector:
matchLabels:
app: db
topologyKey: kubernetes.io/hostname
labelSelector가 자기 자신과 같은 라벨(app: db)을 가리킨다는 점에 주의하세요. "나와 같은 라벨의 파드가 있는 노드는 피해라"는 뜻입니다.
흔한 함정 — 파드가 Pending
required 안티어피니티로 "노드당 1개"를 강제했는데 노드 수보다 replicas가 많으면, 남는 파드는 갈 곳이 없어 Pending에 빠집니다.
kubectl describe pod <pod>
# Events: 0/3 nodes are available: 3 node(s) didn't match pod anti-affinity rules.
이럴 땐 replicas를 노드 수 이하로 줄이거나, required를 preferred로 바꿔 강제를 풉니다.
체크리스트
kubectl get pods -o wide # 의도대로 모였는지/흩어졌는지
kubectl describe pod <pod> # Pending 사유 확인
kubectl get nodes -L topology.kubernetes.io/zone # zone 라벨 확인
topologyKey로 쓰는 라벨이 노드에 실제로 붙어 있는지 먼저 확인하는 게 디버깅의 출발점입니다.
affinity 규칙을 직접 걸고 파드가 어디로 가는지 관찰하는 실습은 쿠버네티스 트랙에서 해볼 수 있습니다 — 회원가입 없이 무료로.