Kubernetes 1.36 변경사항 18가지 완전 정리 — GA 승격·Breaking Change 업그레이드 가이드

목차

kubectl get node -o wide
# NAME   STATUS   ROLES   AGE   VERSION   INTERNAL-IP   EXTERNAL-IP   OS-IMAGE   KERNEL-VERSION   CONTAINER-RUNTIME   ARCH
# node1  Ready    ...     ...   v1.36.0   ...           ...           ...        ...              ...                 amd64

kubectl get node -o wide 출력에 ARCH 컬럼이 하나 추가되었다. 이 릴리스에는 이것보다 훨씬 큰 변경이 70개 포함되어 있다. 코드네임 ‘ハル(Haru)’, 2026-04-22 릴리스. 18개 GA 승격, 25개 Beta 진입, 25개 Alpha 신규 도입이라는 규모가 상당한 편이다.

스타트업에서 서버를 혼자 운영하는 입장이라면 Breaking Change 항목부터 확인하는 게 순서일 것이다. 이 글은 업그레이드 시 코드가 깨지는 변경을 먼저 다루고, 이후 GA·Beta·Alpha 순으로 정리한다.

gitRepo 볼륨 영구 제거 — Kubernetes 1.36 변경사항 정리의 핵심

v1.36에서 가장 임팩트가 큰 Breaking Change는 gitRepo 볼륨 플러그인의 영구 비활성화다(KEP-5040). v1.11 시점에 이미 폐기 선언되었지만, 이번에 재활성화 옵션 자체가 사라졌다. 임의 코드를 root 권한으로 실행할 수 있는 보안 취약점이 근본 원인이며, 단순 비권장이 아니라 완전 제거인 셈이다.

기존에 gitRepo 볼륨을 사용하던 워크로드는 두 가지 경로로 마이그레이션해야 한다.

방법장점단점적합한 경우
init container별도 사이드카 불필요, 시작 시 1회 clonePod 재시작마다 clone 발생배포 빈도 낮은 배치 작업
git-sync 사이드카지속적 동기화, 변경 즉시 반영추가 컨테이너 리소스 소비config repo 실시간 반영 필요 시

init container 방식의 마이그레이션 패턴은 다음과 같다.

apiVersion: v1
kind: Pod
metadata:
  name: git-init-example
spec:
  initContainers:
  - name: git-clone
    image: alpine/git:latest
    command: ['git', 'clone', 'https://github.com/example/repo.git', '/workspace']
    volumeMounts:
    - name: workspace
      mountPath: /workspace
  containers:
  - name: app
    image: my-app:latest
    volumeMounts:
    - name: workspace
      mountPath: /workspace
  volumes:
  - name: workspace
    emptyDir: {}

git-sync 사이드카 방식은 k8s.gcr.io/git-sync/git-sync:v4.2.1 이미지를 별도 컨테이너로 추가하고, 공유 emptyDir 볼륨을 통해 앱 컨테이너와 파일을 주고받는 구조다. --period 플래그로 동기화 주기를 조정할 수 있고, --depth 1로 shallow clone을 지정하면 대용량 레포지토리에서 초기화 시간을 크게 줄일 수 있다.

