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 itibaren
failCgroupV1varsayılan olaraktrue. 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: falseayarlayabilir; 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.
MemoryQoSfeature gate’i etkinleştirildiğinde Burstable container’laramemory.highthrottling uygulanıyor. Eşik; request, limit vememoryThrottlingFactor(varsayılan0.9) üzerinden hesaplanıyor.memoryReservationPolicy: Nonevarsayılan değer;memory.minveyamemory.lowyazmıyor.memoryReservationPolicy: TieredReservation, Guaranteed Pod bellek isteklerinimemory.min‘e (sert koruma), Burstable Pod isteklerinimemory.low‘a (yumuşak koruma) eşliyor. BestEffort Pod’lar hiçbir koruma almıyor.- kubelet, node üzerindeki toplam
memory.minvememory.lowrezervasyonları için Alpha metrikleri yayınlıyor. - Kernel 5.9 veya sonrası öneriliyor. Daha eski çekirdeklerde
memory.highgeri 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?cgroup2fsdönmeli.systemctl list-units 'kube*' --type=sliceveya--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) vestatus.containerStatuses[*].resources(in-place resize sonrası uygulanan). Pod düzeyi kaynaklarspec.resourcesve ü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_bytesve Memory QoS içinunified.crictl inspectbu 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.limitvelinux.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.maxvememory.max. Memory QoS ayrıcamemory.high,memory.minvememory.lowekler.
Ö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
- The Shift to cgroup v2 in Kubernetes: What You Need to Know (kubernetes.io blog)
- Kubernetes 1.31: cgroup v1 desteğinin maintenance mode’a alınması
- Kubernetes belgeleri: cgroups kavramı ve cgroup v2’ye geçiş
- kubelet yapılandırma dosyası kullanımı
- Kubernetes deprecation politikası
- KEP-5573: cgroup v1 desteğinin kaldırılması
- system-validators v1.12.1 sürüm notları
- Linux kernel: cgroup v2 belgeleri
- Linux kernel: cgroup v1 belgeleri
- Pod QoS sınıfları ve cgroup v2 karşılıkları
- Node baskısı kaynaklı tahliye (node-pressure eviction)
- kubernetes/kubernetes#43916: active_file bellek hesaplaması
- cgroup v1 CPU Shares’ten v2 CPU Weight’e Yeni Dönüşüm
- Kubernetes 1.36 Ön İzleme: Neler Geliyor, Neler Gidiyor?




