Skip to main content
BlogDevOps

Rilis Kubernetes 1.37: Apa yang Rusak Saat Upgrade dari 1.36

Kubernetes 1.37 Garhwal dibaca untuk platform team: default yang menyala sendiri, SELinuxMount, etcd RangeStream, jadwal deprecation, dan skrip preflight.

Matthews Wong

Software Engineer

Oktober 202612 menit baca
Rilis Kubernetes 1.37: Apa yang Rusak Saat Upgrade dari 1.36

Ringkasan Utama

Kubernetes 1.37 Garhwal rilis pada 26 Agustus 2026 dengan 67 enhancement: 16 Stable, 23 Beta, 27 Alpha, dan satu deprecation. Bagi platform team di 1.36, risiko upgrade ada pada default yang menyala sendiri: SELinuxMount, penolakan cgroup v1, streaming read etcd, concurrent watch decode, dan HPA scale to zero. Audit itu dulu.

Saya tidak menemukan bagian berisiko dari Kubernetes 1.37 dengan menggulir ke daftar Stable. Saya menemukannya dengan satu pertanyaan untuk setiap baris di release post: apakah ini mengubah perilaku di cluster yang flag-nya tidak disentuh siapa pun? Sebagian besar dari 67 enhancement menjawab tidak. Segelintir menjawab ya, dan merekalah yang membangunkan orang setelah control plane di-roll.

Ini bacaan dari sisi platform team atas rilis 1.37, bukan tur fitur. Saya belum menjalankan 1.37 di production, jadi setiap klaim di bawah bersumber dari release announcement, sneak peek bulan Juli, atau tiga post lanjutan di kubernetes.io yang saya baca penuh pada 17 Oktober 2026. Jika release post kurang jelas atau saling bertentangan, saya sebutkan. Deep dive terpisah membahas DRA, gang scheduling, HPA scale to zero, KYAML, manifest-based admission, dan migrasi ipvs; post ini adalah peta yang menunjukkan mana yang perlu Anda baca.

67 enhancement, dan kenapa jumlahnya angka yang paling kurang berguna

Announcement yang terbit 26 Agustus 2026 dengan tema Garhwal menghitung 67 enhancement: 16 naik ke Stable, 23 ke Beta, 27 masuk Alpha, dan 1 deprecation atau removal. Itu rilis berukuran normal. Angkanya tidak bilang apa-apa soal risiko upgrade, karena yang dihitung adalah KEP, bukan perubahan perilaku, dan sebuah KEP yang menambah field Alpha opt-in tidak membebani Anda sampai Anda memilih memakainya.

Satu hal kecil saat mengutip angka utamanya. Daftar Stable di post yang sama, di bawah judul yang menyebut 16, berisi 17 bullet. Pod Certificates dan ClusterTrustBundles adalah dua bullet dan, menurut post, dua KEP (4317 dan 3257), yang mungkin menjelaskan selisihnya, tetapi post tidak menyebutkannya. Saya akan mengutip 16 sebagai angka resmi proyek dan tidak berhitung dari situ.

Alih-alih menghitung, saya memilah. Saya membagi rilis jadi tiga tumpukan: perubahan yang aktif secara default dan menyentuh perilaku yang sudah Anda andalkan, perubahan opt-in yang bisa menunggu staging cluster, dan jam deprecation yang sudah mulai berjalan. Sisa post mengikuti urutan itu.

Sembilan default yang berubah di cluster yang tidak Anda sentuh

Tabel ini adalah isi post dalam bentuk ringkas. Setiap baris adalah sesuatu yang menurut release post aktif, diberlakukan, atau dihapus di 1.37 tanpa operator mengaktifkannya. Stage dan default berasal dari release announcement; kolom terakhir adalah mode kegagalan sebagaimana digambarkan proyek sendiri.

