background

Kubernetes’te Kaynak Yönetimi

Kubernetes’te Kaynak Yönetimi

Kubernetes container dünyası için de-facto haline gelmiş open source bir yönetim platformu. Birçok şirket tüm uygulamalarını on-premise, cloud veya hybrid cloud üzerinde koşan Kubernetes cluster’larında çalıştırıyor.

Birden fazla uygulamayı aynı Kubernetes cluster’ı üzerinde çalıştırıyorsanız bu uygulamaların birbirlerini etkilemediklerinden, cluster’ın kaynaklarını doğru bir şekilde kullandıklarından emin olmak zorundasınız. Aksi halde bir uygulamada yaşanacak sorun diğer tüm uygulamaları etkileyebilir. Bu yazıda Kubernetes üzerinde koşan pod ve container’ların memory, CPU kullanımlarını nasıl yönetebileceğinizi anlatmaya çalışacağım.

Kubernetes’te container’ların kaynak kullanım sınırları request ve limitlerle belirlenir.

Request

Request, bir container’ın kubernetes cluster üzerinde ayağa kalkması için ihtiyacı olan minimum kaynağı belirler. Örneğin, 3 node’lu bir cluster düşünelim. Mevcut kullanımlardan dolayı node’larda kullanılabilir memory miktarlarının aşağıdaki gibi olduğunu düşünelim:

Node1: 1Gi

Node2: 2Gi

Node2: 2Gi

Eğer biz pod’un memory request’ini 3Gi olarak belirlersek pod yalnızca Node3'te çalışacaktır. Eğer request’i 5Gi belirlersek pod hiçbir node’da ayağa kalkmayacak ve deployment’ınız Pending durumunda kalacaktır.

Limit

Limit ise bir container’ın kullanacağı maksimum kaynak sınırını belirler. Örnek olarak bir pod’unuzun memory limit’ini 4Gi olarak belirlediniz ve yük altında bu uygulamanın memory kullanımı 4Gi’e ulaştı diyelim. Kubelet kısa süre içinde pod’unuzu OOMKilled hatasıyla restart edecektir.

Kubernetes’te koşacak uygulamalarınız için default bir request veya limit tanımlı değildir. Bu request ve limitleri sizin tanımlamanız beklenir. Best practice olarak, memory limit’i tanımlanmayan hiçbir uygulamanın cluster üzerinde koşmaması önerilir. Aksi halde bir memory leak veya aşırı yük durumunda tüm cluster’ın memory’sini tüketebilirsiniz ve tüm uygulamalarınız cevap veremez hale gelir.

Peki request ve limit’leri nasıl tanımlarız? Örnek üzerinden inceleyelim:

Yukarıdaki yaml’a baktığınızda ilk fark edeceğiniz şeylerden biri, request ve limitlerin pod’lara değil, container’lara tanımlandığıdır. Aynı pod’un içindeki container’ların farklı limit ve request’leri olabilir. Fakat pod’un request ve limitlerini de, içerdiği container’ların request ve limitlerinin toplamı gibi düşünebiliriz. Limit değerleri requestlere eşit veya request değerlerinden büyük olmak zorundadır. Eğer limiti request’ten küçük tanımlamaya çalışırsanız Kubernetes o pod’u yaratmanıza izin vermez.

Kubernetes üzerinde limit ve request tanımlamak bu kadar kolay. Peki birçok yazılımcının çalıştığı büyük bir cluster’da request ve limitlerin tanımlandığını nasıl garanti ederiz ve sınırlarını nasıl belirleriz? Bu soruların yanıtlarını da Kubernetes’in ResourceQuota ve LimitRange tanımlarında bulabiliriz.

ResourceQuota

Namespace bazında kota uygulamak için kullanılan bir resource tipidir. ResourceQuota ile bir namespace’te tanımlanacak memory, CPU limit ve requestlerin toplamının sınırı belirlenebilir. Bununla beraber, bir namespace’te maksimum kaç pod, kaç service, kaç configmap, kaç PVC vb. tanımlanacağı belirlenebilir. Fakat konumuz cluster kaynakları olduğu için bu yazıda o kısıtlamalara yer vermeyeceğiz.

