6.7 테인트(Taints)와 톨러레이션(Tolerations)의 파드 할당 조건

🎯 학습 목표

  • 테인트와 톨러레이션의 동작 원리 이해
  • Equal/Exists 연산자별 매칭 규칙 습득
  • 실제 YAML 코드 작성 및 적용 방법 학습

📋 기본 개념

테인트(Taints)

  • 노드에 설정되어 특정 파드의 스케줄링을 제한하는 메커니즘
  • Key, Value, Effect 3가지 요소로 구성

톨러레이션(Tolerations)

  • 파드에 설정되어 테인트가 있는 노드에 스케줄링될 수 있도록 허용하는 메커니즘
  • 테인트와 매칭되는 Key, Value, EffectOperator 설정

🛠️ 실습 환경 설정

노드에 테인트 설정

# 노드에 테인트 추가
kubectl taint nodes <node-name> key=value:NoSchedule
 
# 예시: worker 노드에 특수 용도 테인트 설정
kubectl taint nodes worker1 special=true:NoSchedule
kubectl taint nodes worker2 gpu=nvidia:NoSchedule
 
# 테인트 확인
kubectl describe node <node-name> | grep Taints
 
# 테인트 제거
kubectl taint nodes <node-name> key=value:NoSchedule-

마스터 노드 테인트 확인

# 마스터 노드의 기본 테인트 확인
kubectl describe node master | grep Taints
# 일반적으로: node-role.kubernetes.io/master:NoSchedule

🔍 매칭 규칙

Operator: Equal (값 비교)

✅ 파드 할당 성공 조건

  1. 모든 요소 완전 일치

    • 테인트: K=a, V=1, E=NoSchedule
    • 톨러레이션: K=a, V=1, E=NoSchedule
    • 결과: K(O), V(O), E(O) → ✅ 배포 가능
  2. Value 생략 (와일드카드)

    • 테인트: K=a, V=1, E=NoSchedule
    • 톨러레이션: K=a, V=-, E=NoSchedule
    • 결과: K(O), V(-), E(O) → ✅ 배포 가능

❌ 파드 할당 거부 조건

  1. Key 불일치

    • 테인트: K=a, V=1, E=NoSchedule
    • 톨러레이션: K=b, V=1, E=NoSchedule
    • 결과: K(X), V(X), E(X) → ❌ 배포 불가
  2. Value만 불일치

    • 테인트: K=a, V=1, E=NoSchedule
    • 톨러레이션: K=a, V=2, E=NoSchedule
    • 결과: K(O), V(X), E(X) → ❌ 배포 불가
  3. Effect만 불일치

    • 테인트: K=a, V=1, E=NoSchedule
    • 톨러레이션: K=a, V=1, E=PreferNoSchedule
    • 결과: K(O), V(O), E(X) → ❌ 배포 불가

Operator: Exists (존재 여부만 확인)

✅ 파드 할당 성공 조건

  1. Key와 Effect 일치, Value 무시

    • 테인트: K=a, V=1, E=NoSchedule
    • 톨러레이션: K=a, E=NoSchedule (Operator: Exists)
    • 결과: K(O), E(O) → ✅ 배포 가능
  2. Key만 일치, Effect 생략

    • 테인트: K=a, V=1, E=NoSchedule
    • 톨러레이션: K=a (Operator: Exists)
    • 결과: K(O) → ✅ 배포 가능 (모든 Effect 허용)
  3. 완전 와일드카드

    • 테인트: K=a, V=1, E=NoSchedule
    • 톨러레이션: (빈 톨러레이션, Operator: Exists)
    • 결과: ✅ 모든 테인트 무시하고 배포 가능

🔧 YAML 코드 예제

1. Equal 연산자 예제

기본 톨러레이션 (완전 일치)

# pod-with-toleration-equal.yaml
apiVersion: v1
kind: Pod
metadata:
  name: pod-equal-match
spec:
  tolerations:
  - key: "special"
    operator: "Equal"
    value: "true"
    effect: "NoSchedule"
  containers:
  - name: nginx
    image: nginx:1.20

Value 생략 톨러레이션

# pod-with-toleration-equal-wildcard.yaml
apiVersion: v1
kind: Pod
metadata:
  name: pod-equal-wildcard
spec:
  tolerations:
  - key: "special"
    operator: "Equal"
    # value 생략 - 모든 값에 대해 허용
    effect: "NoSchedule"
  containers:
  - name: nginx
    image: nginx:1.20

2. Exists 연산자 예제

Key와 Effect 매칭

# pod-with-toleration-exists.yaml
apiVersion: v1
kind: Pod
metadata:
  name: pod-exists-match
spec:
  tolerations:
  - key: "gpu"
    operator: "Exists"
    effect: "NoSchedule"
  containers:
  - name: cuda-app
    image: nvidia/cuda:11.0-base

Key만 매칭 (Effect 생략)

# pod-with-toleration-exists-key-only.yaml
apiVersion: v1
kind: Pod
metadata:
  name: pod-exists-key-only
