날씨 정보를 불러오는 중...

쿠버네티스 v1.37 "Garhwal" 정리 - 무엇이 바뀌었고, 내 클러스터는 올려도 될까

2026-10-02 18:32 · IT기술 · 조회 6
banner

쿠버네티스 v1.37 "Garhwal" 정리 - 무엇이 바뀌었고, 내 클러스터는 올려도 될까

쿠버네티스 v1.37이 2026년 8월 26일에 나왔다. 쿠버네티스는 1년에 세 번(대략 4월, 8월, 12월) 새 버전이 나오는데, 이번 버전에는 총 67개의 개선 사항이 들어갔다. 그중 16개가 정식(Stable/GA) 기능이 됐고, 23개가 베타로, 27개가 새로 알파로 들어왔으며, 지원 중단이 1건 있다.

집 서버에서 돌리는 k3s도 9월 14일에 v1.37.0+k3s1, 9월 30일에 v1.37.1+k3s1이 나와서 이제 올릴 수 있는 상태가 됐다. 이 글에서는 공식 릴리스 노트를 바탕으로 주요 변화를 정리하고, 마지막에 지금 v1.36을 쓰는 우리 클러스터에 영향이 있는지 실제로 점검해본 결과를 남긴다.

theme릴리스 이름 - Garhwal(가르왈)

쿠버네티스는 버전마다 이름과 로고를 붙인다. v1.37의 이름은 인도 우타라칸드 주의 히말라야 지역인 가르왈이다. 로고에는 설산 아래 계단식 논이 그려져 있는데, 각 층이 아래층에 기대어 올라가듯 릴리스도 이전 작업 위에 쌓인다는 의미를 담았다고 한다. 지붕에는 데바나가리 숫자로 १.३७(1.37)이 적혀 있다.

한눈에 보는 핵심 변화 5가지

  1. HPA가 0개까지 줄일 수 있게 됨 (베타, 기본 활성화) — 할 일이 없으면 파드를 0개로 내렸다가 일이 생기면 다시 띄운다.
  2. KYAML 정식화 — 헷갈리는 YAML 문법을 피한 쿠버네티스용 YAML 표기법. kubectl get -o kyaml이 정식 기능이 됐다.
  3. 안 쓰는 PVC 찾기 (베타, 기본 활성화) — 어떤 파드도 쓰지 않는 PVC에 Unused 상태가 표시된다.
  4. AI/ML용 스케줄링 강화 — 파드 묶음을 "전부 아니면 전무"로 배치하는 갱(gang) 스케줄링이 베타가 됐다.
  5. kube-proxy ipvs 모드 지원 중단 예고 — v1.40에서 기본 비활성화, v1.43에서 제거 예정이다.

정식(GA) 기능이 된 것들

kyamlKYAML - 더 안전한 YAML 표기법

YAML은 사람이 읽기 편하지만 함정이 많다. 따옴표 없이 NO라고 쓰면 국가 코드(노르웨이)가 아니라 불리언 false로 읽히는 "노르웨이 문제"가 유명하고, 들여쓰기 한 칸 실수로 구조가 통째로 바뀌기도 한다. KYAML은 이런 모호함을 없앤 YAML의 부분집합이다. 문자열은 항상 큰따옴표로 감싸고, 구조는 들여쓰기 대신 {}와 []로 표시한다. 출력은 대략 이런 모양이다(일부 필드 생략).

$ kubectl get svc hello -o kyaml
{
  apiVersion: "v1",
  kind: "Service",
  metadata: {
    name: "hello",
    namespace: "default",
  },
  spec: {
    ports: [{
      port: 80,
      targetPort: 8080,
    }],
  },
}

중요한 점은 KYAML 파일도 그 자체로 올바른 YAML이라는 것이다. 기존 매니페스트를 바꿀 필요가 전혀 없고, 어떤 버전의 kubectl도 KYAML을 그대로 읽는다. "앞으로 이 형식만 쓰라"는 게 아니라, 출력하거나 새로 작성할 때 실수를 줄이는 선택지가 하나 생긴 것이다. v1.34에서 알파, v1.35에서 베타였고 이번에 정식이 됐다.

metricsmetrics.k8s.io API - 9년 만에 정식

kubectl top과 HPA가 CPU·메모리 사용량을 읽어올 때 쓰는 API다. 무려 9년 가까이 베타로 머물러 있었는데, "베타를 영원히 두지 않는다"는 프로젝트 원칙에 따라 드디어 v1이 생겼다. 기존 v1beta1도 정해진 지원 중단 절차에 따라 한동안 계속 쓸 수 있으니 당장 바꿀 것은 없다.