PerubahanStageDefault di 1.37Yang bisa bermasalah
SELinuxMount dan SELinuxChangePolicyStableAktif, dan hanya untuk volume yang CSIDriver-nya mengatur seLinuxMount ke truePod dengan label SELinux berbeda yang berbagi satu volume di satu node bisa gagal start
Static Pod yang mereferensikan Secret atau ConfigMapBug fixDiberlakukan; gate PreventStaticPodAPIReferences dihapusReferensi yang lolos karena bug lama kini dilarang, tanpa opt-out
Node yang masih memakai cgroup v1Phase-outfailCgroupV1 default true sejak 1.35Kubelet menolak inisialisasi kecuali Anda meng-override
Inisialisasi watch cacheStable, terkunci aktifAktif sejak 1.36Sebagian request terbatas ditolak dengan HTTP 429; client harus melakukan backoff
ConcurrentWatchObjectDecodeBeta sejak 1.31Dinyalakan di 1.37Hingga 10 konversi bisa menghantam satu CRD conversion webhook sekaligus
EtcdRangeStreamBetaAktif, hanya kube-apiserverButuh etcd 3.7 atau lebih baru; etcd lama diam-diam fallback ke unary Range
HPA scale to zeroBetaAktifHanya bekerja dengan metrik object atau external, tidak pernah CPU atau memory
MemoryQoSBetaAktif, dengan default yang dirancang agar tidak men-throttle workload lamaMemakai kontrol memory cgroups v2, jadi tidak berguna di node cgroup v1
Kondisi Unused pada PVCBetaAktifKondisi baru muncul di status PersistentVolumeClaim; hanya informatif

Perhatikan polanya. Tiga dari sembilan adalah pekerjaan scale control plane yang tidak akan pernah Anda lihat jika berjalan baik. Dua adalah penolakan yang bisa dideteksi sebelum upgrade, di node dan di manifest static Pod. Satu, SELinux, adalah perubahan perilaku sungguhan untuk sebagian workload. Tiga terakhir adalah fitur Beta yang default-nya dirancang tetap senyap sampai ada workload yang menyentuhnya. Ketimpangan itulah alasan saya memperlakukan audit sebagai pekerjaan pendek dan berurutan, bukan proyek.

Control plane diam-diam jadi lebih sulit dirobohkan

Item Stable terpenting untuk cluster besar adalah yang paling tidak glamor. Pekerjaan inisialisasi watch cache selesai: gate WatchCacheInitializationPostStartHook yang tersisa naik ke Stable dan dikunci aktif, setelah default aktif sejak 1.36. Warm-up cache tidak lagi membuat lonjakan request ke etcd, dan kube-apiserver kini mendelegasikan request terbatas dan menolak sisanya dengan HTTP 429, alih-alih membiarkan list dan watch yang mahal menghabiskan etcd atau kapasitas API Priority and Fairness. Post menyatakan jelas bahwa controller dan operator kustom harus menghormati Retry-After dan memakai exponential backoff.

Dua item Beta menyerang biaya startup yang sama dari sisi berbeda. EtcdRangeStream menambah RPC RangeStream server-streaming yang mengunci satu revisi MVCC dan mengembalikan chunk, sehingga API server tidak lagi merakit seluruh list di memory. Ia butuh etcd 3.7 atau lebih baru; terhadap etcd lama, API server menerima Unimplemented dan fallback ke unary Range. Tulisan di kubernetes.io menambahkan bahwa payload yang sama dulu berada di memory etcd dan API server sekaligus. ConcurrentWatchObjectDecode, yang Beta dan nonaktif sejak 1.31, kini aktif dan men-decode watch event dengan 10 worker sementara collector menjaga urutan event.

Angkanya milik proyek, bukan milik saya: pada 150k pod, concurrent decode saja memangkas inisialisasi cache sekitar 40 persen, dan sekitar 55 persen jika digabung dengan RangeStream. Saya belum mereproduksinya, dan saya tidak akan menjanjikannya ke stakeholder. Trade-off yang disebut post nyata dan spesifik: dengan gate aktif, hingga 10 konversi bisa berjalan bersamaan terhadap conversion webhook saat inisialisasi cache. Jika sebuah webhook membatasi concurrency-nya di bawah 10, siapkan diri bahwa ia menjadi bottleneck baru.