spec:
  tolerations:
  - key: "special"
    operator: "Exists"
    # effect 생략 - 모든 effect에 대해 허용
  containers:
  - name: nginx
    image: nginx:1.20

완전 와일드카드 (모든 테인트 허용)

# pod-with-toleration-wildcard.yaml
apiVersion: v1
kind: Pod
metadata:
  name: pod-wildcard-toleration
spec:
  tolerations:
  - operator: "Exists"
    # key, value, effect 모두 생략 - 모든 테인트 허용
  containers:
  - name: nginx
    image: nginx:1.20

3. 다중 톨러레이션 예제

# pod-with-multiple-tolerations.yaml
apiVersion: v1
kind: Pod
metadata:
  name: pod-multiple-tolerations
spec:
  tolerations:
  - key: "special"
    operator: "Equal"
    value: "true"
    effect: "NoSchedule"
  - key: "gpu"
    operator: "Exists"
    effect: "NoSchedule"
  - key: "dedicated"
    operator: "Equal"
    value: "database"
    effect: "NoExecute"
    tolerationSeconds: 3600  # 1시간 후 eviction
  containers:
  - name: multi-toleration-app
    image: nginx:1.20

4. tolerationSeconds 활용 예제

# pod-with-toleration-seconds.yaml
apiVersion: v1
kind: Pod
metadata:
  name: pod-with-time-limit
spec:
  tolerations:
  - key: "maintenance"
    operator: "Equal"
    value: "true"
    effect: "NoExecute"
    tolerationSeconds: 300  # 5분 후 eviction
  containers:
  - name: temporary-app
    image: nginx:1.20

🧪 실습 시나리오

시나리오 1: 특수 목적 노드 구성

# 1. GPU 전용 노드 테인트 설정
kubectl taint nodes worker-gpu gpu=nvidia:NoSchedule
 
# 2. GPU 워크로드 파드 배포
kubectl apply -f - <<EOF
apiVersion: v1
kind: Pod
metadata:
  name: gpu-workload
spec:
  tolerations:
  - key: "gpu"
    operator: "Equal"
    value: "nvidia"
    effect: "NoSchedule"
  containers:
  - name: cuda-app
    image: nvidia/cuda:11.0-base
    command: ["sleep", "3600"]
  nodeSelector:
    gpu: "nvidia"
EOF
 
# 3. 결과 확인
kubectl get pods -o wide
kubectl describe pod gpu-workload

시나리오 2: 데이터베이스 전용 노드

# 1. 데이터베이스 전용 노드 설정
kubectl taint nodes worker-db dedicated=database:NoSchedule
kubectl taint nodes worker-db dedicated=database:NoExecute
 
# 2. 데이터베이스 파드 배포
kubectl apply -f - <<EOF
apiVersion: v1
kind: Pod
metadata:
  name: database-pod
spec:
  tolerations:
  - key: "dedicated"
    operator: "Equal"
    value: "database"
    effect: "NoSchedule"
  - key: "dedicated"
    operator: "Equal"
    value: "database"
    effect: "NoExecute"
  containers:
  - name: mysql
    image: mysql:8.0
    env:
    - name: MYSQL_ROOT_PASSWORD
      value: "password"
  nodeSelector:
    dedicated: "database"
EOF

시나리오 3: 마스터 노드에 파드 배포

# 1. 마스터 노드 테인트 확인
kubectl describe node master | grep Taints
 
# 2. 마스터 노드에 배포 가능한 파드 생성
kubectl apply -f - <<EOF
apiVersion: v1
kind: Pod
metadata:
  name: master-pod
spec:
  tolerations:
  - key: "node-role.kubernetes.io/master"
    operator: "Exists"
    effect: "NoSchedule"
  containers:
  - name: nginx
    image: nginx:1.20
  nodeSelector:
    kubernetes.io/hostname: "master"
EOF

🔬 트러블슈팅 가이드

일반적인 문제와 해결방법

1. 파드가 Pending 상태로 남아있는 경우

# 문제 진단
kubectl describe pod <pod-name>
kubectl get events --sort-by='.lastTimestamp'
 
# 노드 테인트 확인
kubectl describe nodes | grep -A5 Taints
 
# 해결방법: 적절한 톨러레이션 추가 또는 테인트 제거

2. 마스터 노드에 파드가 스케줄되지 않는 경우

# 마스터 노드 테인트 확인
kubectl describe node master | grep Taints
 
# 해결방법: 마스터 노드용 톨러레이션 추가
tolerations:
- key: "node-role.kubernetes.io/master"
  operator: "Exists"
  effect: "NoSchedule"

3. NoExecute 테인트로 인한 예상치 못한 파드 종료

# 이벤트 로그 확인
kubectl get events --field-selector involvedObject.name=<pod-name>
 
