최신글

Kubernetes v1.36 업그레이드 전에 확인할 운영 영향과 핸즈온

반응형

이 글은 kubernetes v1.36 릴리즈 노트를 읽고, 패치 내용 요약과 몇 가지 핸즈온을 더한 글입니다. 

 

새로운 기능

Stable MutatingAdmissionPolicy CEL 기반 in-process mutation 정책 단순 label, field, default injection은 webhook보다 운영 부담이 적음
Stable User Namespaces for pods 컨테이너 root를 host 비권한 UID/GID로 매핑 multi-tenant 환경과 breakout 방어에 유리하지만 runtime, volume, securityContext 호환성 확인 필요
Stable Fine-grained kubelet API authorization kubelet API 권한을 nodes/proxy보다 세밀하게 제어 monitoring agent 권한을 least privilege로 줄일 수 있음
Stable VolumeGroupSnapshot 여러 PVC를 crash-consistent하게 snapshot CSI driver와 snapshot controller 지원이 전제
Stable Mutable CSINode allocatable CSI driver가 node별 volume attach limit을 동적으로 갱신 volume attach limit이 바뀌는 환경에서 scheduling 실패를 줄임
Stable DRA prioritized alternatives DRA device request에 우선순위 기반 fallback 가능 GPU 모델 fallback 같은 AI/HPC scheduling에 유용
Stable PSI metrics on cgroup v2 kubelet이 CPU, memory, I/O stall time을 node, pod, container 수준으로 노출 단순 사용률보다 node contention 분석에 도움
Alpha MemoryQoS with cgroup v2 memory.high, memory.min, memory.low로 pod QoS class별 memory 보호를 조정 kernel, runtime, kubelet 설정이 맞는 node에서만 실험적으로 검토
Beta Resource health status pod status에서 device health 확인 GPU/가속기 장애 원인 추적에 도움
Beta Strict IP/CIDR validation 잘못된 IP/CIDR 입력을 더 엄격하게 검증 오래된 manifest에 비정상 값이 있으면 경고나 실패 가능성 확인 필요
Beta .kuberc cluster config와 kubectl 사용자 preference 분리 개인 CLI 설정과 cluster 접근 설정을 분리 가능
Beta DRA device taints/tolerations node taint처럼 device 상태를 scheduling에 반영 가속기 장애, 점검, 격리 운영에 유용
Beta Constrained Impersonation impersonation 권한을 수행 가능 action과 함께 제한 controller 권한 위임 리스크 감소
Beta /statusz, /flagz component 상태와 실행 flag를 HTTP endpoint로 확인 장애 대응 때 control plane 설정 확인이 쉬워짐
Alpha HPA scale to zero external/object metric 기반으로 replica 0까지 축소 비용 절감 가능성이 있지만 feature gate와 metric 설계가 필요
Alpha Manifest-based admission control config admission policy를 API object가 아니라 static file에서 로드 etcd 장애나 policy 삭제 공격에도 admission 보호 가능성
Alpha Native histogram metrics kube-apiserver 등에서 sparse histogram 기반 metric 실험 SLI/SLO 해상도 개선 가능성, metric backend 호환성 확인 필요

 

변경되는  기능

가장 눈에 띄는 변경은 Service.spec.externalIPs deprecation입니다. v1.36부터 externalIPs를 사용하는 service를 생성하거나 수정하면 warning이 표시됩니다.

공식 릴리즈 글과 KEP-5707 기준으로 kube-proxy의 externalIPs 지원은 단계적으로 제거될 예정입니다. v1.40에서는 AllowServiceExternalIPs feature gate 기본값이 false로 바뀌고, v1.43에서는 feature gate가 잠기며 관련 구현이 제거될 예정입니다.

 

그 외에도 일부 메트릭과 플러그인 동작이 변경되었습니다.

ACTION REQUIRED volume_operation_total_errors metric 이름이 volume_operation_errors_total로 변경 Prometheus alert, Grafana dashboard, recording rule이 깨질 수 있음 모니터링 repo에서 기존 metric 검색
ACTION REQUIRED scheduler PreBind plugin 병렬 실행 인터페이스 변경 custom scheduler plugin이 있으면 PreBindPreFlightResult 대응 필요 사내 scheduler plugin 코드 검색
ACTION REQUIRED DRA ResourceClaim status update RBAC 세분화 DRA driver/controller가 403을 만날 수 있음 DRA 사용 cluster의 ClusterRole 확인
ACTION REQUIRED kubeadm flex-volume 통합 지원 제거 kubeadm이 더 이상 KCM static pod에 flex-volume 경로를 자동 mount하지 않음 flex-volume 사용 여부 확인
ACTION REQUIRED etcd_bookmark_counts metric 이름이 etcd_bookmark_total로 변경 etcd/API server 관련 alert와 dashboard 수정 필요 모니터링 repo에서 기존 metric 검색
Deprecation Service.spec.externalIPs deprecated v1.36부터 warning이 발생하고, KEP-5707 기준 kube-proxy 지원이 단계적으로 제거될 예정 kubectl get svc -A -o yaml에서 externalIPs 검색
Removed/Disabled gitRepo volume plugin 비활성화, 다시 켤 수 없음 gitRepo volume을 쓰는 pod가 더 이상 정상 동작하지 않음 manifest에서 gitRepo: 검색
Removed in-tree Portworx volume plugin 제거 Portworx in-tree 경로 의존 cluster는 CSI migration 상태 확인 필요 PV/StorageClass provisioner 확인
Removed cAdvisor의 container_cpu_load_average_10s, container_cpu_load_d_average_10s, cpu_tasks_state metric 제거 사용 중인 dashboard panel이 빈 값이 될 수 있음 Prometheus query 검색

 

