GPU Operator 와 타임슬라이싱 · 한 장을 여럿이 쓴다는 말의 뜻 · 이론
롤아웃이 한 노드에서 멈출 때
한 줄 요약
데몬셋의 maxUnavailable: 1 은 한 노드가 새 파드를 못 띄우면 나머지 노드를 건드리지 않고 그대로 멈춘다. 이것은 버그가 아니라 약속이고, 그 결과 클러스터는 옛 설정 노드와 새 설정 노드로 갈라진 채 남는다.
왜 한 노드가 전체를 멈추게 두는가
반대를 생각해 보면 답이 나온다. 새 스펙이 잘못됐는데 데몬셋이 멈추지 않고 계속 밀어붙이면 어떻게 될까. GPU 노드 일곱 대가 전부 동시에 죽는다. 롤링 업데이트의 목적은 빨리 끝내는 것이 아니라 잘못된 변경의 폭발 반경을 한 대로 묶는 것이다. 그래서 데몬셋은 한 대를 바꾸고, 그 파드가 준비될 때까지 기다리고, 준비되지 않으면 영원히 기다린다.
문제는 이 정지가 조용하다는 데 있다. kubectl get ds 는 이렇게 보인다.
NAME DESIRED CURRENT READY UP-TO-DATE AVAILABLEnvidia-container-toolkit 3 3 2 1 2에러가 아니다. 빨간 글씨도 없다. READY 2/3 은 언뜻 "거의 다 됐네" 로 읽힌다. 그런데 이 표가 말하는 것은 클러스터가 두 세대로 갈라졌다는 사실이다. 한 대는 새 스펙으로 못 뜨고 있고, 두 대는 아직 옛 스펙 그대로다. GPU 설정처럼 노드 파일을 고치는 데몬셋이라면, 이 상태는 "노드마다 런타임 설정이 다른 클러스터" 를 뜻한다.
어떻게 동작하나
데몬셋의 롤링 업데이트는 노드 단위로 이렇게 돈다.
1. 아직 옛 스펙인 노드를 하나 고른다.
2. 그 노드의 파드를 먼저 지운다.
3. 새 스펙의 파드를 만든다.
4. 그 파드가 사용 가능해질 때까지 기다린다.
5. maxUnavailable 만큼의 여유가 다시 생기면 1번으로 돌아간다.
3번에서 새 파드가 스케줄되지 못하면 4번이 끝나지 않고, 5번은 영영 오지 않는다. 2번이 3번보다 먼저라는 점이 중요하다 — 멈춘 노드는 옛 파드도 없고 새 파드도 못 뜬 빈 상태가 된다.
새 파드가 안 뜨는 이유는 대개 셋 중 하나다. 이미지를 받지 못하거나, 노드가 요청한 자원을 댈 수 없거나, 톨러레이션·노드셀렉터가 어긋난 것이다. 앞의 둘은 파드가 Pending 또는 ImagePullBackOff 로 남고, 마지막은 성격이 다르다 — 톨러레이션이 어긋나면 데몬셋 컨트롤러가 아예 "이 노드에는 파드가 있으면 안 된다" 고 판단해 대상에서 빼 버리므로, DESIRED 숫자 자체가 줄어든다. 같은 증상처럼 보이지만 봐야 할 칸이 다르다.
kubectl rollout status ds/... 는 이 상태에서 그냥 매달린다. CI 파이프라인에 이 명령이 타임아웃 없이 들어 있으면 잡이 한 시간씩 걸려 있게 되므로 --timeout 을 반드시 준다.
현장에서 만나는 모습
첫째, 알림은 numberUnavailable 로 건다. 데몬셋이 몇 분 이상 desiredNumberScheduled != numberReady 인 상태를 유지하면 사람이 봐야 한다. 파드 재시작 횟수나 에러 로그로는 이 정지가 안 잡힌다 — 아무것도 재시작하지 않고 아무 에러도 안 나기 때문이다.
둘째, 갈라진 세대를 확인하는 습관을 들인다. 노드마다 실제로 어떤 스펙이 돌고 있는지 보는 가장 빠른 방법은 파드의 이미지와 노드를 함께 뽑아 보는 것이다. UP-TO-DATE 숫자만 보면 어느 노드가 뒤처졌는지 알 수 없고, GPU 설정에서는 그 "어느 노드" 가 곧 장애 범위다.
셋째, 되돌리기가 앞으로 가기보다 빠를 때가 많다. 새 스펙이 안 뜨는 원인을 고치는 동안에도 한 노드는 계속 비어 있다. kubectl rollout undo 로 옛 스펙을 복구해 노드 세 대를 같은 상태로 되돌린 다음, 원인은 그다음에 찾는 편이 낫다. 사고 대응에서 먼저 할 일은 진단이 아니라 상태를 하나로 모으는 것이다.
다음 퀴즈에서 확인할 것
READY 2/3 이 왜 진행 중이 아니라 정지 상태인지, 그리고 어느 칸을 봐야 원인의 갈래를 나눌 수 있는지를 확인한다.