# 해결방법: tolerationSeconds 조정 또는 적절한 톨러레이션 추가
tolerations:
- key: "maintenance"
  operator: "Equal"
  value: "true" 
  effect: "NoExecute"
  tolerationSeconds: 7200  # 2시간으로 연장

테스트 및 검증 명령어

# 1. 모든 노드의 테인트 상태 확인
kubectl get nodes -o custom-columns=NAME:.metadata.name,TAINTS:.spec.taints --no-headers
 
# 2. 특정 테인트가 있는 노드 찾기
kubectl get nodes -o json | jq '.items[] | select(.spec.taints[]?.key=="gpu") | .metadata.name'
 
# 3. 파드의 톨러레이션 확인
kubectl get pod <pod-name> -o jsonpath='{.spec.tolerations}'
 
# 4. 노드별 파드 배치 현황 확인
kubectl get pods -o wide --all-namespaces | grep <node-name>

📚 심화 학습 내용

1. 시스템 기본 톨러레이션

쿠버네티스는 특정 상황에서 자동으로 톨러레이션을 추가합니다:

# DaemonSet은 기본적으로 다음 톨러레이션을 가집니다
tolerations:
- effect: NoSchedule
  operator: Exists
- key: CriticalAddonsOnly
  operator: Exists
- effect: NoExecute
  operator: Exists

2. PodDisruptionBudget과의 연관성

# NoExecute와 PDB 함께 사용 예제
apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
  name: db-pdb
spec:
  minAvailable: 2
  selector:
    matchLabels:
      app: database

3. 클러스터 오토스케일러와 테인트

# 오토스케일러가 테인트된 노드를 고려하도록 설정
cluster-autoscaler.kubernetes.io/safe-to-evict: "true"

⚠️ 주의사항 및 베스트 프랙티스

주의사항

  1. NoExecute 사용 시 주의: 기존 파드를 즉시 종료시킬 수 있음
  2. tolerationSeconds 적절히 설정: 너무 짧으면 서비스 중단, 너무 길면 리소스 낭비
  3. 와일드카드 톨러레이션 남용 금지: 보안상 위험할 수 있음

베스트 프랙티스

  1. 목적별 네이밍 컨벤션 사용:

    # 좋은 예
    kubectl taint nodes gpu-node1 hardware=gpu:NoSchedule
    kubectl taint nodes db-node1 workload=database:NoSchedule
     
    # 나쁜 예  
    kubectl taint nodes worker1 a=b:NoSchedule
  2. 문서화 및 라벨링:

    kubectl label nodes gpu-node1 description="GPU-enabled node for ML workloads"
  3. 단계적 적용:

    # 1단계: PreferNoSchedule로 시작
    kubectl taint nodes worker1 special=true:PreferNoSchedule
     
    # 2단계: 검증 후 NoSchedule로 변경
    kubectl taint nodes worker1 special=true:PreferNoSchedule-
    kubectl taint nodes worker1 special=true:NoSchedule

❌ 파드 할당 거부 조건

  1. Key 불일치

    • 테인트: K=a, V=1, E=NoSchedule
    • 톨러레이션: K=b, E=NoSchedule (Operator: Exists)
    • 결과: K(X) → ❌ 배포 불가
  2. Effect 불일치

    • 테인트: K=a, V=1, E=NoSchedule
    • 톨러레이션: K=a, E=PreferNoSchedule (Operator: Exists)
    • 결과: K(O), E(X) → ❌ 배포 불가

🎯 Effect 유형

Effect설명
NoSchedule가장 기본적인 설정. 노드에 테인트가 설정되어 있지 않은 경우 파드가 노드에 스케줄되지 않음. 톨러레이션을 통한 배포만 가능
PreferNoScheduleNoSchedule과 유사하지만 스케줄러에서 더 이상 할당할 수 있는 노드가 없는 경우 테인트 설정을 무시하고 스케줄함
NoExecuteNoSchedule에 현재 할당된 파드에도 바로 적용되도록 스케줄을 다시 조정하는 기능 추가. 톨러레이션이 없는 파드는 모두 노드에서 제거함

💡 핵심 정리

Equal 연산자

  • 엄격한 매칭: Key, Value, Effect가 정확히 일치해야 함
  • Value 생략 가능: -로 표시하면 Value 무시
  • 하나라도 불일치하면 배포 불가

Exists 연산자

  • 느슨한 매칭: Key의 존재만 확인, Value는 자동 무시
  • Effect는 여전히 중요: Effect가 일치해야 함
  • 완전 와일드카드 가능: 모든 항목 생략 시 모든 테인트 허용

📖 범례

기호의미
O값을 입력하며 일치
X값을 입력하며 불일치
-값을 입력하지 않고 생략
KKey
VValue
EEffect

출처: 컨테이너 인프라 환경 구축을 위한 쿠버네티스/도커
제작: 조훈심, 근우문, 성주
관련 강의:

  1. 쉽게 시작하는 쿠버네티스
  2. 그림으로 배우는 쿠버네티스
  3. 실습으로 배우는 프로메테우스