[Kubernetes] Taint & Toleration, Cordon & Drain은 왜 필요할까?

굿굿·2026년 5월 29일

CI/CD

목록 보기
73/73

쿠버네티스에서 Pod는 기본적으로 Scheduler가 적절한 Node를 골라 배치한다.

Pod 생성
   ↓
Scheduler가 Node 선택
   ↓
선택된 Node에서 Pod 실행

그런데 운영하다 보면 이런 상황이 생긴다.

특정 Node에는 아무 Pod나 못 올라오게 하고 싶다.
GPU Node에는 GPU 작업만 올리고 싶다.
장애가 난 Node에는 더 이상 Pod를 배치하고 싶지 않다.
Node 점검 전에 기존 Pod들을 다른 Node로 옮기고 싶다.

이때 자주 나오는 개념이 바로 이것들이다.

taint
toleration
cordon
drain

처음 보면 다 비슷해 보인다.

하지만 역할이 다르다.

큰 그림으로 먼저 보면 이렇다.

taint / toleration
= 특정 Node에 어떤 Pod가 들어올 수 있는지 제한

cordon
= Node에 새 Pod가 더 이상 스케줄링되지 않게 막음

drain
= Node에 있던 기존 Pod들을 내보냄

1. 먼저 Node 배치를 생각해보자

쿠버네티스에서 Pod는 아무 Node에나 뜨는 것처럼 보이지만, 실제로는 Scheduler가 여러 조건을 보고 배치한다.

Node 자원이 충분한가?
Node가 Ready 상태인가?
Pod가 요구하는 nodeSelector가 있는가?
Node에 taint가 걸려 있는가?
Pod가 그 taint를 toleration할 수 있는가?

여기서 taint와 toleration은 Node와 Pod 사이의 출입 제한 규칙이라고 보면 된다.


1부. Taint & Toleration

2. Taint란?

Taint는 Node에 붙이는 “오염 표시” 또는 “출입 제한 표시”다.

조금 더 쉽게 말하면 이렇다.

Taint
= 이 Node에는 아무 Pod나 들어오지 못하게 하는 표시

예를 들어 GPU Node가 있다고 하자.

gpu-worker-1

이 Node는 비싼 GPU가 달려 있다.

그런데 일반 nginx Pod나 테스트 Pod가 막 올라오면 아깝다.

그래서 이 Node에 taint를 걸 수 있다.

kubectl taint nodes gpu-worker-1 dedicated=gpu:NoSchedule

이 뜻은 이렇다.

gpu-worker-1 Node에는 dedicated=gpu taint가 있다.
이 taint를 견딜 수 없는 Pod는 스케줄링하지 마라.

즉 taint는 Node 쪽에서 거는 제한이다.

Node: 아무나 들어오지 마.

3. Toleration이란?

Toleration은 Pod에 붙이는 “허용증”이다.

Taint가 걸린 Node에 들어가려면 Pod가 그 taint를 견딜 수 있어야 한다.

즉 toleration은 이런 의미다.

Toleration
= 나는 이 taint가 걸린 Node에도 들어갈 수 있다.

예를 들어 Node에 이런 taint가 있다.

dedicated=gpu:NoSchedule

그러면 Pod에는 이런 toleration을 넣어야 한다.

tolerations:
  - key: "dedicated"
    operator: "Equal"
    value: "gpu"
    effect: "NoSchedule"

이 뜻은 이렇다.

나는 dedicated=gpu:NoSchedule taint를 견딜 수 있다.
그래서 그 Node에 스케줄링될 수 있다.

정리하면 이렇다.

Taint
= Node가 거는 제한

Toleration
= Pod가 가진 통과권

4. Taint와 Toleration 비유

비유하면 이해하기 쉽다.

Taint
= 출입 제한 구역 표시

Toleration
= 출입 허가증

예를 들어 GPU Node는 이런 문구가 붙어 있는 방이다.

GPU 작업 전용 구역
허가증 없는 사람 출입 금지

일반 Pod는 허가증이 없다.

일반 Pod
→ 들어갈 수 없음

GPU 작업 Pod는 허가증이 있다.

GPU Pod
→ toleration 있음
→ 들어갈 수 있음

5. Taint의 effect 종류

Taint에는 effect가 있다.

대표적으로 세 가지가 있다.

effect의미
NoScheduletoleration이 없는 Pod는 새로 배치하지 않음
PreferNoSchedule가능하면 배치하지 않음
NoExecutetoleration이 없는 기존 Pod도 내보냄

하나씩 보면 이렇다.


6. NoSchedule

가장 많이 보는 effect다.

kubectl taint nodes worker-1 dedicated=gpu:NoSchedule