migrateStorage Version Migration - 기본 내장

API 버전이 올라가면(예: v1beta1 → v1) etcd에 이미 저장된 오래된 데이터를 새 버전 형식으로 다시 써야 할 때가 있다. 지금까지는 kubectl get | kubectl replace 스크립트를 돌리거나 별도 도구를 설치해야 했다. 이제는 StorageVersionMigration 오브젝트 하나만 만들면 컨트롤 플레인이 알아서 다시 써준다. 저장 데이터 암호화(encryption at rest) 설정을 바꾼 뒤 기존 Secret을 새 키로 다시 암호화할 때도 쓸 수 있다.

certPod 인증서와 ClusterTrustBundle

파드에 개인키와 X.509 인증서를 쿠버네티스가 직접 나눠주는 기능이 정식이 됐다. 인증서 발급기(signer) 컨트롤러를 하나 두면, 파드는 podCertificate 볼륨만 선언해서 자기 신원을 증명하는 인증서를 자동으로 받고 갱신까지 받는다. 서비스끼리 mTLS로 통신할 때 별도 도구 없이도 기반을 마련할 수 있게 된 셈이다.

selinuxSELinux 볼륨 라벨링 방식 변경 - 주의

SELinux를 켠 노드(RHEL·Rocky 계열에서 흔하다)에서는 볼륨을 붙일 때 파일 하나하나의 SELinux 라벨을 다시 붙이느라 큰 볼륨일수록 파드 시작이 느렸다. v1.37부터는 마운트 옵션(-o context=...)으로 한 번에 라벨을 지정하는 방식이 기본이 된다. 빨라지는 대신 하나의 마운트에는 라벨을 하나만 붙일 수 있어서, 같은 노드에서 SELinux 라벨이 서로 다른 파드들이 볼륨 하나를 같이 쓰던 경우에는 파드가 시작하지 못할 수 있다.

다만 이 동작은 CSI 드라이버가 seLinuxMount: true로 직접 선택한 경우에만 적용되고, SELinux가 꺼진 클러스터는 아무 영향이 없다. 문제가 생기는 파드는 spec.securityContext.seLinuxChangePolicy: Recursive로 예전 방식을 유지할 수 있다.

apiserverAPI 서버 시작 시 과부하 방지

API 서버가 재시작하면서 내부 캐시를 다시 채우는 동안 etcd에 요청이 몰려 컨트롤 플레인 전체가 휘청이는 문제가 있었다. 이제는 감당할 수 있는 요청만 처리하고 나머지는 HTTP 429(Too Many Requests)로 돌려보낸다. 직접 만든 컨트롤러나 오퍼레이터가 있다면 429를 받았을 때 Retry-After 헤더를 존중하고 점점 간격을 늘려 재시도(지수 백오프)하는지 확인해두자. client-go를 쓰면 대부분 이미 처리된다.

베타가 된 기능 중 눈여겨볼 것

hpaHPA 스케일 투 제로 (기본 활성화)

v1.16에 알파로 들어온 지 무려 7년 만에 베타가 되면서 기본으로 켜졌다. minReplicas: 0으로 설정하면 할 일이 없을 때 파드를 0개까지 줄이고, 일이 생기면 다시 늘린다. 큐에 쌓인 작업을 처리하는 워커나 GPU를 쓰는 배치 작업처럼, 놀고 있을 때 자원을 잡아먹는 워크로드의 비용을 크게 줄일 수 있다.

apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: queue-worker
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: queue-worker
  minReplicas: 0          # 0까지 허용
  maxReplicas: 10
  metrics:
    - type: External      # 큐 길이 같은 외부 지표만 가능
      external:
        metric:
          name: queue_messages_ready
        target:
          type: AverageValue
          averageValue: "30"

함정이 하나 있다. CPU·메모리 지표로는 0까지 못 내린다. 파드가 0개면 CPU 사용량을 잴 파드 자체가 없으니, 다시 늘려야 할 때를 알 방법이 없기 때문이다. 그래서 큐 길이처럼 파드 바깥에서 측정되는 Object나 External 지표를 써야 한다. 0으로 내려간 동안에는 HPA 상태에 ScaledToZero=True 조건이 붙어서, HPA가 줄인 것인지 사람이 직접 0으로 줄인 것인지 구분된다.

pvc안 쓰는 PVC 추적 (기본 활성화)

