Kubernetes cgroup v2 Geçişi: Node’larda Ne Değişiyor

Kubernetes’te cgroup v1 desteği deprecat ediliyor; v1.35’ten itibaren kubelet varsayılan olarak cgroup v1’i çalıştırmıyor. Geçişte Memory QoS, container bazlı OOM davranışı ve PSI gibi cgroup v2’ye bağlı iyileştirmeler öne çıkıyor.

Linux tarafında cgroups (control groups), sistem kaynaklarını yönetmek için kullanılan bir çekirdek özelliği. Kubernetes de CPU ve bellek gibi kaynakları container’lara dağıtırken bu mekanizmaya dayanıyor; böylece uygulamalar birbirini etkilemeden çalışabiliyor. Artık cgroup v1 kullanımdan kaldırılma sürecine girdiği için, Linux node’larını cgroup v2’ye taşımak isteğe bağlı bir iyileştirme olmaktan çıkıp yükseltme planının zorunlu bir parçası hâline geliyor. Bu yazıda neyin ne zaman değiştiğini, hangi özelliklerin yalnızca cgroup v2 ile çalıştığını ve geçiş sonrası doğrulamayı nasıl yapacağınızı derledim.

cgroup v1’in kullanımdan kaldırılması ve takvim

cgroup v2 yönetimi Kubernetes v1.25’ten bu yana stabil durumda. Kubernetes v1.31 ile birlikte v1 cgroup desteği maintenance mode‘a alınmıştı. Şimdi ise cgroup v1 resmen deprecate edildi.

Pratik sonuçları şöyle:

  • Kubernetes v1.35’ten itibarenfailCgroupV1 varsayılan olarak true. Yani kubelet, cgroup v1 çalıştıran bir node’da varsayılan yapılandırmayla başlamıyor.
  • Yöneticiler kubelet yapılandırma dosyasında geçici olarak failCgroupV1: false ayarlayabilir; ancak bu geçici çözüm Kubernetes deprecation politikası çerçevesinde kaldırılacak.
  • Geri dönüş (fallback) seçeneği Kubernetes v1.38’de kaldırılmak üzere planlanmış durumda. Kaldırma çalışmaları KEP-5573 altında takip ediliyor.

v1.35 öncesi bir sürümdeyseniz, yükseltmeden önce tüm Linux node’larını cgroup v2’ye taşıyın ya da geçici failCgroupV1: false geçersiz kılmasını planlayın. Zaten v1.35 veya sonrasındaysanız, her Linux node’unun cgroup v2 ile çalıştığını (veya bilinçli olarak override bıraktığınızı) doğrulayın.

kubeadm kullanıyorsanız kontrol daha erken devreye giriyor

k8s.io/system-validators tarafından sağlanan SystemVerification preflight kontrolü, Kubernetes v1.35 ile birlikte daha katı davranıyor: kubelet v1.35 veya sonrası ile cgroup v1 tespit edilirse kubeadm init, kubeadm join ve kubeadm upgrade sırasında hata dönduruyor. Daha eski bir kubelet söz konusuysa kontrol yalnızca uyarı olarak kalıyor.

cgroup v2 ile gelenler: Memory QoS, OOM ve PSI

cgroup v2, tek bir birleşik hiyerarşi, daha tutarlı bir arayüz ve kaynak izolasyonu için daha sağlam bir temel sunuyor. Kubernetes tarafındaki somut karşılıkları şunlar:

Memory QoS ve katmanlı bellek koruması

Memory QoS, Kubernetes v1.22’de alpha olarak geldi, v1.27’de güncellendi ve v1.36’da hâlâ alpha. Yeni hâliyle bellek kısıtlamasını (throttling) bellek rezervasyonundan ayırıyor ve katmanlı koruma ekliyor. Bu özellik yalnızca cgroup v2 kullanan Linux node’larında çalışıyor; çünkü doğrudan cgroup v2 bellek denetleyicisine dayanıyor: memory.high throttling, memory.min ve memory.low ise sırasıyla sert ve yumuşak koruma sağlıyor. cgroup v1 bu koruma modelini sunamıyor.

  • MemoryQoS feature gate’i etkinleştirildiğinde Burstable container’lara memory.high throttling uygulanıyor. Eşik; request, limit ve memoryThrottlingFactor (varsayılan 0.9) üzerinden hesaplanıyor.
  • memoryReservationPolicy: None varsayılan değer; memory.min veya memory.low yazmıyor.
  • memoryReservationPolicy: TieredReservation, Guaranteed Pod bellek isteklerini memory.min‘e (sert koruma), Burstable Pod isteklerini memory.low‘a (yumuşak koruma) eşliyor. BestEffort Pod’lar hiçbir koruma almıyor.
  • kubelet, node üzerindeki toplam memory.min ve memory.low rezervasyonları için Alpha metrikleri yayınlıyor.
  • Kernel 5.9 veya sonrası öneriliyor. Daha eski çekirdeklerde memory.high geri kazanımı bilinen bir livelock’u tetikleyebiliyor; v1.36’dan itibaren kubelet, etkilenen bir çekirdekte Memory QoS açıldığında uyarı logluyor.