Namespace bazında kota tanımları için aşağıdaki yaml’ı inceleyelim:

Bu basit örnek namespace için bazı kısıtlar getiriyor. Örneğin bu kota tanımlandıktan sonra o namespace içinde CPU ve memory için request ve limit tanımları olmayan bir pod ayağa kalkamaz. Podların toplam CPU requestleri toplamı 1'i, CPU limitleri toplamı 2'yi geçemez. Toplam memory requestleri 1Gi’yi, toplam memory limit’leri 2Gi’yi geçemez.

XYZ isimli bir uygulamanız olduğunu ve bu uygulamanın deployment yaml’ına yanlışlıkla fazla fazla memory request’i yazıldığını ve bu container’ların — uygulama çok memory kullanmasa bile — cluster’daki memory’nin çoğunu rezerve ettiğini düşünün. Cluster’daki diğer uygulamalar ayağa kalkamayacak veya ayaktaki uygulamalar OOMKilled hatası almaya başlayacak. Bunu engellemek için ResourceQuota yardımıyla namespace bazında kullanılacak maksimum request ve limitleri belirleyebilirsiniz.

Tekrar altını çizmek isterim ki, ResourceQuota kullanılan memory veya CPU ile ilgilenmez, tanımlanan toplam limit ve requestlerle ilgilenir. Örneğin, bir namespace’teki anlık memory kullanımı çok düşük olabilir. Dolayısıyla yeni pod’unuza atanacak yeterli memory bulunabilir. Fakat namespace’teki pod’ların memory limit ve requestlerinin toplamları yüksekse ve yeni pod’unuzla birlikte ResourceQuota’da tanımladığınız değerleri aşacaksa pod’unuz ayağa kalkmaz.

LimitRange

LimitRange de ResourceQuota gibi namespace bazında tanımlanan request ve limit değerleriyle ilgilenir. Fakat ResourceQuota tanımlanan toplam değerlere bakarken, LimitRange container (veya pod) başına tanımlanabilecek max ve min değerlerle ilgilenir.

Ayrıca, request ve limit tanımlanmayan container’lara default request ve limit tanımlamak için de kullanılır. Örnek üzerinden gidelim:

Yukarıdaki tanım bize birkaç şey söylüyor. Type container olarak seçildiği için bu limitRange’in container bazında kontrol yaptığını anlayabiliyoruz. Max ve Min değerler sırasıyla container’ların limit ve request sınırlarını belirliyor. Yani örneğin siz bir pod yaratmak istediniz ve pod içindeki container’ınıza 100m’den daha az bir CPU request’ini tanımlamak istediniz diyelim. Min CPU değeri 100m tanımlandığı için bu pod’unuz ayağa kalkmayacak demektir.

ResourceQuota’da örneğini verdiğimix XYZ uygulamasını tekrar aklımıza getirelim. Uygulamanın memory limiti fazla fazla yazıldı. Fakat biz LimitRange’de container’a tanımlanacak max limit’i belirlediğimiz için pod ayağa kalkmayacak ve cluster’daki diğer uygulamaları korumuş olacağız.

ResourceQuota gibi, LimitRange de kullanılan anlık değerlerle değil tanımlanan limit ve requestlerle ilgilenir.

ResourceQuota gibi, LimitRange de kullanılan anlık değerlerle değil tanımlanan limit ve requestlerle ilgilenir.

TL;DR

Kubernetes cluster’ınızda uygulamalarınızın kontrolsüz bir şekilde tüm kaynakları tüketip cluster genelinde sorun oluşturmasını istemezsiniz. Bunun için container’larınıza request ve limit değerleri tanımlayarak kullanılacak minimum ve maximum değerleri kontrol edebilirsiniz. Cluster’ınız büyükse ve namespace’ler için hem toplam hem de container bazında policy’ler set etmek istiyorsanız ResourceQuota ve LimitRange kullanarak uygulamalarınızın kullandığı kaynakları merkezi bir şekilde kontrol edebilirsiniz.

Nasıl yardımcı olabiliriz?