# Does your etcd meet the RangeStream floor? The release post says etcd 3.7+.
# Read the VERSION column; older etcd just means a silent fallback, not a failure.
etcdctl endpoint status --cluster -w table

# The post says etcdctl get --stream ships alongside the feature. Confirm the
# flag exists in your build before scripting around it.
etcdctl get --help | grep -i stream

# Which CRDs depend on a conversion webhook? These are the ones that now see
# up to 10 concurrent conversions while the watch cache warms.
kubectl get crd -o custom-columns=NAME:.metadata.name,CONVERSION:.spec.conversion.strategy | grep -i webhook

# Are any clients already being told to slow down? Needs access to /metrics.
kubectl get --raw /metrics | grep 'apiserver_request_total' | grep 'code="429"' | head

Sebelum upgrade, cari controller dan operator Anda sendiri yang memanggil list atau watch dalam loop dan pastikan mereka menghormati Retry-After. Proyek menjadikan 429 sebagai kontrak untuk watch cache yang sedang warm-up, jadi client yang retry seketika mengubah penolakan singkat menjadi badai buatan sendiri.

SELinux adalah satu-satunya yang benar-benar mengubah perilaku workload

Jika node Anda tidak menjalankan SELinux, lewati bagian ini: post April oleh Jan Safranek dan Swathi Rao menyebut kubelet melewati seluruh logika SELinux saat ia tidak tersedia atau nonaktif. Jika ya, SELinuxMount dan SELinuxChangePolicy sudah Stable dan aktif di 1.37. Volume lalu di-mount dengan label sebagai mount option, dalam waktu konstan, alih-alih runtime me-relabel setiap file, tetapi hanya jika CSI driver opt-in dengan seLinuxMount true pada objek CSIDriver-nya (plugin in-tree fc dan iscsi juga mendukung) dan Pod mengatur minimal seLinuxOptions.level.

Harganya satu mount, satu label. Dua kasus yang berjalan pada recursive relabelling kini tidak: Pod dengan label berbeda yang berbagi volume lewat subPath berbeda, serta Pod privileged dan unprivileged yang berbagi volume. Pada keduanya, satu Pod menunggu di ContainerCreating sampai yang lain berhenti. Proyek menyebut kasus pertama niche dan kasus kedua jarang tetapi pernah teramati di aplikasi. Release post menambahkan bahwa perilaku ini baru terkunci di 1.38, jadi Anda masih bisa mematikannya di seluruh cluster untuk satu rilis lagi.

# 1. Find the conflicts BEFORE upgrading (v1.36 tooling, from the April post).
#    Add the controller to kube-controller-manager:
--controllers=*,selinux-warning-controller

#    Then read the conflict metric. It names the Pods; the kubelet metric
#    volume_manager_selinux_volume_context_mismatch_warnings_total only counts them.
selinux_warning_controller_selinux_volume_conflict

# 2. Opt a conflicting workload out, per Pod. Recursive keeps the old behaviour.
apiVersion: v1
kind: Pod
metadata:
  name: legacy-shared-volume
spec:
  securityContext:
    seLinuxChangePolicy: Recursive   # Opt-out: fine for a legacy app, a poor default
    seLinuxOptions:
      level: "s0:c123,c456"
  containers:
    - name: app
      image: registry.example.com/app:1.0

# 3. After the upgrade, the kubelet counts Pods that could not start:
volume_manager_selinux_volume_context_mismatch_errors_total

Post April juga menyarankan menerapkan opt-out secara massal dengan MutatingAdmissionPolicy, mutating webhook, atau Kyverno atau Gatekeeper, alih-alih mengedit setiap Deployment. Satu peringatan dari post itu: metrik konflik membuka nama namespace, jadi diasumsikan hanya cluster administrator yang bisa membaca metrik kube-controller-manager.

Empat jam deprecation untuk dicatat di kalender

Tidak ada yang rusak pada hari upgrade, tetapi masing-masing kini punya tanggal atau pemicu. Release post dan sneak peek sepakat soal semuanya. Yang bertanggal memakai kata expected, bukan committed, jadi anggap sebagai input perencanaan.