Katmanlı korumayı açmak için örnek yapılandırma:

apiVersion: kubelet.config.k8s.io/v1beta1
kind: KubeletConfiguration
featureGates:
MemoryQoS: true
memoryReservationPolicy: TieredReservation
memoryThrottlingFactor: 0.9

Kubernetes’in genel önerisi Alpha özellikleri üretimde açmamak yönünde. Yine de bu yapıyı platformunuz için değerli görüyorsanız, TieredReservation‘ı etkinleştirmeden önce yapılandırmayı test edin ve sert rezerve edilen belleği hesaba katın.

Container farkındalıklı OOM davranışı

cgroup v2 node’larında kubelet, singleProcessOOMKill değerini varsayılan olarak false yapıyor. Böylece her container cgroup’u için memory.oom.group ayarlanıyor ve bir OOM olayı o container’daki tüm süreçleri birlikte sonlandırıyor; çok süreçli bir container yarım çalışır hâlde kalmıyor. Çekirdeğin süreçleri tek tek öldürebildiği cgroup v1 uyumlu davranışa ihtiyacınız varsa singleProcessOOMKill: true ayarlayabilirsiniz.

Bu davranışın kapsamı container cgroup’u, Pod’un tamamı değil. Ayrıca cgroup.kill bambaşka bir yönetim arayüzü: içine 1 yazmak o cgroup ve altındaki tüm süreçlere SIGKILL gönderir, OOM davranışını yapılandırmaz. cgroup v2 bellek denetleyicisi ayrıca izleme sistemlerinin ve kullanıcı alanı OOM yöneticilerinin gözlemleyebileceği memory.events sayaçlarını sunuyor.

PSI ve eBPF tarafı

Pressure Stall Information (PSI), node, Pod ve container düzeyinde CPU, bellek ve G/Ç çekişmesini raporluyor. Destekleyen kümelerde kubelet PSI’yi varsayılan olarak sunuyor (KubeletPSI stabil ve kilitli). Gereksinimleri: cgroup v2, Linux 4.20 veya sonrası, CONFIG_PSI=y ve psi=0 ile açılmamış bir çekirdek. Veriler Summary API ve /metrics/cadvisor üzerinden erişilebiliyor.

Cihaz erişim denetimleri de değişiyor: cgroup v1’de bu denetimler arayüz dosyalarıyla sunulurken, cgroup v2 cihaz denetleyicisinin arayüz dosyası yok ve cgroup BPF üzerine kurulu. Cilium, soket tabanlı yük dengeleme için BPF cgroup programlarını bağlıyor ve varsayılan cgroup kökü olarak /run/cilium/cgroupv2 kullanıyor.

Rootless ve kullanıcı ad alanları

cgroup v1’de denetleyicileri daha az ayrıcalıklı container’lara devretmek riskli olabiliyordu. cgroup v2 ise delegasyonu resmen destekliyor; rootless container uygulamalarının çoğu v2 denetleyicilerini root olmayan kullanıcılara devretmek için systemd’ye dayanıyor. Bu delegasyon mekanizması, container kullanıcılarını ayrıcalıksız host kullanıcılarına eşleyen Kubernetes Pod user namespace özelliğinden ayrıdır. Pod user namespace desteği Kubernetes v1.36’da stabil seviyeye ulaştı; etkinleştirmeden önce dosya sistemi, çekirdek, CRI runtime ve OCI runtime ön koşullarını kontrol edin.

Yerinde kaynak güncellemeleri