의미는 이렇다.

이 taint를 견디지 못하는 Pod는 이 Node에 새로 스케줄링하지 마라.

중요한 점은 “새로 스케줄링”이다.

이미 그 Node에 떠 있던 Pod는 보통 그대로 남아 있을 수 있다.

기존 Pod
→ 그대로 있을 수 있음

새 Pod
→ toleration 없으면 못 들어옴

7. PreferNoSchedule

PreferNoSchedule은 약한 제한이다.

kubectl taint nodes worker-1 dedicated=gpu:PreferNoSchedule

의미는 이렇다.

가능하면 이 Node에는 배치하지 마라.
하지만 어쩔 수 없으면 배치해도 된다.

즉 강제는 아니다.

Scheduler가 다른 Node를 우선 찾지만, 조건상 필요하면 배치할 수 있다.


8. NoExecute

NoExecute는 가장 강한 effect다.

kubectl taint nodes worker-1 maintenance=true:NoExecute

의미는 이렇다.

이 taint를 견디지 못하는 Pod는 새로 배치하지도 말고,
이미 떠 있는 Pod도 내보내라.

즉 NoExecute는 기존 Pod에도 영향을 준다.

기존 Pod
→ toleration 없으면 퇴출

새 Pod
→ toleration 없으면 배치 불가

9. Toleration 예시 YAML

GPU 작업 Pod를 예로 들어보자.

Node에는 taint가 걸려 있다.

kubectl taint nodes gpu-worker-1 dedicated=gpu:NoSchedule

Pod YAML은 이렇게 작성할 수 있다.

apiVersion: v1
kind: Pod
metadata:
  name: gpu-job
spec:
  tolerations:
    - key: "dedicated"
      operator: "Equal"
      value: "gpu"
      effect: "NoSchedule"
  containers:
    - name: app
      image: nginx

이 Pod는 dedicated=gpu:NoSchedule taint를 견딜 수 있다.

그래서 gpu-worker-1에 배치될 수 있다.


10. 그런데 toleration만 있으면 GPU Node에 꼭 가나?

아니다.

이게 정말 중요하다.

toleration은 “갈 수 있게 해주는 것”이지,
“반드시 그 Node로 보내는 것”은 아니다.

예를 들어 Pod에 toleration이 있다.

tolerations:
  - key: "dedicated"
    operator: "Equal"
    value: "gpu"
    effect: "NoSchedule"

이 말은 이렇다.

GPU taint가 있는 Node에도 갈 수 있다.

하지만 꼭 GPU Node에 간다는 뜻은 아니다.

다른 일반 Node에도 조건이 맞으면 배치될 수 있다.

그래서 특정 Node로 보내고 싶으면 보통 nodeSelector나 nodeAffinity를 같이 쓴다.

nodeSelector:
  accelerator: nvidia

tolerations:
  - key: "dedicated"
    operator: "Equal"
    value: "gpu"
    effect: "NoSchedule"

이렇게 하면 의미가 분명해진다.

nodeSelector
→ GPU Node를 선택

toleration
→ GPU Node의 taint를 통과

11. taint 확인 명령어

Node의 taint를 확인하려면 describe를 많이 쓴다.

kubectl describe node <node-name>

출력 중에 이런 부분을 보면 된다.

Taints: dedicated=gpu:NoSchedule

전체 Node의 라벨과 함께 보고 싶으면 다음도 자주 쓴다.

kubectl get nodes --show-labels

12. taint 제거하기

taint를 제거할 때는 뒤에 -를 붙인다.

kubectl taint nodes gpu-worker-1 dedicated=gpu:NoSchedule-

또는 key 기준으로 제거할 수도 있다.

kubectl taint nodes gpu-worker-1 dedicated-

뜻은 이렇다.

gpu-worker-1 Node에서 dedicated 관련 taint 제거

2부. Cordon & Drain

13. cordon이란?

cordon은 Node에 새 Pod가 더 이상 스케줄링되지 않도록 막는 명령이다.

쉽게 말하면 이렇다.

cordon
= 이 Node에는 이제 새 Pod 넣지 마.

명령어는 간단하다.

kubectl cordon worker-1

그러면 worker-1은 SchedulingDisabled 상태가 된다.

확인해보면 이렇게 보일 수 있다.

kubectl get nodes
NAME       STATUS                     ROLES
worker-1   Ready,SchedulingDisabled   <none>
worker-2   Ready                      <none>
worker-3   Ready                      <none>

이제 Scheduler는 새 Pod를 worker-1에 배치하지 않는다.

하지만 중요한 점이 있다.

cordon은 기존 Pod를 내보내지 않는다.

즉 이미 worker-1에서 실행 중인 Pod는 그대로 있다.