ItemJamCara tahu Anda terdampak
kube-dnsTidak ada package baru diharapkan setelah v1.40; CoreDNS jadi default sejak v1.13Periksa image Deployment DNS di kube-system
kube-proxy mode ipvsWarning deprecation saat startup sekarang; nonaktif secara default diharapkan pada v1.40; dihapus pada v1.43Baca mode di ConfigMap kube-proxy
cgroup v1failCgroupV1 true sejak 1.35; penghapusan direncanakan di rilis mendatangCek tipe filesystem /sys/fs/cgroup di tiap node
kubectl run dengan --filename atau -fSedang di-deprecate; Pod yang dihasilkan hanya pernah berasal dari argumen CLICari flag itu di script CI Anda
# kube-dns or CoreDNS? On kubeadm clusters both keep the k8s-app=kube-dns label,
# so the label proves nothing. Read the image.
kubectl -n kube-system get deploy -o jsonpath='{range .items[*]}{.metadata.name}{"\t"}{.spec.template.spec.containers[*].image}{"\n"}{end}'

# ipvs mode, exactly as the release post gives it:
kubectl -n kube-system get configmap kube-proxy -o jsonpath='{.data.config\.conf}' | grep 'mode:'

# cgroup v1 or v2, run on each node. cgroup2fs means v2; tmpfs means v1.
stat -fc %T /sys/fs/cgroup

# Temporary kubelet override, which the post calls a short-term fix only.
# Memory QoS and in-place resize of memory-backed volumes need cgroup v2.
apiVersion: kubelet.config.k8s.io/v1beta1
kind: KubeletConfiguration
failCgroupV1: false