앱을 지워도 PVC는 남는다. 데이터를 지키려는 의도적인 동작이지만, 시간이 지나면 주인 없는 PVC가 디스크를 차지한 채 잊힌다. v1.37부터는 PVC를 쓰는 파드가 하나도 없게 되면 PVC 상태에 Unused 조건(Status=True, 사유 NoPodsUsingPVC)이 자동으로 붙고, 파드가 다시 쓰기 시작하면 False로 바뀐다. 언제부터 놀고 있었는지도 함께 기록된다.

# 지금 아무도 안 쓰는 PVC 목록
kubectl get pvc -A -o json | jq -r '
  .items[]
  | select(any(.status.conditions[]?; .type=="Unused" and .status=="True"))
  | "\(.metadata.namespace)/\(.metadata.name)"'

디스크가 넉넉하지 않은 홈랩에서 특히 반가운 기능이다. 우리 클러스터에도 이전에 쓰던 Oracle DB를 일부러 0으로 줄여두고 15Gi PVC를 남겨둔 게 있는데, 이렇게 "의도적으로 남긴 것"과 "깜빡 잊은 것"을 정리할 때 출발점이 되어준다. 물론 Unused라고 바로 지우면 안 되고, 목록을 보고 판단하는 용도로 쓰자.

memory메모리 QoS (cgroup v2, 기본 활성화)

파드의 메모리 requests와 limits 값을 리눅스 cgroup v2의 memory.min, memory.low, memory.high 설정으로 연결해준다. 요청한 만큼의 메모리는 다른 프로세스 때문에 회수되지 않게 보호하고, 한도에 가까워지면 갑자기 OOM으로 죽이기 전에 먼저 속도를 늦춘다. 업그레이드한다고 기존 워크로드가 갑자기 느려지지 않도록 기본값은 보수적으로 잡혀 있고, 더 강한 보호는 운영자가 kubelet 설정으로 선택해서 켜는 방식이다.

gang갱 스케줄링 - AI 학습 작업을 위한 "전부 아니면 전무"

기본 스케줄러는 파드를 하나씩 배치한다. 그런데 GPU 8장을 쓰는 분산 학습 작업이 파드 8개 중 5개만 자리를 잡으면, 나머지 3개가 자리를 기다리는 동안 이미 뜬 5개는 GPU를 붙잡은 채 아무것도 못 한다. 두 작업이 서로 반씩 자리를 차지하고 영원히 기다리는 교착 상태도 생긴다. 갱 스케줄링은 묶음 전체가 들어갈 자리가 있을 때만 한꺼번에 배치한다. 베타가 되면서 작업 단위로 우선순위를 판단해 밀어내는(preemption) 기능도 함께 들어왔다. 쿠버네티스가 AI 워크로드의 사실상 표준 플랫폼이 되어가면서 최근 몇 버전 동안 가장 활발하게 발전하는 분야다.

etcdetcd RangeStream - 대량 조회 시 메모리 절감

etcd는 목록 조회 결과를 메모리에 통째로 만든 뒤에 보냈다. 노드가 수천 개인 큰 클러스터에서 API 서버가 캐시를 채울 때 이 때문에 메모리가 순간적으로 치솟았다. 이제는 결과를 조각조각 스트리밍으로 보낸다. etcd 3.7 이상이 필요하고, 구버전 etcd를 만나면 API 서버가 알아서 예전 방식으로 돌아가니 신경 쓸 것은 없다.

새로 들어온 알파 기능 중 재미있는 것

  • StatefulSet의 Recreate 업데이트 전략 — Deployment처럼 파드를 전부 내린 뒤 새로 띄우는 방식이다. 지금까지 StatefulSet은 하나씩 교체하는 RollingUpdate와 수동인 OnDelete만 있었다. 버전이 섞여 돌면 안 되는 DB 클러스터 같은 경우에 유용하다.
  • 파드 단위 체크포인트/복원 — 실행 중인 파드 상태를 통째로 저장했다가 복원하는 기능의 기반이 들어왔다. 컨테이너 런타임도 이 기능을 지원해야 쓸 수 있다.
  • 노드 생명주기 조건 — DrainInProgress, Drained, MaintenancePlanned 같은 표준 상태가 생겼다. 지금은 도구마다 taint, 라벨, 어노테이션을 제각각 해석해서 "이 노드가 점검 중인가"를 판단하고 있다.
  • nftables 모드에서 localhost NodePort — iptables 모드에서는 되던 localhost:NodePort 접속이 nftables 모드에서도 가능해졌다(선택 사항).

지원 중단과 주의할 변화

