상황
하드웨어 변경이 필요해서 PC 1대를 종료를 했다. 해당 PC는 Master 1, Worker 3개의 노드를 담당하는 PC이다.
PC를 종료 했을 때 Argocd에 접속이 안되었고, Grafana, Uptime Kuma에서 Slack으로 비즈니스앱 헬스체크 오류가 발생했다는 알림이 왔다.
- 종로 직후 K9S 상태 - 종료 후 1분이 지낫을 때 상태
- 슬랙 알림
즉각 복구를 시작하는 줄 알았는데 5분 정도뒤에 복구 알림이 왔다. 처음 1분간은 아무런 변화가 없었다.
Gemini 답변
k3s 환경에서 노드 하나를 종료했는데도 k9s 화면에서 해당 포드들이 여전히 'Running' 상태이거나 붉은색으로 표시되며 자동으로 복구되지 않는 이유는 Kubernetes의 'Node Eviction(노드 축출)' 메커니즘 때문입니다.
현재 상황과 해결 방법을 핵심 위주로 정리해 드릴게요.
1. 왜 자동으로 바로 안 바뀔까? (타임아웃의 문제)
Kubernetes는 노드와 일시적인 네트워크 연결이 끊긴 것인지, 아니면 정말로 노드가 죽은 것인지 신중하게 판단합니다. 기본 설정상 노드가 응답하지 않아도 바로 포드를 삭제하지 않고 기다리는 유예 시간이 있습니다.
- Node Monitor Grace Period (기본 40초): 컨트롤러 평면이 노드의 상태를
Unknown으로 판단하기까지 걸리는 시간입니다. - Default Taint Toleration (기본 300초/5분): 노드에 장애가 생겼다고 판단한 후, 해당 노드의 포드를 다른 곳으로 옮기기(Eviction)까지 5분을 더 기다립니다.
즉, 아무 설정을 건드리지 않았다면 PC를 끄고 약 5~6분이 지나야 다른 노드에서 포드가 새로 생성되기 시작합니다.
노드 종료의 정석 (Graceful Shutdown)
작업 순서는 반드시 Cordon(차단) → Drain(비우기) → Shutdown(종료) 순으로 진행해야 합니다.
1단계: 노드 스케줄링 차단 (Cordon)
새로운 포드가 이 노드에 할당되지 않도록 막습니다.
Bash
kubectl cordon <노드-이름>
- 결과: 노드 상태가
Ready, SchedulingDisabled로 변경됩니다.
2단계: 노드 비우기 (Drain)
현재 실행 중인 포드들을 안전하게 다른 노드로 퇴거시킵니다.
Bash
kubectl drain <노드-이름> --ignore-daemonsets --delete-emptydir-data
-ignore-daemonsets: 각 노드마다 떠야 하는 시스템 포드(DaemonSet)는 무시하고 진행합니다.-delete-emptydir-data: 로컬 임시 저장소를 쓰는 포드가 있어도 강제로 삭제하고 옮깁니다. (데이터 유실 주의)
왜 DS 는 안 죽이는가?
좋은 질문입니다! drain 명령어를 실행할 때 --ignore-daemonsets 옵션을 넣는 이유와 왜 **DaemonSet(ds)**은 죽이지 않는지(정확히는 강제로 쫓아내지 않는지) 그 이유를 명확히 짚어드릴게요.
1. DaemonSet의 본질: "노드와 운명을 같이하는 존재"
DaemonSet은 정의 자체가 **'모든(혹시 특정) 노드에 반드시 하나씩 실행되어야 하는 포드'**입니다.
- 역할: 주로 네트워크 플러그인(Flannel, Calico), 로그 수집기(Fluentd), 모니터링 에이전트(Prometheus Node Exporter) 같은 인프라 서비스들입니다.
- 특징: 노드가 살아있는 동안 인프라를 관리하기 위해 존재합니다. 따라서 노드를 비울 때 이 녀석들을 다른 노드로 '이사' 보낼 필요가 없습니다. (이미 다른 노드들에는 자기 짝꿍들이 하나씩 다 떠 있거든요.)
2. 기술적인 이유: "갈 곳이 없다"
일반적인 포드(Deployment 기반)는 A 노드에서 쫓겨나면 B 노드로 이사를 가서 새로 자리를 잡습니다. 하지만 DaemonSet은:
- 중복 불가: B 노드에는 이미 해당 DaemonSet 포드가 실행 중입니다.
- 이사 불가: DaemonSet은 자신의 설정에 맞는 노드에만 존재해야 합니다. A 노드를 비우겠다고 명령했는데, A 노드 전용 관리자를 B로 보낼 수는 없는 노릇이죠.
즉, drain 시에 DaemonSet을 죽이지 않는 게 아니라, "다른 곳으로 옮길 수 없으니 무시하고 진행하겠다"는 뜻입니다.
3. -ignore-daemonsets 옵션을 안 쓰면 어떻게 될까?
만약 이 옵션을 빼고 kubectl drain을 치면, 쿠버네티스는 다음과 같이 반응하며 거절합니다:
"이 노드에는 DaemonSet이 관리하는 포드가 있어서 비울 수 없어요! 안전을 위해 작업을 중단합니다."
그래서 사용자가 "응, 인프라 포드들은 노드 꺼질 때 같이 꺼져도 상관없어(이사 안 가도 돼)"라고 확답을 주는 것이 바로 --ignore-daemonsets 옵션입니다.
💡 정리하자면:
- 일반 포드: 서비스 유지를 위해 다른 노드로 피신시켜야 함.
- DaemonSet 포드: 노드를 관리하는 애들이라 피신시킬 곳도 없고 그럴 필요도 없음. 노드 전원을 끌 때 같이 운명을 맞이하게 두면 됨.