# Static Pods that reference Secrets or ConfigMaps (kubeadm default path).
# My grep is wider than the post's wording, so expect some false positives.
grep -lE 'secretRef|configMapRef|secretKeyRef|configMapKeyRef' /etc/kubernetes/manifests/*.yaml

Baris ipvs yang paling mungkin mengejutkan, karena ipvs diperkenalkan di v1.8 untuk mengatasi bottleneck iptables dan banyak cluster memilihnya bertahun-tahun lalu. Alasan di post: API ipvs kernel tidak bisa mengimplementasikan Kubernetes Service sepenuhnya, jadi mode ipvs tetap memakai iptables di bawahnya. Target migrasi yang bersih adalah mode nftables, yang di rilis ini juga mendapat jalur rule berbasis netlink dan proxy localhost NodePort opt-in.

Fitur opt-in yang layak dicoba di staging, dan yang bisa dilewati

Semua di sini nonaktif secara default atau Alpha, jadi tidak ada yang bisa merugikan Anda sampai Anda memutuskan. Pertanyaannya, mana yang layak memakai waktu staging cluster. Saya mengurutkannya dari yang paling langsung menggantikan sesuatu yang sudah Anda operasikan.

Pertama, HPA scale to zero, kini Beta dan aktif secara default: atur minReplicas ke 0 pada workload yang digerakkan metrik object atau external, misalnya queue, dan HPA mencatat kondisi ScaledToZero agar bisa membedakan scale-down miliknya dari Deployment yang dinolkan manual. Kedua, API StorageVersionMigration sudah Stable dan aktif: objek deklaratif kini menggantikan loop kubectl replace dan migrator out-of-tree, dan post kubernetes.io menyebut ia juga menulis ulang data setelah perubahan encryption at rest. Ketiga, kondisi lifecycle Node DrainInProgress, Drained, MaintenancePlanned, MaintenanceInProgress, dan GracefulNodeShutdownInProgress, yang Alpha, layak dibaca jika Anda memelihara controller node-drain. Lewati pod-level checkpoint and restore kecuali runtime Anda sudah mengimplementasikan RPC CheckpointPod dan RestorePod; post menyatakan itu wajib.

# Scale a queue consumer to zero. External metrics only: the post is explicit that
# CPU and memory cannot drive scale to zero because they need running Pods.
# The metric name below is a placeholder from my own example, not from the post.
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: queue-worker
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: queue-worker
  minReplicas: 0
  maxReplicas: 20
  metrics:
    - type: External
      external:
        metric:
          name: queue_messages_ready
        target:
          type: AverageValue
          averageValue: "30"

---
# Rewrite stored objects after a CRD storage version change. From the kubernetes.io
# storage version migration post.
apiVersion: storagemigration.k8s.io/v1
kind: StorageVersionMigration
metadata:
  name: crontabs-migration
spec:
  resource:
    group: example.com
    resource: crontabs

---
# Kubelet-side gates from the release post, all off by default. Staging only.
apiVersion: kubelet.config.k8s.io/v1beta1
kind: KubeletConfiguration
featureGates:
  PodAndContainerStatsFromCRI: true
  PodLevelResourceManagers: true

Rilis ini juga menaikkan beberapa bagian DRA ke Stable, yaitu extended resources, device taints and tolerations, field status ResourceClaim, dan atribut numaNode standar, serta memindahkan gang scheduling dan workload-aware preemption ke Beta. Itu layak dibaca sendiri dan dibahas di post terpisah, bukan diulang di sini.

Di mana 1.37 masih bisa melukai Anda

Trade-off jujur di rilis ini adalah bahwa perubahan yang tampak paling aman justru memindahkan beban. Streaming read dan concurrent decode membuat API server lebih tenang, dan memindahkan tekanan ke etcd 3.7 dan ke webhook Anda. Keduanya tidak muncul di checklist fitur, dan saya memperkirakan tanda pertamanya adalah conversion webhook yang panas saat API server restart, bukan pesan error.

Release post mendokumentasikan regresi nyata yang tidak boleh diulang. Di 1.36, bug pada field maxUnavailable StatefulSet bisa membuat Pod macet di CrashLoopBackOff tanpa batas jika revisi pertama yang rusak tidak pernah ready; field itu diaktifkan kembali secara default di 1.37 setelah perbaikan (kubernetes#137409). Jika Anda mematikan MaxUnavailableStatefulSet sebagai workaround, cek gate-nya sebelum berasumsi tidak ada yang berubah.

Tiga jebakan yang lebih kecil. Scale to zero tampak seperti fitur hemat biaya dan gagal diam-diam jika diarahkan ke metrik CPU, karena proyek tidak mendukungnya. Memory QoS aktif secara default, tetapi default-nya dipilih agar tidak ada throttling mengejutkan, sehingga perilakunya bergantung pada pengaturan kubelet memoryReservationPolicy dan memoryThrottlingFactor, dan keduanya layak dibaca sebelum Anda berasumsi tidak ada yang berubah. Dan perubahan SELinux membuat Pod yang konflik menunggu di ContainerCreating, jadi buat alert untuk kondisi itu, bukan hanya crash loop.

Yang dikerjakan hari Senin

Ini urutan yang akan saya jalankan, dari yang termurah dan paling informatif. Tidak ada langkah yang mengubah cluster; semuanya hanya membaca.

  1. Inventarisasi node: versi kubelet, container runtime, dan versi cgroup. Satu node cgroup v1 saja memblokir kubelet kecuali Anda mengatur failCgroupV1 ke false, jadi temukan sebelum rollout menemukannya.
  2. Cek etcd. Jika di bawah 3.7, rencanakan upgrade etcd sebagai perubahan tersendiri; RangeStream akan fallback dengan aman, jadi ini keuntungan yang Anda pilih, bukan blocker.
  3. Jika ada node yang menjalankan SELinux enforcing, aktifkan selinux-warning-controller di 1.36 dan baca metrik konflik selama seminggu penuh traffic, bukan satu sore.
  4. Daftar CRD conversion webhook Anda dan cek concurrency yang sanggup ditangani masing-masing. Naikkan, atau terima bahwa warm-up cache kini memakai hingga 10 konversi bersamaan.
  5. Baca ConfigMap ipvs dan image DNS. Jika salah satunya masih yang lama, ajukan migrasi terhadap tanggal v1.40, bukan terhadap penghapusan v1.43.
#!/usr/bin/env bash
# Read-only 1.37 preflight. Run from a machine with kubectl and etcdctl.
set -euo pipefail

echo '== node versions and runtimes =='
kubectl get nodes -o custom-columns=NAME:.metadata.name,KUBELET:.status.nodeInfo.kubeletVersion,RUNTIME:.status.nodeInfo.containerRuntimeVersion

echo '== kube-proxy mode =='
kubectl -n kube-system get configmap kube-proxy -o jsonpath='{.data.config\.conf}' | grep 'mode:' || echo 'no mode line found'

echo '== CRDs with conversion webhooks =='
kubectl get crd -o custom-columns=NAME:.metadata.name,CONVERSION:.spec.conversion.strategy | grep -i webhook || echo none

echo '== etcd versions =='
etcdctl endpoint status --cluster -w table

echo '== 429s already served =='
kubectl get --raw /metrics | grep 'apiserver_request_total' | grep 'code="429"' | head -5 || true

echo '== static pod manifests touching Secrets or ConfigMaps =='
grep -lE 'secretRef|configMapRef|secretKeyRef|configMapKeyRef' /etc/kubernetes/manifests/*.yaml 2>/dev/null || echo none

Jalankan pengecekan cgroup di tiap node secara terpisah, karena kubectl tidak bisa melihatnya: stat -fc %T /sys/fs/cgroup. Lalu baca changelog 1.37 lengkap untuk hal yang spesifik pada distribusi Anda sebelum menjadwalkan rollout.

Aturan yang saya ambil dari 1.37 adalah memilah rilis berdasarkan default, bukan berdasarkan stage. Enam belas fitur Stable tidak terlalu berarti bagi saya, sementara segelintir gate Beta yang sudah aktif dan satu perubahan SELinux menentukan apakah upgrade berjalan membosankan. Audit yang aktif tanpa diminta, catat tanggal deprecation di kalender, dan biarkan daftar Alpha untuk staging cluster yang punya waktu.

FAQ

Pertanyaan Umum

Jawaban singkat untuk pertanyaan yang paling sering diajukan pembaca tentang topik ini.

Apa yang baru di Kubernetes 1.37?

Kubernetes 1.37 dengan nama Garhwal dirilis pada 26 Agustus 2026 dengan 67 enhancement: 16 Stable, 23 Beta, 27 Alpha, dan 1 deprecation atau removal. Sorotannya mencakup API metrics.k8s.io yang Stable setelah hampir sembilan tahun di Beta, KYAML, SELinuxMount, HPA scale to zero di Beta, dan pod-level checkpoint and restore di Alpha.

Apakah upgrade ke Kubernetes 1.37 akan merusak cluster saya?

Biasanya tidak, tetapi beberapa default berubah tanpa flag apa pun. SELinuxMount bisa membuat Pod yang berbagi volume dengan label SELinux berbeda macet di ContainerCreating, dan node yang masih memakai cgroup v1 membuat kubelet menolak start kecuali failCgroupV1 diatur ke false. Audit keduanya di 1.36 sebelum menjalankan upgrade.

Apakah saya butuh etcd 3.7 untuk Kubernetes 1.37?

Tidak wajib. EtcdRangeStream berstatus Beta dan aktif secara default untuk kube-apiserver, tetapi butuh etcd 3.7 atau lebih baru agar berlaku. Terhadap etcd lama, API server mendeteksi respons Unimplemented dan fallback ke pemanggilan unary Range tanpa perubahan perilaku.

Kapan mode ipvs kube-proxy dihapus?

Kubernetes 1.37 mencatat warning deprecation saat startup untuk mode ipvs. Release post memperkirakan ipvs nonaktif secara default pada v1.40 dan dihapus sepenuhnya pada v1.43. Anda bisa cek mode saat ini dengan membaca baris mode di ConfigMap kube-proxy.

Bisakah HPA men-scale Deployment ke nol di Kubernetes 1.37?

Bisa. HPA scale to zero berstatus Beta dan aktif secara default, dan Anda mengikutsertakan workload dengan mengatur minReplicas ke 0. Fitur ini hanya bekerja dengan metrik object atau external, misalnya kedalaman queue, karena metrik CPU dan memory butuh Pod yang berjalan.