Taints와 Tolerations — 특정 노드에 Pod을 제한하거나 허용하는 방법
nodeSelector와 Affinity로 "원하는 노드에 가게" 할 수 있다면, "원치 않는 Pod이 못 오게"는 어떻게 할까요?
nodeSelector/Affinity는 Pod 관점에서 "이 노드에 배치해 주세요"라고 요청하는 것입니다. 반면 Taints와 Tolerations는 노드 관점에서 "이 조건을 허용하지 않는 Pod은 오지 마세요"라고 설정하는 것입니다. 두 가지를 조합하면 특정 노드를 특정 워크로드 전용으로 만들 수 있습니다.
Taint와 Toleration의 관계
- Taint: 노드에 설정하는 "오염 표시". 이 표시를 감수하지 않는 Pod은 배치 불가
- Toleration: Pod에 설정하는 "감수 선언". 특정 Taint를 허용함을 선언
# 노드에 Taint 추가
kubectl taint nodes node-1 gpu=true:NoSchedule
# 노드의 Taint 확인
kubectl describe node node-1 | grep Taint
# Taint 제거 (끝에 '-' 추가)
kubectl taint nodes node-1 gpu=true:NoSchedule-
Taint Effect 종류
| Effect | 새 Pod | 기존 Pod | 사용 사례 |
|---|---|---|---|
| NoSchedule | 스케줄 거부 | 유지 | 전용 노드 |
| PreferNoSchedule | 가능하면 회피 | 유지 | 소프트한 제한 |
| NoExecute | 스케줄 거부 | 퇴출 | 노드 장애 대응 |
NoSchedule
kubectl taint nodes node-1 dedicated=ml:NoSchedule
Toleration이 없는 새 Pod은 이 노드에 스케줄되지 않습니다. 이미 실행 중인 Pod은 영향을 받지 않습니다.
PreferNoSchedule
kubectl taint nodes node-1 preference=lowpriority:PreferNoSchedule
가능하면 다른 노드를 선택하지만, 다른 노드가 없으면 이 노드에도 스케줄합니다.
NoExecute
kubectl taint nodes node-1 maintenance=true:NoExecute
Toleration이 없는 기존 Pod까지 퇴출합니다. 노드 유지보수 시 유용합니다.
Toleration 설정
spec:
tolerations:
# 정확한 매칭 (Equal)
- key: "gpu"
operator: "Equal"
value: "true"
effect: "NoSchedule"
# 키만 매칭 (Exists) — value 무시
- key: "dedicated"
operator: "Exists"
effect: "NoSchedule"
# NoExecute + 유예 시간
- key: "maintenance"
operator: "Equal"
value: "true"
effect: "NoExecute"
tolerationSeconds: 300 # 300초 후 퇴출 (유예 시간)
tolerationSeconds
NoExecute Taint에 대해 유예 시간을 줍니다. Pod이 Graceful Shutdown을 수행할 시간을 확보할 수 있습니다.
모든 Taint를 허용하는 Toleration
tolerations:
- operator: "Exists" # key, value, effect 모두 생략 → 모든 Taint 허용
DaemonSet의 모니터링 에이전트처럼 모든 노드에서 실행해야 하는 Pod에 사용합니다.
시스템이 자동으로 추가하는 Taint
Kubernetes는 노드 상태에 따라 자동으로 Taint를 추가합니다.
| Taint | 조건 | Effect |
|---|---|---|
node.kubernetes.io/not-ready | 노드가 Ready 아님 | NoExecute |
node.kubernetes.io/unreachable | 노드와 통신 불가 | NoExecute |
node.kubernetes.io/memory-pressure | 메모리 부족 | NoSchedule |
node.kubernetes.io/disk-pressure | 디스크 부족 | NoSchedule |
node.kubernetes.io/pid-pressure | PID 부족 | NoSchedule |
node.kubernetes.io/unschedulable | cordon 상태 | NoSchedule |
Kubernetes는 모든 Pod에 기본적으로 not-ready와 unreachable에 대한 Toleration(tolerationSeconds: 300)을 자동 추가합니다. 즉, 노드 장애 시 5분간 기다린 후 Pod을 퇴출합니다.
GPU 노드 전용 설계
GPU 노드를 ML 워크로드 전용으로 만드는 전형적인 패턴입니다.
# GPU 노드에 Taint와 레이블 추가
kubectl taint nodes gpu-node-1 nvidia.com/gpu=true:NoSchedule
kubectl label nodes gpu-node-1 accelerator=nvidia-a100
# ML 워크로드 — Toleration + nodeSelector 조합
apiVersion: v1
kind: Pod
metadata:
name: ml-training
spec:
tolerations:
- key: "nvidia.com/gpu"
operator: "Equal"
value: "true"
effect: "NoSchedule"
nodeSelector:
accelerator: nvidia-a100
containers:
- name: training
image: pytorch:2.0
resources:
limits:
nvidia.com/gpu: 1
Taint만으로는 부족합니다. Taint는 "Toleration 없는 Pod을 거부"하지만, Toleration이 있는 일반 Pod이 GPU 노드에 배치되는 것은 막지 못합니다. nodeSelector를 함께 사용하여 ML 워크로드만 GPU 노드로 향하게 해야 합니다.
노드 유지보수
노드 업그레이드나 점검 시 워크로드를 안전하게 이동시킵니다.
# 1. 새 Pod 스케줄 차단 (cordon)
kubectl cordon node-1
# node/node-1 cordoned
# 2. 기존 Pod 안전하게 퇴출 (drain)
kubectl drain node-1 \
--ignore-daemonsets \ # DaemonSet Pod은 무시
--delete-emptydir-data \ # emptyDir 데이터 삭제 허용
--grace-period=60 # Graceful Shutdown 60초
# 3. 유지보수 수행...
# 4. 노드 복귀 (uncordon)
kubectl uncordon node-1
kubectl drain은 내부적으로 node.kubernetes.io/unschedulable:NoSchedule Taint를 추가하고, Eviction API로 Pod을 퇴출합니다.
Taint + Toleration + Affinity 조합 패턴
전용 노드 그룹
# 노드: Taint + 레이블
# kubectl taint nodes spot-1 node-type=spot:NoSchedule
# kubectl label nodes spot-1 node-type=spot
# Pod: Toleration + nodeAffinity
spec:
tolerations:
- key: "node-type"
operator: "Equal"
value: "spot"
effect: "NoSchedule"
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: node-type
operator: In
values: ["spot"]
Control Plane에 Pod 배포 (비권장)
tolerations:
- key: "node-role.kubernetes.io/control-plane"
operator: "Exists"
effect: "NoSchedule"
일반적으로 Control Plane에는 워크로드를 배포하지 않지만, 리소스가 부족한 소규모 클러스터에서는 사용할 수 있습니다.
실무에서 주의할 점
- Taint 설정은 신중하게: 잘못된 Taint는 Pod이 어디에도 스케줄되지 못하게 만들 수 있습니다
- drain 전에 PDB를 확인하세요: PodDisruptionBudget이 있으면 최소 가용 Pod 수를 보장합니다
- DaemonSet은 기본적으로 Toleration을 가집니다: system-critical DaemonSet은 대부분의 Taint를 허용합니다
- drain이 멈추면: PDB 제약이나 삭제 불가능한 Pod(local storage) 때문일 수 있습니다
정리
Taints는 노드 관점에서 "이 Pod은 오지 마"를, Tolerations는 Pod 관점에서 "이 Taint를 감수한다"를 선언합니다. GPU 전용 노드, 스팟 인스턴스 전용, 노드 유지보수 등 실무에서 자주 사용되며, nodeSelector/Affinity와 조합하면 강력한 노드 배치 전략을 구현할 수 있습니다.