dev.to

Kubernetes 1.35's kubelet refuses to start on a cgroup v1 host by default

Kubernetes 1.35부터 cgroup v1 호스트에서 기본적으로 시작하지 않는 kubelet

Kubernetes 1.35부터 cgroup v1 호스트에서는 kubelet이 기본 설정으로 시작하지 않고 재시작을 반복합니다. 작성자는 kubelet 설정과 kubeadm 사전 검증에 각각 우회 설정이 필요하며, cgroup v1을 유지하면 Kubernetes 1.37에서 기본 활성화된 Memory QoS도 적용되지 않는다고 확인했습니다.

에디터 노트

업그레이드 실패를 피하려면 kubelet과 kubeadm의 검사를 따로 통과시켜야 한다는 점이 가장 실용적인 확인 결과입니다. 작성자는 kubelet의 재시작과 kubeadm 사전 검증을 각각 시험했고, 두 번째 우회 설정이 빠지면 kubeadm이 중단된다는 오류 문구도 제시합니다. 다만 전체 클러스터를 구동하지 못했으므로 파드 수준의 결과까지 검증한 글은 아닙니다. Memory QoS 설명은 댓글에서 정정됐습니다. 1.37에서 기본 활성화된 기능을 cgroup v1 우회 설정과 함께 쓰면 memory.high 조절이 적용되지 않는다는 설명이므로, 1.35와 1.36에도 같은 영향이 있다는 식으로 넓혀 읽으면 안 됩니다. cgroup v1 지원을 임시로 유지하는 절차와 기능 손실이 생기는 버전을 구분해 제시한 점이 이 자료의 실제 범위입니다.

AI 요약

Kubernetes 1.35부터 cgroup v1을 사용하는 호스트에서 kubelet의 시작 검증이 실패합니다. 작성자는 cgroup v1 환경에서 kind 노드 이미지를 비교하고 kubelet과 kubeadm의 동작을 따로 확인했습니다. 테스트는 전체 클러스터를 띄우지 못한 환경 제약이 있었지만, 문제가 파드 스케줄링 이전인 kubelet 시작 단계에서 발생하는 것을 직접 관찰했습니다.

버전별 kubelet 동작

작성자는 kindest/node 이미지를 cgroup v1 호스트에서 실행했습니다. Kubernetes 1.34.0의 kubelet은 cgroup v1 지원이 유지보수 상태라는 경고를 한 번 남긴 뒤 계속 실행됐습니다. 1.35.0과 1.37.0은 설정 검증 단계에서 cgroup v1이 지원되지 않는다는 치명 오류를 내고 종료한 뒤 재시작을 반복했습니다. 1.36.1은 시험하지 않았으므로 버전 경계는 1.34와 1.35 사이에서 확인했다고 한정합니다.

1.37.0 노드는 약 30초 동안 재시작 횟수가 58회에서 82회로 늘었습니다. 1.35.0 노드도 장시간 실행하자 재시작 횟수가 137회에 이르렀습니다. 1.37.0 노드는 유용한 작업 없이 CPU를 9.35% 사용했고, kubelet 오류 메시지만 반복 기록한 systemd journal은 8.0MB로 커졌습니다.

우회 설정은 두 단계

kubelet 설정에 failCgroupV1: false를 추가하면 kubelet은 cgroup v1 호스트에서도 실행됩니다. 작성자는 1.37.0 노드에 이 설정을 적용한 뒤 재시작 횟수가 0인 상태를 확인했습니다. 하지만 kubeadm은 kubelet 설정과 별도로 SystemVerification 사전 검증에서 cgroup v1을 거부합니다. 따라서 kubeadm을 사용할 때는 kubelet 설정 외에 init, join, upgrade 명령마다 --ignore-preflight-errors=SystemVerification도 지정해야 합니다. 이 옵션을 주면 사전 검증 오류가 경고로 바뀝니다.

kind는 생성하는 kubeadm 설정에 preflight 단계를 건너뛰도록 지정합니다. 따라서 kind에서 테스트하면 kubeadm의 SystemVerification 검증은 실행되지 않고 kubelet 자체 검증만 드러납니다. 실제 kubeadm 환경에는 서로 독립된 두 검사가 있으므로 kind의 결과만으로 사전 검증 동작까지 확인했다고 볼 수 없습니다.