14. cordon은 언제 쓸까?

cordon은 보통 Node 점검 전에 쓴다.

예를 들어 worker-1을 재부팅하거나, 패키지를 업데이트하거나, 장애가 의심되어 새 Pod 유입을 막고 싶다고 하자.

worker-1 점검 예정
   ↓
새 Pod가 더 들어오면 안 됨
   ↓
kubectl cordon worker-1

이렇게 하면 기존 Pod는 그대로 두면서, 새 Pod만 막을 수 있다.

즉 cordon은 “문 닫기”에 가깝다.

새 손님은 못 들어옴.
이미 들어온 손님은 그대로 있음.

15. uncordon이란?

점검이 끝나면 다시 Pod가 스케줄링될 수 있게 풀어야 한다.

이때 쓰는 명령어가 uncordon이다.

kubectl uncordon worker-1

그러면 다시 정상 Node가 된다.

Ready,SchedulingDisabled
→ Ready

즉 uncordon은 cordon을 해제하는 명령이다.


16. drain이란?

drain은 Node에 있는 기존 Pod들을 안전하게 내보내는 명령이다.

쉽게 말하면 이렇다.

drain
= 이 Node 비울게. 여기 있던 Pod들 다른 곳으로 옮겨.

명령어는 이렇게 쓴다.

kubectl drain worker-1 --ignore-daemonsets

그러면 쿠버네티스는 worker-1에 있던 Pod들을 삭제한다.

하지만 그냥 없애는 게 아니다.

Deployment, ReplicaSet, StatefulSet 같은 컨트롤러가 관리하는 Pod라면 다른 Node에 다시 생성된다.

worker-1의 Pod 삭제
   ↓
Deployment가 replicas 부족 감지
   ↓
다른 Node에 새 Pod 생성

즉 drain은 Node 점검 전에 기존 워크로드를 다른 Node로 옮기기 위한 명령이다.


17. drain은 cordon도 같이 한다

중요한 점이 있다.

kubectl drain은 내부적으로 cordon도 같이 한다.

왜냐하면 Node를 비우는 중인데 새 Pod가 다시 들어오면 안 되기 때문이다.

그래서 drain을 하면 해당 Node는 SchedulingDisabled 상태가 된다.

drain
= cordon + 기존 Pod 퇴출

정리하면 이렇다.

cordon
→ 새 Pod만 막음

drain
→ 새 Pod도 막고, 기존 Pod도 내보냄

18. drain에서 --ignore-daemonsets가 필요한 이유

drain을 할 때 자주 보는 옵션이 있다.

kubectl drain worker-1 --ignore-daemonsets

왜 이 옵션이 필요할까?

DaemonSet은 각 Node마다 하나씩 떠야 하는 Pod다.

예를 들어 이런 것들이 있다.

kube-proxy
fluent-bit
node-exporter
CNI agent

DaemonSet Pod는 일반적으로 drain으로 제거해도 컨트롤러 특성상 해당 Node에 계속 있어야 한다.

그래서 drain은 DaemonSet Pod를 그냥 삭제 대상으로 처리하지 않는다.

이때 --ignore-daemonsets를 붙여서 말한다.

DaemonSet Pod는 무시하고 나머지 Pod만 비워줘.

그래서 실습이나 운영에서 drain을 할 때 이 옵션을 자주 붙인다.


19. emptyDir 데이터가 있는 Pod와 drain

drain할 때 이런 메시지가 나올 수도 있다.

cannot delete Pods with local storage

Pod가 emptyDir 같은 로컬 임시 스토리지를 쓰고 있으면, Pod를 삭제할 때 데이터가 사라질 수 있다.

이때 강제로 진행하려면 옵션을 붙인다.

kubectl drain worker-1 --ignore-daemonsets --delete-emptydir-data

이 뜻은 이렇다.

emptyDir 데이터가 삭제될 수 있다는 걸 알고 진행한다.

운영 환경에서는 조심해야 한다.

emptyDir은 Pod가 삭제되면 같이 사라지는 임시 저장소이기 때문이다.


20. drain과 PDB

운영 환경에서는 PodDisruptionBudget, 줄여서 PDB가 drain에 영향을 줄 수 있다.

PDB는 자발적 중단 상황에서 최소한의 Pod 가용성을 보장하기 위한 리소스다.

예를 들어 어떤 서비스가 최소 2개 Pod는 항상 살아 있어야 한다고 하자.

replicas: 3
minAvailable: 2

이 상태에서 drain 때문에 Pod 2개가 한꺼번에 내려가면 서비스 가용성이 깨진다.

그래서 PDB가 있으면 drain이 막힐 수 있다.