gitRepo 볼륨 재활성화 불가
v1.36부터는 피처 게이트로도 gitRepo를 다시 켤 수 없다. 업그레이드 전에 클러스터 내 gitRepo 사용 여부를 `kubectl get pods -A -o json | grep gitRepo`로 반드시 점검해야 하는 이유가 여기에 있다.
[Kubernetes v1.36 스닉 피크 — 삭제 항목 상세](https://kubernetes.io/blog/2026/03/30/kubernetes-v1-36-sneak-peek/)에서 KEP-5040의 배경과 타임라인을 확인할 수 있다.

메트릭명 변경과 Portworx·Flex-volumes 제거

gitRepo만큼 눈에 잘 띄지는 않지만, 모니터링 파이프라인을 운영 중이라면 메트릭명 변경이 더 치명적일 수 있다.

메트릭 리네이밍

  • volume_operation_total_errorsvolume_operation_errors_total
  • etcd_bookmark_countsetcd_bookmark_total

Prometheus alert rule이나 Grafana 대시보드에서 이전 메트릭명을 참조하고 있으면 업그레이드 직후 알림이 누락되는 결과로 이어진다. recording rule을 사용하는 경우에도 마찬가지인데, 메트릭명이 바뀌면 PromQL 쿼리 자체가 빈 결과를 반환하기 때문이다. 배포 전에 grep으로 전수 검사하는 것이 안전한 편이다.

# Prometheus rule 파일에서 변경 대상 메트릭 검색
grep -rn "volume_operation_total_errors\|etcd_bookmark_counts" \
  /etc/prometheus/rules/

스토리지 플러그인 정리

Portworx 인트리 플러그인이 완전 제거되었다. CSI 드라이버로의 마이그레이션이 필수이며, 인트리 방식으로는 더 이상 Portworx 볼륨을 프로비저닝할 수 없게 된다. Flex-volumes 역시 kubeadm에서 제거되었다.

Portworx CSI 전환 시에는 pxd.portworx.com StorageClass를 새로 작성하고, 기존 PV/PVC를 CSI 기반으로 재생성해야 한다. 기존 데이터가 있는 경우에는 Portworx 공식 마이그레이션 도구(pxctl volume migrate)를 사용하거나, 스냅샷을 통한 데이터 복원 방식으로 전환한다. Flex-volumes를 사용 중이라면 kubectl get pv -o json | jq '.items[] | select(.spec.flexVolume != null)'로 영향 범위를 먼저 파악하는 것이 첫 단계다.

DRA RBAC 세분화 요구사항

DRAResourceClaimGranularStatusAuthorization이 Beta로 활성화되면서 DRA 드라이버에 resourceclaims/binding, resourceclaims/driver 세분화 RBAC 권한이 필요해졌다. GPU 등 디바이스 할당을 DRA로 관리하는 클러스터라면, 기존 ClusterRole에 해당 서브리소스 권한을 추가하지 않으면 디바이스 할당 자체가 실패하는 경우가 있다.

업그레이드 전 Breaking Change 체크 순서
1단계: gitRepo 볼륨 사용 워크로드 검색 → 2단계: Prometheus/Grafana 메트릭명 일괄 치환 → 3단계: Portworx 인트리 → CSI 전환 확인 → 4단계: DRA ClusterRole 서브리소스 권한 추가. 이 순서대로 진행하면 업그레이드 당일 장애를 최소화할 수 있다.
## externalIPs 필드 공식 폐기 — Kubernetes 1.36 변경사항 중 보안 관련

Service .spec.externalIPs 필드가 v1.36에서 공식 폐기되었다(KEP-5707). 완전 제거 시점은 v1.43으로 예정되어 있어 당장 동작이 멈추지는 않지만, 폐기 경고 로그가 출력되기 시작하는 것이다.

폐기 원인은 CVE-2020-8554 중간자 공격 취약점이다. externalIPs를 이용하면 클러스터 내부에서 외부 IP를 가로채는 MITM 공격이 가능한데, 이 취약점은 근본적으로 설계 수준의 문제라 패치가 아닌 기능 자체의 제거가 결정된 배경이 있다.

대안은 세 가지로 정리할 수 있다.

대안특징제약
LoadBalancer Service클라우드 LB 자동 프로비저닝클라우드 환경 전제, 비용 발생
NodePort노드 IP + 포트 직접 노출포트 범위 30000~32767 제한
Gateway APIL7 라우팅 통합 관리아직 일부 구현체만 GA

NodePort로 전환하는 경우, 기존 externalIPs로 노출하던 Service를 다음과 같이 수정한다.

# 마이그레이션 전 (externalIPs 방식 — 폐기 예정)
spec:
  type: ClusterIP
  externalIPs:
  - 203.0.113.10
  ports:
  - port: 80
---
# 마이그레이션 후 (NodePort 방식)
spec:
  type: NodePort
  ports:
  - port: 80
    targetPort: 8080
    nodePort: 30080

온프레미스 환경에서 LoadBalancer 타입을 사용하고 싶다면 MetalLB를 도입하는 것이 현실적인 선택지다. MetalLB의 IPAddressPool에 고정 IP 대역을 등록하면 LoadBalancer Service에 외부 IP가 자동 할당되며, externalIPs 방식과 유사한 접근성을 유지할 수 있다.

externalIPs 마이그레이션 시한
v1.43 제거까지 약 7개 마이너 버전의 유예 기간이 있으나, 보안 취약점이 원인인 만큼 조기 마이그레이션을 권장한다. `kubectl get svc -A -o json | jq ‘.items[] | select(.spec.externalIPs != null) | .metadata.name’` 명령으로 대상 Service를 먼저 식별하는 것이 첫 단계가 된다.
Gateway API로의 마이그레이션 단계별 가이드는 커뮤니티에서도 정리된 자료가 부족한 상태다. 이 부분은 향후 공식 문서 업데이트를 지켜볼 필요가 있다.

GA 승격 주요 기능 4가지

v1.36에서 GA(정식)로 올라간 18개 기능 중 실무 영향이 큰 4가지를 정리한다.

UserNamespacesSupport

컨테이너 내부의 root 사용자를 호스트의 비특권 사용자로 매핑하는 기능이다. 컨테이너 탈출(container escape) 공격 시에도 호스트에서는 일반 사용자 권한만 갖게 되므로, 보안 경계가 한 단계 강화되는 셈이다. 멀티테넌트 클러스터에서 특히 유용한 편이다.

User Namespace를 활성화하려면 Pod spec에 hostUsers: false를 명시한다. 이 필드를 설정하면 컨테이너 내부의 UID 0(root)이 호스트에서는 65536 이상의 비특권 UID로 매핑된다.

spec:
  hostUsers: false
  containers:
  - name: app
    image: my-app:latest
    securityContext:
      runAsUser: 0   # 컨테이너 내부에서는 root로 실행

User Namespace는 OCI 런타임(runc 1.2+, crun 1.9+)과 리눅스 커널 5.19+ 환경에서만 동작한다. 노드 OS가 CentOS 7처럼 구형 커널을 사용하는 경우에는 이 기능을 사용할 수 없으므로, 노드 OS 버전 확인이 선행되어야 한다.

MutatingAdmissionPolicy v1

CEL(Common Expression Language) 기반으로 API 서버 내에서 직접 mutation 로직을 실행할 수 있게 되었다. 기존에는 Webhook 서버를 별도로 운영해야 했던 부분을 인라인 CEL 표현식으로 대체 가능하다.

apiVersion: admissionregistration.k8s.io/v1
kind: MutatingAdmissionPolicy
metadata:
  name: add-default-label
spec:
  matchConstraints:
    resourceRules:
    - apiGroups: [""]
      apiVersions: ["v1"]
      operations: ["CREATE"]
      resources: ["pods"]
  mutations:
  - patchType: "ApplyConfiguration"
    applyConfiguration:
      expression: >
        Object{metadata: Object.metadata{
          labels: object.metadata.labels +
            {"environment": "production"}
        }}

이 예제는 Pod 생성 시 environment: production 레이블을 자동으로 추가하는 정책이다. Webhook 서버 없이 API 서버 내에서 처리되므로 별도 배포 구성이 필요 없고, Webhook 서버 장애가 API 서버 가용성에 영향을 주던 구조적 문제도 사라진다.

NodeLogQuery

kubectl로 노드 로그를 직접 조회할 수 있는 기능이 GA가 되었다. SSH 접속 없이 노드 레벨 로그를 확인할 수 있다는 점에서, 혼자 서버를 관리하는 환경에서 디버깅 시간을 줄이는 데 도움이 되는 기능이다.

# 노드의 kubelet 로그 조회
kubectl get --raw "/api/v1/nodes/node1/proxy/logs/kubelet"

# 커널 로그(syslog) 조회
kubectl get --raw "/api/v1/nodes/node1/proxy/logs/syslog"

노드 로그 API를 호출하려면 kubelet의 --enable-debugging-handlers 설정이 활성화되어 있어야 하며, 호출 사용자에게 nodes/proxy 리소스에 대한 get 권한이 필요하다.

Fine-grained Kubelet API Authorization

KubeletFineGrainedAuthz 피처 게이트가 GA로 전환되었다. Kubelet API에 대한 접근 제어를 세밀하게 설정할 수 있게 되면서, 노드별 권한 분리가 가능해진 것이다.

이전에는 모든 Kubelet API 접근이 단일 권한으로 묶여 있어 노드 로그 조회 권한과 Pod exec 권한을 분리할 수 없었다. KubeletFineGrainedAuthz GA로 인해 nodes/log, nodes/metrics, nodes/exec 등을 개별적으로 허용하는 RBAC 설계가 가능해졌고, 이는 최소 권한 원칙 적용 범위를 노드 수준까지 확장한다.

UserNamespaces와 MutatingAdmissionPolicy의 실무 의미
UserNamespaces는 Pod Security Standards의 `restricted` 프로파일과 함께 사용하면 컨테이너 보안 레이어가 이중으로 구성된다. MutatingAdmissionPolicy는 Webhook 서버 장애가 API 서버 가용성에 영향을 주던 구조적 문제를 해소하는 것이 핵심이다.
## Beta 진입·Alpha 도입 — Kubernetes 1.36 변경사항 중 AI/ML 대응

InPlacePodLevelResourcesVerticalScaling (Beta, 기본 활성화)

Pod 레벨에서 CPU와 메모리를 인플레이스로 리사이징할 수 있는 기능이 Beta로 올라오면서 기본 활성화 상태가 되었다. 기존에는 리소스 변경 시 Pod를 재시작해야 했지만, 이제는 실행 중인 Pod의 리소스 요청을 직접 수정할 수 있는 것이다.

# 실행 중인 Pod의 CPU 요청을 즉시 변경 (재시작 없음)
kubectl patch pod my-pod --subresource=resize \
  --patch '{"spec":{"containers":[{"name":"app","resources":{"requests":{"cpu":"500m"}}}]}}'

다만 InPlacePodLevelResourcesVerticalScaling Beta의 실전 적용 예제(YAML manifest)는 공식 문서에 아직 충분히 제공되지 않은 상태다. Kubernetes v1.36 CHANGELOG에서 피처 게이트 관련 세부 사항을 확인할 수 있다.

항목단계기본 활성화핵심 변경
InPlacePodLevelResourcesVerticalScalingBetaOPod 재시작 없이 리소스 조정
DeviceTaintRules & TolerationsBetaODRA 디바이스에 taint/toleration 적용
ConstrainedImpersonationBetaO임퍼소네이션 보안 제어 강화
TopologyAwareWorkloadSchedulingAlphaX토폴로지 기반 PodGroup 스케줄링
WorkloadAwarePreemptionAlphaXAI/ML 워크로드 인식 프리엠션

DeviceTaintRules & Tolerations (KEP-5055)

DRA(Dynamic Resource Allocation) 디바이스에 taint와 toleration을 적용할 수 있게 되었다. GPU가 일부 불량이거나 특정 워크로드 전용으로 예약해야 하는 상황에서, 노드 taint와 유사한 방식으로 디바이스 수준 스케줄링 제어가 가능해지는 것이다.

taint/toleration 설정은 기존 노드 taint와 동일한 effect 값(NoSchedule, PreferNoSchedule, NoExecute)을 사용한다. 특정 GPU 모델(예: NVIDIA A100)을 고성능 학습 전용으로 예약하고, 일반 추론 워크로드에는 PreferNoSchedule을 설정하는 방식이 일반적인 활용 패턴이다. 이를 통해 기존에 노드 단위로만 가능했던 워크로드 격리를 디바이스 단위까지 세분화할 수 있다.

AI/ML 워크로드 대응 Alpha 기능

TopologyAwareWorkloadScheduling은 PodGroup 단위로 토폴로지를 고려한 스케줄링을 지원한다. 분산 학습에서 GPU 간 통신 레이턴시를 최소화하려면 같은 NUMA 노드나 같은 랙에 Pod를 배치해야 하는데, 이를 스케줄러 레벨에서 처리하겠다는 접근이다.

WorkloadAwarePreemption은 AI/ML 학습 작업처럼 장시간 실행되는 워크로드가 선점(preemption) 대상이 될 때, 워크로드 특성을 인식하여 선점 결정을 내리는 기능이다. 학습 완료 직전의 Pod가 선점당하는 비효율을 줄이기 위한 것인데, 아직 Alpha라 프로덕션 적용은 시기상조인 편이다.

kubectl ARCH 컬럼 추가와 실전 확인

글 서두에서 보여준 kubectl get node -o wide 출력의 ARCH 컬럼은 작은 변경이지만 실용적이다. 멀티 아키텍처(amd64/arm64) 클러스터를 운영할 때 노드 아키텍처를 한눈에 파악할 수 있게 된 것이다.

kubectl get node -o wide
# NAME   STATUS   ROLES   AGE   VERSION   INTERNAL-IP   EXTERNAL-IP   OS-IMAGE   KERNEL-VERSION   CONTAINER-RUNTIME   ARCH
# node1  Ready    ...     ...   v1.36.0   ...           ...           ...        ...              ...                 amd64

기존에는 노드 아키텍처를 확인하려면 kubectl describe node 또는 kubectl get node -o jsonpath='{.status.nodeInfo.architecture}'를 사용해야 했다. wide 출력에 기본 포함됨으로써 별도 명령 없이 확인 가능해진 셈이다.

ARM 노드와 x86 노드가 혼재하는 환경에서 이미지 호환성 문제를 진단할 때 유용하기도 하다. 특히 Graviton 인스턴스를 비용 절감 목적으로 섞어 쓰는 경우, 배포 실패 원인이 아키텍처 불일치인지 빠르게 파악하는 데 도움이 된다.

멀티 아키텍처 클러스터 운영 참고
ARCH 컬럼과 함께 nodeSelector 또는 nodeAffinity에서 `kubernetes.io/arch` 레이블을 활용하면 아키텍처별 Pod 배치를 명시적으로 제어할 수 있다. arm64 전용 워크로드와 amd64 전용 워크로드를 분리 배치하는 패턴이 일반적이다.
## Kubernetes 1.36 변경사항 정리 — 업그레이드 체크리스트

v1.36 업그레이드를 앞두고 있다면, 아래 체크리스트를 순서대로 확인하는 것이 효율적이다.

[업그레이드 전 체크리스트]
□ gitRepo 볼륨 사용 워크로드 → init container 또는 git-sync 전환
□ .spec.externalIPs 사용 Service → LoadBalancer/NodePort/Gateway API 전환 계획
□ Prometheus 메트릭: volume_operation_total_errors → volume_operation_errors_total
□ Prometheus 메트릭: etcd_bookmark_counts → etcd_bookmark_total
□ Portworx 인트리 → CSI 드라이버 전환 완료 여부
□ Flex-volumes 사용 여부 확인 (kubeadm 환경)
□ DRA 사용 시 ClusterRole에 binding/driver 서브리소스 권한 추가
□ Grafana 대시보드 메트릭명 갱신

핵심은 Breaking Change 4건(gitRepo 제거, 메트릭명 변경, Portworx 인트리 제거, DRA RBAC 요구사항)을 먼저 처리하고, Deprecation 1건(externalIPs)은 유예 기간 내 계획을 수립하는 순서로 진행하는 것이다.

v1.36의 GA 기능 중 UserNamespacesSupport와 MutatingAdmissionPolicy는 보안과 운영 효율 양쪽에서 큰 변화를 가져올 것이다. Beta로 올라온 InPlacePodLevelResourcesVerticalScaling은 VPA 운영 방식을 근본적으로 바꿀 가능성이 있으며, AI/ML 워크로드 대응 Alpha 기능들은 향후 릴리스에서의 발전 방향을 보여준다.

연관 주제로는 kubernetes mutating admission policy CEL 작성 패턴, kubernetes in-place pod resize 실전 YAML 예제, 그리고 클러스터 규모별 업그레이드 전략이 있다. InPlacePodLevelResourcesVerticalScaling이 Beta 기본 활성화된 만큼, in-place resize 적용 방법은 현재 클러스터에 직접 영향을 미치는 영역이다. Kubernetes v1.36 릴리스 공식 블로그 포스트에서 전체 enhancement 목록과 Kubernetes 1.36 변경사항 정리를 추가로 확인할 수 있다.

관련 글

이 글 공유하기