In-place Pod vertical scaling, Kubernetes v1.35’te stabil oldu. v1.36 ise Pod düzeyindeki kaynaklar için yerinde dikey ölçeklemeyi Beta olarak varsayılan açtı. kubelet, Pod düzeyi ve container cgroup’ları arasındaki değişiklikleri koordine ediyor: artışlarda container limitleri büyümeden önce headroom oluşturuluyor, azaltmalarda ise Pod düzeyi sınır daraltılmadan önce container’lar kısıtlanıyor. Bu v1.36 özelliğinde toplu (aggregate) yaptırımın doğru çalışması cgroup v2 gerektiriyor.

CPU weight dönüşümü

cgroup v1 cpu.shares, cgroup v2 ise cpu.weight kullanıyor. Yeni OCI runtime’lar, varsayılan önceliği koruyan ve küçük CPU isteklerine daha kullanışlı bir çözünürlük veren geliştirilmiş, doğrusal olmayan bir dönüşüm uyguluyor. Değişiklik Kubernetes’te değil OCI runtime tarafında: crun v1.23 ve runc v1.3.2 ile geliyor. Runtime yükselttikten sonra, kesin cpu.weight değerlerini tahmin eden izleme veya politika araçlarının güncellenmesi gerekebilir.

Bilinen sınır: active_file belleği

kubelet, active_file belleğini geri kazanılabilir saymıyor. Yoğun G/Ç yapan iş yüklerinde büyük bir page cache, kubelet’in bellek baskısı raporlamasına ve Pod’ların tahliye edilmesine yol açabiliyor. Bu, kubernetes/kubernetes#43916 ile takip edilen bilinen bir kubelet sorunu ve cgroup v2’ye geçmek bu hesaplamayı tek başına değiştirmiyor. Belgelenen geçici çözüm, yoğun G/Ç yapan container’lar için uygun bir değeri ölçtükten sonra bellek request ve limit değerlerini eşitlemek.

cgroup v2’ye geçiş gereksinimleri

  • v2 cgroup yönetimini destekleyen bir Kubernetes sürümü — v1.25’ten beri stabil ve desteklenen tüm sürümlerde mevcut.
  • En az bir Linux node; cgroup yalnızca Linux’a özgü bir kavram.
  • İşletim sistemi kurulumunun cgroup v2 etkin çalışması.
  • Kernel sürümü 5.8 veya sonrası (Memory QoS kullanılacaksa 5.9 ve üzeri öneriliyor).
  • cgroup v2 destekleyen bir container runtime: containerd v1.4 ve sonrası destekliyor, otomatik cgroup sürücüsü keşfi için containerd v2.0 ve sonrası; CRI-O tarafında v1.20 ve sonrası.
  • kubelet ile container runtime’ın aynı cgroup sürücüsünü kullanacak şekilde yapılandırılması.

Çekirdek tarafındaki kilometre taşları şöyle: cgroup v2 yönetimi ilk kez Linux 4.5 ile (2016) geldi ve io, memory, pids denetleyicilerini destekliyordu. cpu denetleyicisi Linux 4.15’te eklendi, PSI desteği 4.20 ile başladı. Kubernetes projesi, cgroup düzeyinde task freezer desteği bulunmadığı için 5.2’den eski çekirdeklerde cgroup v2 kullanılmasını önermiyor. Belgelenen minimum sürüm 5.8 (kök cgroup’un sistem düzeyi cpu.stat dosyası bu sürümde eklendi), Memory QoS’un dayandığı memory.high livelock düzeltmesi 5.9 ve sonrasında, memory.peak ise 5.19’da geldi.

Geçiş sırasında cgroup dosya sistemini doğrudan okuyan yazılımları da güncelleyin; geçiş rehberi cAdvisor v0.43.0 veya sonrasını öneriyor ve uyumlu Java, Node.js ile automaxprocs sürümlerini listeliyor.

cgroup sürücüsü yapılandırması

kubelet’in cgroup sürücüsü, container runtime’ınkiyle eşleşmeli. kubeadm kullanıyorsanız Kubernetes systemd sürücüsünü öneriyor; çünkü kubeadm, kubelet’i bir systemd servisi olarak yönetiyor. Başka bir yönetim aracı kullanıyorsanız o aracın belgelerine bakın.