Cannot evict pod as it would violate the pod's disruption budget

이 말은 이렇다.

이 Pod를 내보내면 PDB 조건을 깨뜨린다.
그래서 지금은 evict할 수 없다.

즉 drain은 단순히 Pod를 삭제하는 명령처럼 보이지만, 실제로는 가용성을 고려하면서 Pod를 evict한다.


21. cordon과 drain 차이

둘을 비교하면 이렇다.

구분cordondrain
새 Pod 스케줄링 차단함함
기존 Pod 제거안 함함
주 목적새 Pod 유입 차단Node 비우기
사용 상황점검 전 준비, 장애 의심 Node 격리Node 재부팅, 업그레이드, 교체 전
되돌리기uncordon작업 후 uncordon 필요

한 문장으로 보면 이렇다.

cordon
= 이 Node에 새 Pod 넣지 마.

drain
= 이 Node에 새 Pod도 넣지 말고, 기존 Pod도 빼.

3부. taint/toleration과 cordon/drain 비교

22. taint/toleration과 cordon/drain은 뭐가 다를까?

둘 다 Node에 Pod가 올라가는 것을 제어한다.

그래서 헷갈릴 수 있다.

하지만 목적이 다르다.

taint/toleration
= 평소 스케줄링 정책

cordon/drain
= 운영 중 Node 점검이나 장애 대응 명령

예를 들어 GPU Node는 평소에도 일반 Pod가 올라오면 안 된다.

이건 정책이다.

GPU Node
→ 일반 Pod 배치 금지
→ GPU Pod만 허용

이럴 때는 taint/toleration을 쓴다.

반면 worker-1 Node를 오늘 점검해야 한다고 하자.

worker-1 재부팅 예정
→ 새 Pod 막기
→ 기존 Pod 다른 Node로 이동

이럴 때는 cordon/drain을 쓴다.


23. 비교표

구분taint/tolerationcordon/drain
목적특정 Pod만 특정 Node에 들어오게 제어Node 점검/장애 시 Pod 이동
적용 대상Node와 Pod의 스케줄링 조건특정 Node의 운영 상태
지속성정책처럼 계속 유지 가능보통 점검 중 임시 사용
기존 Pod 영향effect에 따라 다름drain은 기존 Pod 제거
대표 상황GPU Node, 전용 Node, control-plane 보호Node 재부팅, 업그레이드, 장애 격리

24. 운영 상황 예시

상황 1. GPU Node 보호

GPU Node에는 일반 Pod가 올라오면 안 된다.

이때는 taint를 건다.

kubectl taint nodes gpu-worker-1 dedicated=gpu:NoSchedule

GPU Pod에는 toleration과 nodeSelector를 넣는다.

nodeSelector:
  accelerator: nvidia

tolerations:
  - key: "dedicated"
    operator: "Equal"
    value: "gpu"
    effect: "NoSchedule"

이 구조는 정책이다.

GPU Node는 GPU 작업만 받는다.

상황 2. Node 점검

worker-1을 점검해야 한다.

먼저 새 Pod 유입을 막는다.

kubectl cordon worker-1

기존 Pod까지 다른 Node로 옮긴다.

kubectl drain worker-1 --ignore-daemonsets --delete-emptydir-data

점검을 진행한다.

OS 패치
커널 업데이트
kubelet 재시작
노드 재부팅
하드웨어 교체

점검이 끝나면 다시 스케줄링을 허용한다.

kubectl uncordon worker-1

25. 한 번에 정리

taint와 toleration은 Node에 아무 Pod나 올라오지 못하게 제어하는 기능이다.

taint
= Node에 붙이는 출입 제한 표시

toleration
= Pod가 가진 출입 허가증

cordon과 drain은 Node 운영 중 점검이나 장애 대응에 사용하는 명령이다.

cordon
= 새 Pod 스케줄링 차단

drain
= 새 Pod 스케줄링 차단 + 기존 Pod 퇴출

uncordon
= 다시 스케줄링 허용

가장 중요한 차이는 이것이다.

taint/toleration
= 평소에 어떤 Pod가 어떤 Node에 들어올 수 있는지 정하는 정책

cordon/drain
= 특정 Node를 점검하거나 비우기 위해 사용하는 운영 명령

처음에는 이렇게 기억하면 된다.

taint는 Node가 거는 “출입 제한”
toleration은 Pod가 가진 “출입 허가증”

cordon은 “새 Pod 금지”
drain은 “Node 비우기”
uncordon은 “다시 받기”

쿠버네티스 운영에서 Node를 안전하게 관리하려면 이 네 가지 개념은 꼭 구분해서 이해해야 한다.

profile
https://greenapple0101.github.io/

0개의 댓글