운영 중인 Kubernetes 클러스터에서는 OS 보안 패치, 커널 업데이트, containerd/kubelet 업그레이드, 노드 설정 변경 등으로 인해 특정 노드를 유지보수 모드로 전환해야 하는 상황이 반드시 생깁니다.
이때 흔히 하는 실수는 다음 두 가지입니다.
cordon/drain이 트래픽 차단 스위치라고 오해하는 것- “노드가 5분 죽어있으면 자동으로 drain 된다”라고 오해하는 것
이 글에서는 노드 장애/유지보수 상황에서 Kubernetes가 실제로 어떻게 동작하는지와, cordon/drain/uncordon을 언제 어떻게 써야 안전한지를 운영 관점으로 정리합니다.
1. 노드가 다운되면 파드는 어떻게 되나?
노드가 다운되면 그 노드 위의 파드(컨테이너)는 즉시 접근 불가가 됩니다.
사용자 영향 여부는 “대체 가능한 파드가 있느냐(Replica가 있느냐)”로 결정됩니다.
- Deployment/ReplicaSet 기반 앱: replica가 여러 개라면 한 노드의 파드가 죽어도 다른 노드의 파드가 트래픽을 받아 서비스가 유지될 수 있음
- 단일 파드(standalone) / replica 1: 그 파드가 있던 노드가 죽는 순간 서비스가 중단될 수 있음
운영에서 “노드 유지보수”는 사실상 “그 노드 위 워크로드가 잠시 사라질 수 있다”는 의미이므로, 워크로드가 컨트롤러(Deployment/RS/StatefulSet) 에 의해 관리되고 있는지가 매우 중요합니다.
2. “5분”의 의미: 자동 drain이 아니라 자동 “장애 복구(eviction/recreate) 흐름”
많이들 “노드 5분 죽으면 자동으로 drain 된다”라고 말하는데, 정확히는 이렇습니다.
- 노드가 NotReady 상태로 일정 시간 이상 지속되면
컨트롤 플레인이 노드를 비정상으로 판단하고, 해당 노드의 파드에 대해 퇴거(eviction) 및 대체 생성(recreate) 흐름이 진행될 수 있습니다. - 이 동작은 사용자가 수행하는
kubectl drain과 결과가 비슷해 보일 때도 있지만, 본질적으로는:drain: 유지보수 사전 예방(계획된 이주)- NotReady 장기화 후 eviction: 장애 사후 복구(이미 영향 발생 후 복구)
중요한 차이 요약
drain은 노드를 unschedulable로 명시 + 파드를 정책을 고려해 우아하게 퇴거- NotReady 장기화는 노드가 죽어서 파드가 이미 영향 받는 상황에서 복구 로직이 뒤늦게 작동
또한 둘 다 공통적으로:
- standalone 파드는 자동으로 다른 노드에 다시 뜨지 않습니다.
(다시 만들어줄 컨트롤러가 없기 때문)
3. Unschedulable(cordon)은 트래픽 차단이 아니다
여기서 가장 중요한 포인트를 먼저 박아두겠습니다.
cordon(Unschedulable)은 “스케줄링”만 막습니다.
“트래픽”을 막는 게 아닙니다.
- 노드를 Unschedulable로 만들어도,
- 그 노드 위 파드가 Ready 상태로 남아 있으면,
- Service는 여전히 그 파드로 트래픽을 보낼 수 있습니다.
반대로 “트래픽이 끊기느냐”는 노드 상태가 아니라 Service 엔드포인트에 포함되는지(Ready Pod인지) 에 의해 결정됩니다.
4. NotReady인 경우 트래픽은?
- 노드가 NotReady가 되면, 해당 노드의 파드들이 Ready에서 빠지거나,
Endpoint/EndpointSlice에서 제외되어 Service가 선택하지 않게 되는 흐름이 일반적입니다. - 다만 “즉시 0초 컷”으로 끊긴다고 단정하긴 어렵고, 상태 전파/헬스 체크 주기에 따라 짧은 지연이 있을 수 있습니다.
결론:
- cordon(Unschedulable): 트래픽은 계속 갈 수 있음(Ready면)
- NotReady: 대체로 트래픽이 끊기는 방향으로 흘러감(Ready 탈락/Endpoint 제외)
5. 명령어 3종 정리: cordon / drain / uncordon
5.1 kubectl cordon
- 노드를 Unschedulable로 표시
- 기존 파드는 그대로 유지
- 이후 새 파드만 해당 노드에 스케줄되지 않음
kubectl cordon <node-name>
5.2 kubectl drain
- 내부적으로 cordon 포함
- 해당 노드의 파드를 퇴거(evict) 시켜 비움
- 컨트롤러(Deployment/RS/StatefulSet 등)가 관리하는 파드는 다른 노드에서 대체 파드 생성
- DaemonSet은 보통 노드마다 있어야 하므로 일반적으로 제외
kubectl drain <node-name> \
--ignore-daemonsets \
--delete-emptydir-data
자주 보는 옵션 의미:
--ignore-daemonsets: DaemonSet 파드는 드레인 대상에서 제외(보통 필수)--delete-emptydir-data: emptyDir(노드 로컬 임시 저장소) 데이터는 파드 종료 시 유실 가능 → 이를 감수하고 진행--force: 컨트롤러에 의해 관리되지 않는 파드(standalone)까지 강제로 삭제 가능
→ 운영에서는 매우 신중(서비스가 그냥 사라질 수 있음)
5.3 kubectl uncordon
- 노드를 다시 Schedulable로 되돌림
- drain으로 다른 노드에 떠버린 파드가 자동으로 원래 노드로 돌아오지는 않음
kubectl uncordon <node-name>
6. “standalone도 drain 하면 다른 노드에 뜨나?”
아니요.
- Deployment/ReplicaSet: drain → 기존 파드 퇴거 → 다른 노드에 자동 생성 ✅
- Standalone Pod: drain → 퇴거(삭제) → 끝(대체 생성 없음) ❌
standalone 여부는 빠르게 확인할 수 있습니다.
kubectl get pod <pod> -n <ns> -o jsonpath='{.metadata.ownerReferences[*].kind}'
- 출력이 비어 있으면 standalone일 가능성이 큼
7. 언제 cordon만 쓰고, 언제 drain까지 해야 하나?
7.1 cordon만 하는 경우 (대표 시나리오)
“새 파드 유입만 막고, 기존 파드는 건드리지 않겠다”가 목적입니다.
- 노드 재부팅/런타임 재시작이 없는 작업
- 예: 특정 설정 변경(재시작 불필요), 점검성 작업
- 아주 짧고 영향이 허용되는 작업
- 단, “짧다”는 건 시간보다 “파드가 끊기지 않는다”가 더 중요합니다.
주의: cordon만 걸고 패치 작업을 한다고 해서 안전이 보장되는 건 아닙니다.
cordon은 트래픽 차단이 아니고, 패치가 노드/런타임/네트워크를 흔들면 “10초 작업”도 실패를 만들 수 있습니다.
7.2 drain이 권장되는 경우
“노드를 건드려서 파드가 흔들릴 가능성이 있다”면, 보통 drain이 정석입니다.
- OS 패치/재부팅
- containerd/docker 재시작
- kubelet 재시작
- CNI/iptables 등 네트워크 계층 영향 가능 작업
- 커널 업데이트
핵심은 이겁니다.
cordon만: “그 노드 위 파드는 그대로 둔 채 작업”drain: “작업 전에 파드를 다른 노드로 안전하게 빼고 작업”
8. cordon 후 10초 패치면 10초 동안 트래픽 실패가 날 수 있나?
가능합니다. 다만 원인은 cordon 자체가 아니라 패치 작업의 영향입니다.
예를 들어 아래가 발생하면 짧은 시간도 실패가 납니다.
- container runtime 재시작(containerd/docker)
- kubelet 재시작(상태 보고/리포팅 흔들림)
- 노드 네트워크 순간 단절
- CNI/iptables 갱신 영향
- long-lived connection(WebSocket/gRPC 스트리밍) 끊김
그래서 “짧은 작업이니까 cordon만”이라는 판단은,
- 해당 작업이 노드/파드의 가용성에 영향을 주는지
- 해당 서비스가 짧은 끊김을 허용하는지
- replica가 충분한지
까지 같이 봐야 합니다.
9. 트래픽이 어디로 가는지 확인하는 실전 커맨드 (EndpointSlice 기준)
“트래픽이 노드로 안 간다/간다”는 표현보다,
Service가 어떤 파드를 엔드포인트로 잡고 있냐를 보는 게 정확합니다.
# 노드 상태 확인
kubectl get nodes -o wide
# 어떤 파드가 해당 노드에 떠 있는지
kubectl get pods -A -o wide | grep <node-name>
# 서비스가 라우팅할 실제 백엔드(EndpointSlice)
kubectl get endpointslice -n <ns> -l kubernetes.io/service-name=<svc>
# 구형 Endpoints(참고)
kubectl get endpoints -n <ns> <svc>
여기서 Ready 파드가 EndpointSlice에 남아있으면, cordon 상태라도 트래픽은 갈 수 있습니다.
10. 유지보수 표준 절차(권장)
재부팅/업그레이드 같은 일반적인 유지보수는 보통 아래 패턴이 정석입니다.
- 노드에 새 파드 배치 차단
kubectl cordon <node-name>
- 파드 안전 퇴거(다른 노드로 재생성 유도)
kubectl drain <node-name> --ignore-daemonsets --delete-emptydir-data
- 유지보수/재부팅 수행
- 노드 복귀 확인 후 스케줄 재개
kubectl get nodes
kubectl uncordon <node-name>
11. 체크리스트: 이 글에서 꼭 기억할 것
cordon(Unschedulable)은 트래픽 차단이 아니다. 새 파드 스케줄링만 막는다.- 트래픽 라우팅은 노드 상태가 아니라 Ready Pod(EndpointSlice 포함 여부) 가 기준이다.
- “5분”은 자동 drain이 아니라, 노드 장애가 길어질 때 발생하는 자동 eviction/복구 흐름에 가깝다.
- drain은 “이동”이 아니라 기존 파드 종료 + 다른 노드에 재생성이다.
- standalone 파드는 drain/자동 복구 모두에서 자동으로 다시 뜨지 않는다.
- “10초 패치”도 노드/런타임/네트워크가 흔들리면 트래픽 실패가 날 수 있다.
Practice Test: https://uklabs.kodekloud.com/topic/practice-test-os-upgrades-2/
'CKA' 카테고리의 다른 글
| Cluster Maintenance - 백업 방법(yaml 및 etcd) (0) | 2025.12.31 |
|---|---|
| Cluster Maintenance - 쿠버네티스 릴리즈 버전 이해 및 버전 업그레이드 방법 (0) | 2025.12.31 |
| Application Lifecycle Management - 총 정리 (0) | 2025.12.31 |
| Application Lifecycle Management - VPA (1) | 2025.12.30 |
| Application Lifecycle Management - 오토스케일링과 HPA (0) | 2025.12.30 |