kubelet, runtime’ın önerdiği cgroup sürücüsünü otomatik tespit etmeye çalışıyor. Bu otomatik tespit, RuntimeConfig CRI RPC’sini uygulayan bir runtime gerektiriyor (containerd v2.0+ veya CRI-O v1.28+). KEP-4033 ile takip edilen bu otomatik keşif Kubernetes v1.34’te stabil oldu ve kullanılabilir olduğunda kubelet, yapılandırılmış cgroupDriver değeri yerine runtime’ın bildirdiği değeri kullanıyor.

cgroup v2 destekleyen ama otomatik tespiti desteklemeyen bir runtime kullanıyorsanız kubelet yapılandırma dosyasında manuel geçersiz kılma yapabilirsiniz:

apiVersion: kubelet.config.k8s.io/v1beta1
kind: KubeletConfiguration
cgroupDriver: systemd

Doğrulama ve sorun giderme

Node üzerinde işe yarayacak temel komutlar:

  • stat -fc %T /sys/fs/cgroup/ — cgroup v2 etkin mi? cgroup2fs dönmeli.
  • systemctl list-units 'kube*' --type=slice veya --type=scope — systemd’nin bellekte tuttuğu Kubernetes ile ilgili birimler.
  • bpftool cgroup list /sys/fs/cgroup/* — ilgili cgroup’a bağlı tüm programlar.
  • systemd-cgls /sys/fs/cgroup/* — control group içeriğini özyinelemeli göster.
  • systemd-cgtop — kaynak kullanımına göre en üstteki control group’lar.
  • tree -L 2 -d /sys/fs/cgroup/kubepods.slice — Pod’lara ait cgroup dizinleri.

Bir Pod’un CPU/bellek limiti cgroup dosyasına gerçekten yazıldı mı?

API nesnesinden node’a doğru inin. Önce node’u belirleyin, sonra spec’teki istenen kaynaklarla status’taki uygulanmış değerleri karşılaştırın (in-place resize bu ikisini geçici olarak ayrıştırabilir):

kubectl get pod <pod-name> -n <namespace> \
-o jsonpath='{.spec.nodeName}{"
"}'
kubectl get pod <pod-name> -n <namespace> \
-o jsonpath='{range.spec.containers[*]}{.name}{" spec\t"}{.resources}{"
"}{end}'
kubectl get pod <pod-name> -n <namespace> \
-o jsonpath='{range.status.containerStatuses[*]}{.name}{" status\t"}{.resources}{"
"}{end}'

Ardından ilgili node’da, root olarak, systemd cgroup sürücüsü ve cgroup v2 ile (bu parçacıklar jq da gerektiriyor). Container’ı kubelet etiketleriyle sabitleyin; container adı tek başına node üzerinde benzersiz değildir. Container çalışmıyorsa crictl ps -a kullanın:

CONTAINER_ID=$(crictl ps \
--label io.kubernetes.pod.namespace=<namespace> \
--label io.kubernetes.pod.name=<pod-name> \
--name <container-name> -q | head -n1)
# OCI görünümü (CRI protobuf alan adları değil)
crictl inspect "$CONTAINER_ID" | jq '.info.runtimeSpec.linux.resources'
# Bu container için kernel cgroup yolu
PID=$(crictl inspect "$CONTAINER_ID" | jq -r '.info.pid')
CGROUP="/sys/fs/cgroup$(awk -F: '$1=="0"{print $3}' /proc/$PID/cgroup)"
cat "$CGROUP/cpu.weight"   # request.cpu → shares → weight; limit değil
cat "$CGROUP/cpu.max"      # limit.cpu "quota period" biçiminde; sınırsız ise "max <period>"
cat "$CGROUP/memory.max"   # limit.memory; sınırsız ise "max"
# Pod düzeyi cgroup (parent slice), Pod düzeyi kaynaklar için
cat "$(dirname "$CGROUP")/cpu.max" "$(dirname "$CGROUP")/memory.max"
# MemoryQoS etkinken mevcut
cat "$CGROUP/memory.high" "$CGROUP/memory.min" "$CGROUP/memory.low"
SCOPE=$(basename "$CGROUP")
systemctl show "$SCOPE" \
-p CPUWeight -p CPUQuotaPerSecUSec -p CPUQuotaPeriodUSec -p MemoryMax

Önemli bir tuzak: runtime systemd sürücüsünü kullanıyorsa info.runtimeSpec.linux.cgroupsPath değerini dosya sistemi yolu sanmayın. O değer bir systemd unit yolu (slice:runtime:id), /sys/fs/cgroup altındaki bir dizin değil.

Katmanlar arası eşleme

  • Kubernetes:spec.containers[*].resources (istenen) ve status.containerStatuses[*].resources (in-place resize sonrası uygulanan). Pod düzeyi kaynaklar spec.resources ve üst pod slice’ında.
  • CRI (kubelet → runtime; bu protobuf adları cgroup v2’de bile v1 stilinde kalıyor): cpu_shares, cpu_quota, cpu_period, memory_limit_in_bytes ve Memory QoS için unified. crictl inspect bu adları göstermez; runtime’ın bunlardan türettiği OCI spec’i gösterir.
  • OCI spec:linux.resources.cpu.{shares,quota,period}, linux.resources.memory.limit ve linux.resources.unified. Runtime; shares, quota ve period değerlerini cgroup v2 dosyalarına dönüştürür. crun veya runc yükseltmesinden sonra shares→weight formülü değişebilir.
  • systemd scope:CPUWeight, CPUQuotaPerSecUSec, CPUQuotaPeriodUSec, MemoryMax. Sınırsız veya ayarlanmamış değerler çoğunlukla [not set] ya da infinity olarak görünür.
  • cgroupfs: container scope’unda cpu.weight (CPU request’ten; ayarlanmamış bir request yine de varsayılan 2 shares üretir), cpu.max ve memory.max. Memory QoS ayrıca memory.high, memory.min ve memory.low ekler.

Özetle ne yapmalı

Yeni bir Linux node havuzu kuruyorsanız doğrudan cgroup v2’yi tercih edin. Mevcut kümelerde ise sıralama basit: önce çekirdek ve runtime sürümlerini gereksinimlere göre doğrulayın, cgroup sürücüsünü eşitleyin, cgroup dosya sistemini doğrudan okuyan yardımcı yazılımları güncelleyin ve node’ları kademeli olarak v2’ye alın. v1.35 ve sonrasında varsayılan yapılandırmada geride kalan bir cgroup v1 node’u, kubelet başlatma aşamasında hata verecektir. Bu yazı yalnızca Kubernetes bileşenlerinin temel gereksinim ve yapılandırmasını kapsıyor; dağıtım düzeyinde cgroup dosya sistemini etkinleştirme adımları için işletim sisteminizin belgelerine ve resmî geçiş rehberine bakın.

Kaynaklar ve İleri Okuma

Bu yazı yapay zeka (büyük dil modelleri) ile hazırlanmış, insan editör tarafından incelenmiştir. İçerik üretim sürecimiz.
Aşkın KILIÇ

20+ yıl deneyimli Azure Solutions Architect. Microsoft sertifikalı bulut mimari ve DevOps danışmanı. Azure, yapay zekâ ve bulut teknolojileri üzerine Türkçe teknik içerikler üretiyor.

AZ-305AZ-104AZ-500AZ-400DP-203AI-102

Bu içerik işinize yaradı mı?

Benzer içerikleri kaçırmamak için YouTube ve GitHub hesaplarımı takip edin.

Haftalık Bülten

Her pazar özenle seçilmiş teknoloji yazıları doğrudan e-postanıza gelsin.

Bir yanıt yazın

E-posta adresiniz yayınlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir

✉

Haftalık Bülten

Azure, DevOps ve Yapay Zeka dünyasındaki en güncel içerikleri her hafta doğrudan e-postanıza alın.

Spam yok. İstediğiniz zaman iptal edebilirsiniz.
📱
Uygulamayı Yükle Ana ekrana ekle, çevrimdışı oku
Kategoriler
Ara
Paylaş
WhatsApp
İçindekiler
← GitHub Webhook IP Aralıkları: ...
→
📩

Gitmeden önce!

Her pazar özenle seçilmiş teknoloji yazıları ve AI haberleri doğrudan e-postanıza gelsin. Ücretsiz, spam yok.

🔒 Bilgileriniz güvende. İstediğiniz zaman ayrılabilirsiniz.

📬 Haftalık bülten: Teknoloji + AI haberleri
Beni Takip Et Yeni Azure / AI / DevOps yazılarını GitHub ve RSS üzerinden takip edin.