cgroup v1에서 달라지는 Memory QoS

우회 설정으로 kubelet을 실행한 뒤에도 로그에는 Memory QoS가 cgroup v2에서만 작동한다는 경고가 남았습니다. 댓글에서 작성자는 본문의 설명을 정정했습니다. Memory QoS는 1.36까지 알파 기능이며 기본 비활성이었고, 1.37에서 베타로 전환되며 기본 활성화됐습니다. 따라서 cgroup v1을 유지한 채 1.37 이상에서 failCgroupV1을 끄면 memory.high 기반 메모리 압박 완화가 적용되지 않습니다. 댓글 작성자는 그 경우 파드가 제한에 닿기 전에 속도를 낮추는 대신 하드 메모리 제한에 도달해 OOM 종료를 겪을 수 있다고 설명했습니다.

적용 전 점검과 테스트 범위

작성자는 각 노드에서 stat -fc %T /sys/fs/cgroup 명령을 실행해 cgroup v2인 cgroup2fs와 cgroup v1인 tmpfs를 구분하라고 안내합니다. 가능하면 업그레이드 전에 cgroup v2로 옮기고, 당장 어렵다면 kubelet과 kubeadm 양쪽 우회 설정을 적용한 뒤 Memory QoS 경고를 확인하라는 내용입니다. cgroup v1 지원은 Kubernetes 1.38에서 제거될 예정이라고 본문은 설명합니다.

작성자는 중첩 컨테이너 환경의 runc 오류 때문에 전체 kind 클러스터의 파드를 실행하지 못했습니다. 이 오류는 1.34에서도 동일하게 나타나 버전별 Kubernetes 문제와 구분했고, docker exec, systemctl, journalctl로 kubelet을 관찰하고 kubeadm 사전 검증을 별도로 실행했습니다. 테스트에는 docker와 kind, kubectl이 필요하며 클라우드 계정은 필요하지 않습니다.

dev.to 반응

  • @kashif_manzer — 두 단계 우회 설정을 잘 짚었습니다. 대부분 kubelet 쪽 설정만 발견합니다. failCgroupV1: false는 영구 설정이 아니라 마이그레이션을 위한 임시 다리로 봐야 합니다. 업그레이드 전에 stat -fc %T /sys/fs/cgroup으로 모든 노드를 조사해 예상하지 못한 호스트가 롤아웃 도중 나타나지 않게 하세요. Memory QoS 경고도 가볍게 넘기면 안 됩니다. cgroup v1에서는 그 보호 기능이 적용되지 않아 나중에 부하가 걸렸을 때 OOM 종료로 이어질 수 있습니다.
    • @alexgeorgiev17 — 저도 마이그레이션을 위한 임시 설정으로 다루겠습니다. 노드를 v2로 옮길 시간을 벌어주는 플래그이지, 이 문제를 더 생각하지 않아도 된다는 뜻은 아닙니다. 오류 메시지도 지원이 사라질 예정이라고 분명히 말합니다. 업그레이드 도중 재시작하는 kubelet을 보고 어떤 노드가 아직 tmpfs인지 알아내는 건 최악의 방식입니다. Memory QoS가 놓치기 쉬운 부분이라는 데 동의하며, 본문의 설명을 고쳐야 합니다. 여러 릴리스 동안 안정 버전이었다는 설명은 틀렸습니다. 1.36까지 알파이며 기본 비활성이었고, 1.37에서 베타가 되면서 기본 활성화됐습니다. 따라서 1.35와 1.36에서는 기능 게이트를 직접 켠 경우가 아니라면 해당되지 않을 가능성이 높습니다. 1.37 이상에서 v1 우회 설정을 쓰면 memory.high 조절이 빠지고, 파드는 먼저 속도를 늦추는 대신 하드 제한에 도달해 OOM 종료될 수 있습니다. cgroup v1에서는 원래도 그랬지만, 이제 기본값이 보장한다고 여길 수 있는 동작과 달라집니다.
  • @mridul_it_is — 업그레이드할 때 유용하겠습니다. 감사합니다.
    • @alexgeorgiev17 — 천만에요.

원문: dev.to / 번역·요약: Trawling