Theme:

nodeSelector와 Affinity로 "원하는 노드에 가게" 할 수 있다면, "원치 않는 Pod이 못 오게"는 어떻게 할까요?

nodeSelector/Affinity는 Pod 관점에서 "이 노드에 배치해 주세요"라고 요청하는 것입니다. 반면 Taints와 Tolerations는 노드 관점에서 "이 조건을 허용하지 않는 Pod은 오지 마세요"라고 설정하는 것입니다. 두 가지를 조합하면 특정 노드를 특정 워크로드 전용으로 만들 수 있습니다.

Taint와 Toleration의 관계

  • Taint: 노드에 설정하는 "오염 표시". 이 표시를 감수하지 않는 Pod은 배치 불가
  • Toleration: Pod에 설정하는 "감수 선언". 특정 Taint를 허용함을 선언
SHELL
# 노드에 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

SHELL
kubectl taint nodes node-1 dedicated=ml:NoSchedule

Toleration이 없는 새 Pod은 이 노드에 스케줄되지 않습니다. 이미 실행 중인 Pod은 영향을 받지 않습니다.

PreferNoSchedule

SHELL
kubectl taint nodes node-1 preference=lowpriority:PreferNoSchedule

가능하면 다른 노드를 선택하지만, 다른 노드가 없으면 이 노드에도 스케줄합니다.

NoExecute

SHELL
kubectl taint nodes node-1 maintenance=true:NoExecute

Toleration이 없는 기존 Pod까지 퇴출합니다. 노드 유지보수 시 유용합니다.

Toleration 설정

YAML
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

YAML
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-pressurePID 부족NoSchedule
node.kubernetes.io/unschedulablecordon 상태NoSchedule

Kubernetes는 모든 Pod에 기본적으로 not-ready와 unreachable에 대한 Toleration(tolerationSeconds: 300)을 자동 추가합니다. 즉, 노드 장애 시 5분간 기다린 후 Pod을 퇴출합니다.

GPU 노드 전용 설계

GPU 노드를 ML 워크로드 전용으로 만드는 전형적인 패턴입니다.

SHELL
# GPU 노드에 Taint와 레이블 추가
kubectl taint nodes gpu-node-1 nvidia.com/gpu=true:NoSchedule
kubectl label nodes gpu-node-1 accelerator=nvidia-a100
YAML
# 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 노드로 향하게 해야 합니다.

노드 유지보수

노드 업그레이드나 점검 시 워크로드를 안전하게 이동시킵니다.

SHELL
# 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 조합 패턴

전용 노드 그룹

YAML
# 노드: 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 배포 (비권장)

YAML
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와 조합하면 강력한 노드 배치 전략을 구현할 수 있습니다.

댓글 로딩 중...