deprecation업그레이드 전에 꼭 확인할 것

  1. kube-proxy ipvs 모드 지원 중단 — ipvs 모드로 쓰면 이제 시작할 때 경고가 찍힌다. v1.40에서 기본 비활성화, v1.43에서 완전히 제거될 예정이다. ipvs는 원래 iptables 성능 문제를 풀려고 도입됐지만, 결국 내부적으로 iptables를 같이 써야 해서 기대만큼의 이점이 없었다. 앞으로의 방향은 nftables 모드다.
  2. kube-dns 지원 중단 — CoreDNS가 v1.13부터 기본이었으니 대부분 해당이 없다. v1.40 이후로는 kube-dns 패키지가 나오지 않을 예정이다.
  3. static Pod의 Secret/ConfigMap 참조 금지 — 원래 안 되는 게 맞았는데 버그로 가능했던 것이 막혔다. 예외를 허용하던 기능 게이트도 제거됐다.
  4. kubectl run -f 지원 중단 예정 — 어차피 무시되던 옵션이다.
  5. cgroup v1 퇴출 진행 중 — v1.35부터 cgroup v1 노드에서는 kubelet이 기본적으로 시작을 거부한다. 임시 우회 설정(failCgroupV1: false)이 남아 있긴 하지만, 위에서 본 메모리 QoS 같은 새 기능은 cgroup v2에서만 동작한다.

우리 클러스터는 올려도 될까 - 직접 점검

지금 집 서버는 k3s v1.36.3이다. 위 지원 중단 목록에 걸리는 게 있는지 하나씩 확인해봤다.

# 1) cgroup 버전 - cgroup2fs면 v2
$ stat -fc %T /sys/fs/cgroup
cgroup2fs

# 2) kube-proxy 모드 - KUBE-SERVICES 체인이 있으면 iptables 모드
$ iptables -t nat -L KUBE-SERVICES -n | head -1
Chain KUBE-SERVICES (2 references)

# 3) 클러스터 DNS - coredns인지 kube-dns인지
$ kubectl get pods -A -o name | grep dns
pod/coredns-54996dc9b4-rpscb

# 4) static Pod 사용 여부 (k3s 기준 경로)
$ ls /var/lib/rancher/k3s/agent/pod-manifests
(비어 있음)

result점검 결과

  • cgroup v2 → cgroup v1 퇴출과 무관하고, 메모리 QoS도 바로 쓸 수 있다
  • kube-proxy iptables 모드(ipvs 아님) → ipvs 지원 중단과 무관
  • DNS는 CoreDNS → kube-dns 지원 중단과 무관
  • static Pod 없음 → Secret 참조 금지와 무관
  • Rocky Linux지만 k3s 기본 저장소(local-path)는 SELinux 마운트 옵션을 선택하지 않으므로 라벨링 변경의 영향권 밖

결론적으로 당장 막히는 것은 없다. 다만 쿠버네티스는 한 번에 한 마이너 버전씩(1.36 → 1.37) 올리는 것이 원칙이고, 업그레이드 전에는 Velero 백업이 최근 것으로 남아 있는지 먼저 확인할 생각이다. 새 마이너 버전은 첫 패치가 나오고 조금 더 지켜본 뒤에 올리는 편이 안전하다. k3s는 이미 v1.37.1까지 나왔으니 슬슬 때가 된 것 같다.

마무리

v1.37을 한 줄로 요약하면 "AI 워크로드를 위한 스케줄링 강화 + 오래 미뤄둔 숙제 정리"다. 갱 스케줄링, DRA(GPU 같은 특수 장치 할당) 관련 기능이 대거 올라온 한편으로, 9년 묵은 metrics API 베타를 정식으로 만들고, 7년 묵은 HPA 스케일 투 제로를 기본으로 켜고, ipvs와 kube-dns 같은 오래된 구성 요소를 정리하기 시작했다.

작은 클러스터를 운영하는 입장에서 체감이 큰 건 안 쓰는 PVC 추적과 KYAML 정도일 것이다. 반대로 큰 영향은 없더라도 ipvs 모드와 cgroup v1은 몇 버전 뒤에 확실히 사라지니, 해당된다면 지금부터 전환 계획을 세워두는 게 좋다. 이 글은 공식 릴리스 블로그(kubernetes.io)의 v1.37 발표 내용을 바탕으로 정리했으며, 세부 동작과 기능 게이트 기본값은 패치 버전에 따라 바뀔 수 있으니 실제 적용 전에는 릴리스 노트 원문을 확인하시길.

참고: Kubernetes v1.37: Garhwal (공식 블로그)


댓글 0

로그인 후 댓글을 작성할 수 있습니다.