Cluster Maintenance - Cordon/Drain/Uncordon

2025. 12. 31. 20:01·CKA

운영 중인 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. 유지보수 표준 절차(권장)

재부팅/업그레이드 같은 일반적인 유지보수는 보통 아래 패턴이 정석입니다.

  1. 노드에 새 파드 배치 차단
kubectl cordon <node-name>
  1. 파드 안전 퇴거(다른 노드로 재생성 유도)
kubectl drain <node-name> --ignore-daemonsets --delete-emptydir-data
  1. 유지보수/재부팅 수행
  2. 노드 복귀 확인 후 스케줄 재개
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
'CKA' 카테고리의 다른 글
  • Cluster Maintenance - 백업 방법(yaml 및 etcd)
  • Cluster Maintenance - 쿠버네티스 릴리즈 버전 이해 및 버전 업그레이드 방법
  • Application Lifecycle Management - 총 정리
  • Application Lifecycle Management - VPA
5jyan5
5jyan5
  • 5jyan5
    jyan
    5jyan5
  • 전체
    오늘
    어제
    • 분류 전체보기 (243)
      • 김영한의 스프링 핵심 원리(기본편) (8)
      • 김영한의 스프링 핵심 원리 - 고급편 (11)
      • 김영한의 스프링 MVC 1편 (1)
      • 김영한의 스프링 DB 1편 (3)
      • 김영한의 스프링 MVC 2편 (3)
      • 김영한의 ORM 표준 JPA 프로그래밍(기본편) (9)
      • 김영한의 스프링 부트와 JPA 활용2 (2)
      • 김영한의 실전 자바 - 중급 1편 (1)
      • 김영한의 실전 자바 - 고급 1편 (9)
      • 김영한의 실전 자바 - 고급 2편 (9)
      • Readable Code: 읽기 좋은 코드를 작성.. (2)
      • 김영한의 실전 자바 - 고급 3편 (9)
      • CKA (119)
      • 개발 (37)
      • 경제 (4)
      • 리뷰 (1)
      • 정보 (2)
  • 블로그 메뉴

    • 링크

    • 공지사항

    • 인기 글

    • 태그

      락
      단방향 맵핑
      Target
      프록시 팩토리
      JPQL
      gesingleresult
      고급
      Thread
      조회 성능 최적화
      @args
      log trace
      typequery
      김영한
      양방향 맵핑
      cglib
      빈 후처리기
      @discriminatorvalue
      스레드
      requset scope
      reentarantlock
      hibernate5module
      버퍼
      페치 조인
      jpq
      프록시
      자바
      @discriminatorcolumn
      WAS
      @within
      jdk 동적 프록시
    • 최근 댓글

    • 최근 글

    • hELLO· Designed By정상우.v4.10.2
    5jyan5
    Cluster Maintenance - Cordon/Drain/Uncordon
    상단으로

    티스토리툴바