실습

쿠버네티스 설치

Docker 컨테이너로 실습을 진행했고, k3d로 kubernetes 클러스터를 설치했습니다. Docker image 버전은 2026년 5월 10일 기준 최신 이미지를 선택했습니다.

  • 선택한 Docker image: rancher/k3s:v1.36.0-k3s1

 

k3d 클러스터를 설치하려면 k3d CLI가 있어야 합니다.

# MacBook
curl -L -o /tmp/k3d-darwin-arm64 https://github.com/k3d-io/k3d/releases/download/v5.8.3/k3d-darwin-arm64
chmod +x /tmp/k3d-darwin-arm64
/tmp/k3d-darwin-arm64 version

 

k3d CLI로 클러스터를 생성합니다.

k3d cluster create k8s-136 \
  --image rancher/k3s:v1.36.0-k3s1

 

클러스터 삭제

k3d cluster delete k8s-136

 

user namespace

user namespace는 컨테이너의 root UID가 host의 root UID를 직접 사용하지 못하게 하는 기능입니다. user namespace를 사용하면 컨테이너 내부의 root UID는 host에서 root가 아니라 별도의 UID로 보입니다.

 

user namespace를 사용하려면 hostUsers: false를 설정하면 됩니다.

apiVersion: v1
kind: Pod
metadata:
  name: userns-root-pod
spec:
  hostUsers: false
  containers:
    - name: shell
      image: busybox:1.36.1
      command:
        - sh
        - -c
        - id && sleep 3600
      securityContext:
        runAsUser: 0
        runAsGroup: 0

 

제약사항은 공식 문서에서 확인할 수 있습니다.

눈에 띄는 제약사항은 NFS 볼륨을 마운트할 때 user namespace를 사용할 수 없다는 점입니다. user namespace를 사용하더라도 idmap mounts 기능으로 컨테이너 내부에서는 고정된 UID 권한으로 파일을 사용할 수 있습니다. 하지만 NFS는 아직 idmap mounts를 지원하지 않습니다.

 

externalIPs deprecated 확인

externalIPs가 설정된 service를 생성하면 warning 메시지를 볼 수 있습니다.

apiVersion: v1
kind: Service
metadata:
  name: deprecated-external-ip-demo
  labels:
    app.kubernetes.io/name: deprecated-external-ip-demo
spec:
  type: ClusterIP
  # externalIPs 설정
  externalIPs:
    - 203.0.113.10
  selector:
    app.kubernetes.io/name: external-ip-demo
  ports:
    - name: http
      port: 80
      targetPort: 8080
      protocol: TCP

 

MutatingAdmissionPolicy

기존에는 admission controller에서 mutation을 적용하려면 webhook과 webhook 요청을 처리할 API server가 필요했습니다. v1.36부터는 webhook server 없이 MutatingAdmissionPolicy와 MutatingAdmissionPolicyBinding API resource로 단순 mutation을 정의할 수 있습니다. mutation 동작원리가 궁금하신 분은 이전 글을 참고바랍니다. 

- admission controller 동작원리: https://malwareanalysis.tistory.com/704

 

쿠버네티스 Admission controller

1. Admission controller이란? 쿠버네티스 Admission controller는 말 그대로 Admission 기능을 수행합니다. Admission이라는 영어 단어는 허가를 의미하며, 쿠버네티스 세계에서 Admission은, 쿠버네티스 요청을 수

malwareanalysis.tistory.com

 

아래 예제는 pod가 생성되면 label을 추가하는 mutation을 정의합니다.

apiVersion: admissionregistration.k8s.io/v1
kind: MutatingAdmissionPolicy
metadata:
  name: add-release-label.example.com
  labels:
    app.kubernetes.io/name: k8s-136-release-notes
spec:
  matchConstraints:
    resourceRules:
      - apiGroups:
          - ""
        apiVersions:
          - v1
        operations:
          - CREATE
        resources:
          - pods
  matchConditions:
    - name: skip-if-release-label-exists
      expression: "!has(object.metadata.labels) || !('release.kubernetes.io/tested-version' in object.metadata.labels)"
  failurePolicy: Fail
  reinvocationPolicy: Never
  mutations:
    - patchType: JSONPatch
      jsonPatch:
        expression: >
          !has(object.metadata.labels) ?
          [
            JSONPatch{
              op: "add",
              path: "/metadata/labels",
              value: {"release.kubernetes.io/tested-version": "v1.36"}
            }
          ] :
          [
            JSONPatch{
              op: "add",
              path: "/metadata/labels/" + jsonpatch.escapeKey("release.kubernetes.io/tested-version"),
              value: "v1.36"
            }
          ]

 

apiVersion: admissionregistration.k8s.io/v1
kind: MutatingAdmissionPolicyBinding
metadata:
  name: add-release-label-binding.example.com
  labels:
    app.kubernetes.io/name: k8s-136-release-notes
spec:
  policyName: add-release-label.example.com

 

아래 pod를 생성하면 MutatingAdmissionPolicy와 MutatingAdmissionPolicyBinding 설정 때문에 pod에 label이 추가됩니다.

apiVersion: v1
kind: Pod
metadata:
  name: map-sample-pod
  labels:
    app.kubernetes.io/name: map-sample
spec:
  restartPolicy: Always
  containers:
    - name: pause
      image: registry.k8s.io/pause:3.10
      resources:
        requests:
          cpu: 5m
          memory: 16Mi
        limits:
          cpu: 50m
          memory: 64Mi

 

 

 

참고자료

반응형