OOMKilled Hatalarının Nedenleri ve Önlemleri
Kubernetes kümelerinde kaynak limitleri her konteyner için işlemci tüketimini sınırlar içinde tutan önemli bir mekanizmadır. Bu tanımlamalar sayesinde bir uygulama kümedeki diğer bileşenleri etkilemeden hizmet verebilir. Operasyon ekibi bu değerleri doğru tanımladığında atıl kaynaklar önlenir ve küme kararlılığı güçlenir. Limit tanımlanmayan pod node üzerindeki tüm boş kaynakları kullanabilir, bu da yan iş yüklerinde kesintilere yol açabilir. Gelişmiş ortamlarda limitler zorunlu kabul edilir. Doğru tasarım için önce uygulamanın tipik ve maksimum yük profili çıkarılmalıdır. Bu analiz metrik araçlarıyla yapıldığında sonuçlar daha isabetli olur. Ayrıca ad alanı düzeyinde ResourceQuota ve sınır aralığı nesneleriyle genel değerler atanabilir. Böylece ekipler kendilerine ait iş yükleri için öngörülebilir sınırlarla hareket eder. Sonuç olarak limit yönetimi, kapasite kontrolü ile güvenilirliği birlikte sağlayan sürekli bir çalışmadır.
Kubernetes'te requests ile limit değerleri arasındaki fark kaynak yönetiminin temelini oluşturur. Requests, zamanlayıcının (scheduler) bir konteyner için garanti ettiği minimum kaynak miktarıdır. Scheduler, node seçerken bu istek miktarlarına bakar ve yalnızca yeterli boş kapasiteye sahip node'lara yerleştirme yapar. Limits ise bir konteynerin tavanı üst sınırı belirler. CPU için bu sınır aşıldığında süreç kısılır, ancak sonlandırılmaz. Bellek için ise limit aşıldığında süreç OOMKilled durumuna düşerek öldürülür. Requests ile limitler aynı değere eşitlendiğinde konteyner Guaranteed QoS sınıfına girer. Farklı değerler tanımlandığında patlayabilir sınıf oluşur. Hiçbir sınır tanımlanmadığında BestEffort sınıfı söz konusu olur ve bu pod kaynak baskısında ilk çıkarılma adayı olur. Dolayısıyla hangi tür sınıfın seçileceğine iş yükünün önceliğine göre karar verilmeli. Önemli veritabanları için garantili sınıf, batch işler için Burstable sınıf uygun olabilir. Her iki değerin da anlaşılması maliyet ve performans dengesini sağlıklı kurmak için gereklidir.
CPU limitlerinin ayarlanması iş yükünün davranışına bağlı olarak yapılmalıdır. İşlemci birimi millicore cinsinden ifade edilir ve 1000m değeri tek bir core'a karşılık gelir. İlk olarak uygulamanın düşük yük ve yoğun trafik altındaki CPU kullanımı kaydedilmelidir. Prometheus gibi izleme sistemleriyle alınan metrikler p95 persentil değerleri üzerinden yorumlanır. Sınır değeri genellikle bu zirve kullanımın biraz üzerinde tutulur. Aşırı kısıtlayıcı bir limit yavaşlamaya ve bekleme sürelerinin artmasına neden olur. Gereksiz geniş bir limit ise küme kapasitesinin boşa kullanılmasına yol açar. Pek çok ekip CPU limitini tamamen kaldırıp yalnızca requests değerine dayanır. Bu yaklaşım boş kapasite kullanımı sağlasa da diğer iş yüklerinde sorunlu etkilere neden olabilir. Yük ortamlarında farklı limit seviyeleri denenerek en uygun nokta tespit edilmelidir. Bu aşamada üretime yakın trafik senaryoları kullanıldığında sonuçlar önemli ölçüde anlamlı olur. Son olarak limitler, servis sürümleri değiştikçe tekrar değerlendirilmelidir.
Bellek limitlerinin belirlenmesi CPU'ya kıyasla çok daha hassas bir konudur, çünkü bellek sıkıştırma yapılamaz bir kaynaktır. Limit aşıldığında kernel OOM Killer çalışır ve süreci sonlandırır. Bu nedenle RAM limiti konservatif ama isabetli ayarlanmalıdır. Hesaba başlamadan önce uygulamanın yığın ve yığın bellek kullanımı detaylı incelenmelidir. JVM tabanlı servislerde heap ayarı ile pod'un toplam RAM'i arasında makul bir boşluk bırakılmalıdır. Node.js ve Python uygulamalarında bellek sızıntıları zamanla limit aşımına yol açabilir. Bu yüzden uzun süreli izleme ile kullanım grafiği incelenmelidir. Küme içinde container_memory_working_set_bytes örneğin metrikler, fiili kullanımı isabetli gösterir. Sınır değeri çoğunlukla zirve kullanımın yüzde on beş üzerinde tutulur. Fakat gereğinden fazla büyük limitler düğüm belleğinin israf edilmesine neden olur. Üretim değişkenleri değiştikçe hesaplamanın yeniden yapılması önerilir.
Kaynak isteklerinin isabetli ayarlanması, küme zamanlamasının verimli çalışması için vazgeçilmezdir. İstek değeri gereğinden az tanımlandığında scheduler pod'u aşırı yoğun düğümlere yerleştirir, bu da performans sorunlarına yol açar. Çok yüksek tanımlandığında ise node'lar gerçekte kullanılmasa bile dolu görünür. Bu durum küme verimliliğini azaltır ve gereksiz bulut maliyeti doğurur. Sağlıklı bir ilk değer için geçmiş metrikler incelenmeli ve ortalama kullanım değerine yakınsak bir istek tanımlanmalıdır. Vertical Pod Autoscaler örneğin araçlar öneri sunabilir ve bu tavsiyeler başlangıç ayar için kullanılabilir. Yatay pod ölçekleyici ile beraber kullanılırken çakışmalara dikkat gösterilmelidir. Bunun yanında ad alanı seviyesinde sınır aralığı kurulduğunda eksik istekler otomatik atanabilir. Periyodik değerlendirme ile ayarlar uygulama gelişimine uyumlu tutulmalıdır.
Kubernetes kümelerinde kaynak sınırlarını doğru belirlemek için öncelikle QoS sınıflarını iyi anlamak gerekir. Bir pod Burstable sınıfına, tanımlanan request ve limit değerlerine göre atanır. Pod içindeki her container için request ve limit eşit tanımlanırsa pod kesin garantili kabul edilir ve bellek baskısı altında en son sonlandırılan grup olur. Yalnızca request tanımlanmış veya request ile limit farklı olan pod'lar esnek sınıfına girer ve kaynak fazlasını kullanabilir. Hiçbir request veya limit belirtilmeyen pod'lar en düşük öncelikli sınıfa düşer ve node üzerinde kaynak sıkıştığında ilk tahliye edilen adaylar arasında yer alır. Bu ayrım, kritik servisleri korumak için temel bir araçtır. Doğru sınıflandırma yapıldığında, yoğun yük altında bile önemli uygulamaların sorunsuz çalışması sağlanabilir. Üretim ortamında her iş yükünün önem derecesine göre QoS sınıfı bilinçli biçimde seçilmelidir. Aksi halde beklenmeyen tahliyeler ve performans düşüşleri sık rastlanan hale gelir. Ekipler bu sınıfları, ilgili manifestolarda açıkça tanımlayarak tutarlı bir davranış elde edebilir. Ayrıca node kapasitesinin bu sınıfların toplam talebini karşılayacak şekilde planlanması gerekir. Son olarak, QoS kararlarının izlenmesi için metrikler ve uyarılar yapılandırılmalı ve düzenli gözden geçirilmelidir.
LimitRange nesnesi, bir namespace içindeki container ve pod'lar için varsayılan request ve limit değerlerini tanımlamanın pratik bir yoludur. Geliştiriciler manifestolarında kaynak belirtmeyi unuttuğunda bile, LimitRange devreye girerek her container'a makul değerler atar. Böylece BestEffort sınıfında kalan pod sayısı azaltılabilir. Bu nesne ile minimum ve maksimum sınırlar da kesin kılınabilir. Örneğin bir container'ın belleği belirli bir üst sınırı aşarsa, API sunucusu isteği engeller. Bu yaklaşım, aşırı kaynak tahsisini önler ve küme genelinde adil dağılım sağlar. LimitRange, request ile limit oranını da kısıtlayabilir ve böylece aşırı taahhüt sorununu azaltır. Varsayılan değerler seçilirken uygulamaların tipik kullanım profilleri dikkate alınmalıdır. Çok düşük değerler sık OOMKill olaylarına, çok yüksek değerler ise kaynak israfına yol açar. Bu nedenle ekipler, LimitRange değerlerini periyodik olarak güncellemeli ve uygulamaların gerçek davranışıyla karşılaştırmalıdır. Ayrıca farklı ortamlar için, örneğin geliştirme ve üretim namespace'leri için, ayrı LimitRange tanımları oluşturulabilir. Bu esneklik, kaynak yönetimini hem kolaylaştırır hem de tutarlılığı destekler.
ResourceQuota, bir namespace'in tüketebileceği toplam kaynak miktarını sınırlandırarak çok kiracılı kümelerde adaletli bir paylaşım sağlar. Bu nesne ile CPU ve bellek toplamları, depolama talepleri ve hatta pod, service veya secret gibi nesne sayıları kısıtlanabilir. Bir namespace kotası dolduğunda, yeni kaynak talepleri API sunucusu tarafından reddedilir. Bu mekanizma, bir ekibin tüm kümeyi tüketmesini engeller. ResourceQuota kullanırken, quota kapsamındaki her pod'un request ve limit değerlerini açıkça belirtmesi gerekir, aksi halde talep kabul edilmez. Bu nedenle LimitRange ile birlikte kullanmak çoğu zaman ideal yaklaşımdır. Kota değerleri belirlenirken geçmiş tüketim verileri ve büyüme tahminleri esas alınmalıdır. Fazla sıkı kotalar dağıtımları durdurabilir, fazla gevşek kotalar ise amacını yitirir. Ayrıca kota kullanım oranlarının düzenli izlenmesi, sorunların erken fark edilmesini sağlar. Kurumsal ortamlarda her ekibin kotası, iş birimi bütçesiyle uyumlu hale getirilebilir.
Vertical Pod Autoscaler, pod'ların geçmiş kullanım verilerine dayanarak request ve limit değerlerini kendiliğinden önermesini veya uygulamasını sağlayan bir bileşendir. VPA, öneri modunda çalıştığında yalnızca tavsiyeler üretir ve bunları kayıt altına alır, böylece ekipler değişiklikleri kendi kontrolüne göre uygulayabilir. Auto moduna geçildiğinde ise VPA, pod'ları yeniden oluşturarak değerleri doğrudan günceller. Bu yaklaşım, manuel ayarlama yükünü önemli ölçüde azaltır. Ancak pod yeniden başlatmalarının kesinti yaratabileceği unutulmamalıdır. Bu nedenle kritik iş yüklerinde önce öneri modu ile gözlem yapılması önerilir. VPA ile Horizontal Pod Autoscaler birlikte kullanılacaksa, aynı metrik üzerinde çakışma olmamasına özen gösterilmelidir. VPA önerilerinin, uygulamanın ölçeklenme davranışı ile uyumlu olup olmadığı değerlendirilmelidir. Öneri değerlerinin minimum ve maksimum sınırlarını belirlemek, aşırı sapmaları engeller. Düzenli olarak önerileri inceleyen bir süreç kurmak, uzun vadede en verimli sonuçları getirir.
Gerçek kullanım verisine dayalı kaynak ayarı, tahminlere değil ölçümlere bağlı en güvenilir yöntemdir. Prometheus gibi araçlarla toplanan CPU ve bellek metrikleri, uygulamanın gerçek profilini ortaya koyar. Bu veriler, belirli bir zaman aralığında yüzdelik değerler, özellikle p95 ve p99, olarak analiz edildiğinde anlamlı sonuçlar verir. Request değeri genellikle ortalama kullanıma yakın, limit değeri ise tepe yüklere yeterli seçilmelidir. Bellek limitlerinin, CPU limitlerine göre daha dikkatli ayarlanması gerekir, çünkü bellek aşımı OOMKill ile sonuçlanır. CPU limitlerinin ise bazı durumlarda gereksiz gecikmelere yol açabileceği tartışılmaktadır. Bu nedenle her iş yükü için ayrı bir değerlendirme gerekir. Ölçüm süreci, farklı trafik dönemlerini, örneğin kampanya veya ay sonu yoğunluğunu, kapsayacak biçimde uzatılmalıdır. Elde edilen değerler, deployment sonrası davranışla karşılaştırılarak doğrulanmalıdır. Sürekli iyileştirme döngüsü kurulduğunda, kaynak kullanımı hem maliyet hem de güvenilirlik açısından optimize hale gelir.
Kümelenmiş uygulama CPU ve bellek sınırları ne şekilde ayarlanır
K8s cluster ortamlarında pod başına kotaları isabetli tanımlamak performans bakımından önemli bir görev taşır. Requests ile limits parametreleri arasında farklılık iyi bilinmeden hazırlanan konfigürasyonlar kesintiye yol açar. Kube-scheduler modülü istek rakamlarına bağlı olarak kapsül dağıtımı gerçekleştirir. Sınırlar ise yürütme sürecinde uygulanır. Başlangıç şeklinde tüm uygulama için test edilmiş değerler hesaplamak, Prometheus örneğin yöntemlerle fiili tüketim bilgilerini incelemek en sağlıklı yoldur.
Sıkça rastlanan yanlışlar hangileridir
Kaynak hususunda en ortaya çıkan hatalardan biri sınırların baştan yapılmamasıdır. Bu şekilde bir tür kümede tek bir pod tüm düğüm işlemcisini ele geçirebilir ile komşu bileşenleri etkileyebilir. Bir diğer sık yanılgı de istek tanımlarını gerektiğinden az ayarlamaktır. Bu durumda ortamda iş yükü node'a fazla yerleştirilir, bu da disk tıkanıklığı hem de bellek yetersizliği vakalarına yol açabilir. Bir başka yanlış öte yandan her pod'lara tek tip değerleri tanımlamaktır. Her bir uygulamanın farklı yük profili olduğu göz ardı edilmemelidir.
Profesyonel ipuçları ile kaynak ayarı
Deneyimli operatörler sıklıkla kaynak hususunda aşağıdaki yöntemi uygular: Başlangıçta yük ölçümleri uygulanır ile toplanan sonuçlar temelinde istek miktarları tipik tüketimin hafifçe yukarısına yerleştirilir. Sınırlar değerleri ise maksimum yükü karşılayacak düzeyde ayarlanmalıdır. CPU için tavan uygulamak kimi zaman gereksiz sınırlamalara sebep doğurabildiğinden temkinli davranılmalıdır. Dikey ölçekleme aracı hem de Horizontal Pod Autoscaler örneğin araçlar bununla birlikte bu süreçte değerlerin uzun vadede dengeli duruma ulaşmasında faydalı olabilir.
Kaynak bütçesi ve masraf planlaması
Kubernetes kümelerinde sınır ayarları bizzat bulut maliyetine tesir eder. Aşırı büyük kaynak talebi tanımlanmış bir çeşit küme kullanılmadan bekleyen kullanılmayan güce para yapılmasına neden kapı getirir. Bu olgu sebeple birim bütçe beklentilerini somut surette belirlemeli ile kaynak kararlarını bu çerçevede planlarla tutarlı biçime getirmelidir. Harcama kontrol araçları ve isim alanı ölçeğinde analiz yapmak bunun yanında hangi uygulama iş yükünün ne kadar güç ayırdığını belirlemeyi sağlar.
Periyodik yük ile zamanlama yaklaşımları
Çeşitli kurum içi sistem takvim ilerledikçe düzensiz bir tür trafik eğilimine sahiptir. Kampanya zamanları, faturalama dönemleri ile dönemsel olaylar süresince kota beklentileri önceden planlanarak hesaplanmalıdır. Böyle dönemler bakımından sabit sınırlar yerine programlanmış büyütme yaklaşımları tercih etmek maliyeti dikkat çekici düzeyde azaltabilir. Zamanlanmış görev iş akışları ile eşdeğer mekanizmalar vasıtasıyla gece vakitlerinde az güce dönüş sağlamak bunun yanında hem verim hem de bütçe açısından önemli getiriler doğurabilir.
Sık karşılaşılan merak konuları hem de açıklamaları
Kubernetes kaynak limiti alanında başlıca merak yöneltilen meselelerden ilki requests ile sınırlar tanımlarının tek olup seçilmeyeceğidir. Söz konusu yöntem Garantili QoS grubunu yaratır, ama kapasite uyumluluğunu önemli ölçüde sınırlayabilir. Bir sık soru de limit aşıldığında hangi tür yaşandığıdır. Bellek limiti aşıldığında servis genellikle OOMKilled hâline geçer, İşlemci tavanı geçildiğinde oysa servis yavaşlatılır ancak çoğu zaman durdurulmaz. Bu fark bu yüzden bellek alanı kotalarının itinayla belirlenmesi şarttır.