Takip et

Kubernetes İleri Seviye Zamanlama: Gelişmiş Pod Dağıtımı ve Optimizasyon Sırları

Kubernetes İleri Seviye Zamanlama: Gelişmiş Pod Dağıtımı ve Optimizasyon Sırları Kubernetes, dağıtık sistemlerin yönetiminde devrim yaratan bir…

Kubernetes İleri Seviye Zamanlama: Gelişmiş Pod Dağıtımı ve Optimizasyon Sırları

Kubernetes, dağıtık sistemlerin yönetiminde devrim yaratan bir platformdur. Temel işlevlerinden biri olan pod zamanlama (scheduling), uygulamaların küme içindeki düğümlere akıllıca yerleştirilmesini sağlar. Ancak varsayılan zamanlayıcı, her senaryo için yeterli olmayabilir. Bu makalede, Kubernetes’in ileri seviye zamanlama yeteneklerini, yani “gizli cevherlerini” keşfederek, uygulamalarınız için daha sofistike ve optimize edilmiş dağıtım stratejileri oluşturmayı öğreneceksiniz.

Node Affinity ve Anti-Affinity: Pod Yerleşimini Hassaslaştırmak

Kubernetes’te podların belirli düğümlere yerleştirilmesi veya belirli düğümlerden uzak tutulması, Node Affinity ve Anti-Affinity kuralları ile sağlanır. Bu kurallar, uygulamanızın performans, güvenlik veya maliyet gereksinimlerine göre düğüm seçimini optimize etmenize olanak tanır.

requiredDuringSchedulingIgnoredDuringExecution

Bu kural, pod’un belirli etiketlere sahip bir düğüme yerleştirilmesini *zorunlu* kılar. Eğer kümede bu koşulu sağlayan bir düğüm yoksa, pod zamanlanamaz ve beklemede kalır. Kural bir kez uygulandıktan sonra, düğümün etiketleri değişse bile pod’un yerleşimi etkilenmez.


apiVersion: v1
kind: Pod
metadata:
  name: my-app-required
spec:
  containers:
  - name: my-container
    image: nginx
  affinity:
    nodeAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:
        nodeSelectorTerms:
        - matchExpressions:
          - key: disktype
            operator: In
            values:
            - ssd

preferredDuringSchedulingIgnoredDuringExecution

Bu kural, pod'un belirli etiketlere sahip bir düğüme yerleştirilmesini *tercih eder*, ancak zorunlu kılmaz. Eğer tercih edilen koşulu sağlayan bir düğüm yoksa, pod yine de başka bir düğüme yerleştirilebilir. Bu, esneklik sağlarken belirli bir düğüm türünü hedeflemek istediğiniz durumlarda kullanışlıdır.


apiVersion: v1
kind: Pod
metadata:
  name: my-app-preferred
spec:
  containers:
  - name: my-container
    image: nginx
  affinity:
    nodeAffinity:
      preferredDuringSchedulingIgnoredDuringExecution:
      - weight: 100
        preference:
          matchExpressions:
          - key: environment
            operator: In
            values:
            - production

Kullanım Senaryoları ve Örnekler

* Donanım Spesifikasyonu: Yüksek performanslı GPU'lara sahip düğümlere sadece makine öğrenimi iş yüklerini yerleştirmek.
* Lisanslama Kısıtlamaları: Belirli yazılımların sadece lisanslı düğümlerde çalışmasını sağlamak.
* Maliyet Optimizasyonu: Geliştirme ortamlarını daha ucuz spot instancelara, üretim ortamlarını ise kararlı on-demand instancelara yönlendirmek.

Taints ve Tolerations: Düğümleri Özel Amaçlar İçin Ayırmak

Taints (leke) ve Tolerations (tolerans), Kubernetes'te düğümleri belirli podlardan "uzak tutmak" veya sadece belirli podların o düğümlerde çalışmasına izin vermek için kullanılan güçlü mekanizmalardır. Bir düğüme taint uygulandığında, o düğümde sadece ilgili toleransa sahip podlar zamanlanabilir.

Taint Türleri ve Uygulama

Bir taint, key=value:effect şeklinde tanımlanır. effect parametresi, pod'un düğüme nasıl tepki vereceğini belirtir:
* NoSchedule: Toleransı olmayan podlar düğüme zamanlanamaz.
* PreferNoSchedule: Toleransı olmayan podların düğüme zamanlanmaması tercih edilir, ancak zorunlu değildir.
* NoExecute: Toleransı olmayan podlar düğüme zamanlanamaz ve halihazırda düğümde çalışan toleransı olmayan podlar tahliye edilir.

Bir düğüme taint eklemek için kubectl taint komutu kullanılır:


kubectl taint nodes node1 key1=value1:NoSchedule

Toleration Tanımlama

Bir pod'un belirli bir taint'e tolerans göstermesi için pod tanımına tolerations alanı eklenir.


apiVersion: v1
kind: Pod
metadata:
  name: my-app-tolerated
spec:
  containers:
  - name: my-container
    image: nginx
  tolerations:
  - key: "key1"
    operator: "Equal"
    value: "value1"
    effect: "NoSchedule"

Pratik Kullanım Alanları

* Ayrılmış Düğümler: Belirli bir ekibe veya kritik uygulamalara özel düğümler ayırmak. Örneğin, "database-node" olarak işaretlenmiş bir düğümde sadece veritabanı podlarının çalışmasını sağlamak.
* Düğüm Bakımı: Bir düğümü bakıma alırken yeni podların o düğüme zamanlanmasını engellemek veya mevcut podları tahliye etmek.
* Karma İş Yükleri: GPU'lu düğümlerde sadece GPU gerektiren iş yüklerinin çalışmasını sağlamak, diğer podların bu pahalı kaynakları kullanmasını engellemek.

Pod Affinity ve Anti-Affinity: Podlar Arası İlişkileri Yönetmek

Node Affinity, podları düğümlerle ilişkilendirirken, Pod Affinity ve Anti-Affinity kuralları podları *birbirleriyle* ilişkilendirir. Bu sayede, uygulamalarınızın bileşenlerini aynı düğümde veya farklı düğümlerde çalışmaya zorlayabilirsiniz.

Pod Affinity ile Birlikte Çalışma

Pod Affinity, belirli etiketlere sahip podların aynı düğümde çalışmasını sağlar. Bu, yüksek bant genişliği gerektiren veya düşük gecikme süresiyle iletişim kurması gereken uygulama bileşenleri için idealdir. Örneğin, bir önbellek servisi ile bu önbelleği kullanan bir mikroservisi aynı düğümde tutmak.


apiVersion: v1
kind: Pod
metadata:
  name: web-app
spec:
  containers:
  - name: web-container
    image: webapp:1.0
  affinity:
    podAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:
      - labelSelector:
          matchLabels:
            app: cache-service
        topologyKey: "kubernetes.io/hostname"


Yukarıdaki örnekte, web-app pod'u, app: cache-service etiketine sahip bir pod'un çalıştığı bir düğüme yerleştirilmek zorundadır. topologyKey: "kubernetes.io/hostname" ifadesi, bu kuralın düğüm bazında uygulanacağını belirtir.

Pod Anti-Affinity ile Ayrıştırma

Pod Anti-Affinity, belirli etiketlere sahip podların *farklı* düğümlerde çalışmasını sağlar. Bu, yüksek erişilebilirlik ve hata toleransı için kritik öneme sahiptir. Aynı uygulamanın replikalarını farklı düğümlere dağıtarak tek bir düğüm arızasının tüm uygulamayı etkilemesini önleyebilirsiniz.


apiVersion: v1
kind: Pod
metadata:
  name: my-app-replica-1
spec:
  containers:
  - name: my-container
    image: myapp:1.0
  affinity:
    podAntiAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:
      - labelSelector:
          matchLabels:
            app: my-app
        topologyKey: "kubernetes.io/hostname"


Bu örnek, app: my-app etiketine sahip başka bir pod'un çalıştığı bir düğüme my-app-replica-1 pod'unun yerleştirilmesini engeller. Böylece, my-app uygulamasının tüm replikaları farklı düğümlerde dağıtılır.

Uygulama Örnekleri

* Yüksek Erişilebilirlik: Bir veritabanı kümesinin replikalarını farklı düğümlere dağıtarak, bir düğüm arızası durumunda servisin kesintiye uğramamasını sağlamak.
* Performans Optimizasyonu: Bir mikroservis ile onun bağımlı olduğu bir mesaj kuyruğu servisini aynı düğümde çalıştırarak ağ gecikmesini azaltmak.
* Kaynak İzolasyonu: Yoğun kaynak kullanan podların farklı düğümlere dağıtılmasını sağlayarak düğüm aşırı yüklenmesini önlemek.

Topology Spread Constraints: Yüksek Erişilebilirlik ve Dağıtımı Sağlamak

Topology Spread Constraints, podların küme içindeki farklı topoloji alanlarına (bölgeler, bölgeler, düğümler vb.) dengeli bir şekilde dağıtılmasını sağlayan güçlü bir zamanlama özelliğidir. Bu, uygulamanızın hata toleransını artırır ve kaynak kullanımını optimize eder.

Constraint Tanımlama

Bir topologySpreadConstraints objesi, podların nasıl dağıtılacağını tanımlar. Önemli parametreleri şunlardır:
* maxSkew: Hedef topoloji alanında izin verilen maksimum dengesizlik.
* topologyKey: Podların dağıtılacağı topoloji alanı (örneğin, kubernetes.io/hostname, topology.kubernetes.io/zone).
* whenUnsatisfiable: Kısıtlamanın karşılanamadığı durumda ne yapılacağı (DoNotSchedule veya ScheduleAnyway).
* labelSelector: Dağıtılacak podları seçmek için kullanılan etiket seçici.


apiVersion: v1
kind: Pod
metadata:
  name: my-app-pod
  labels:
    app: my-app
spec:
  containers:
  - name: my-container
    image: myapp:1.0
  topologySpreadConstraints:
  - maxSkew: 1
    topologyKey: kubernetes.io/hostname
    whenUnsatisfiable: DoNotSchedule
    labelSelector:
      matchLabels:
        app: my-app
  - maxSkew: 1
    topologyKey: topology.kubernetes.io/zone
    whenUnsatisfiable: DoNotSchedule
    labelSelector:
      matchLabels:
        app: my-app


Bu örnek, my-app etiketine sahip podların hem düğüm bazında (kubernetes.io/hostname) hem de bölge bazında (topology.kubernetes.io/zone) dengeli dağıtılmasını sağlar. maxSkew: 1 ile, herhangi bir topoloji alanındaki pod sayısı farkının en fazla 1 olabileceği belirtilir.

maxSkew ve whenUnsatisfiable Parametreleri

* maxSkew: Bu değer, bir topoloji alanındaki pod sayısı ile diğer topoloji alanlarındaki pod sayısı arasındaki maksimum farkı belirler. Örneğin, maxSkew: 1 ise, bir bölgedeki pod sayısı diğer bir bölgedeki pod sayısından en fazla 1 fazla olabilir.
* whenUnsatisfiable:
* DoNotSchedule: Eğer kısıtlama karşılanamıyorsa, pod zamanlanmaz. Bu, daha katı bir dağıtım politikası sağlar.
* ScheduleAnyway: Eğer kısıtlama karşılanamıyorsa bile pod zamanlanır. Bu, esneklik sağlar ancak dağıtım dengesiz olabilir.

Farklı Topoloji Alanlarında Dağıtım

Topology Spread Constraints, sadece düğüm veya bölge bazında değil, aynı zamanda özel etiketlerle tanımlanmış herhangi bir topoloji alanı üzerinde de çalışabilir. Örneğin, bir küme içinde farklı raf (rack) etiketleri tanımlayarak podları fiziksel raflara göre dağıtabilirsiniz. Bu, bir raf arızası durumunda uygulamanın etkilenme riskini azaltır.

Priority ve Preemption: Kritik İş Yüklerine Öncelik Vermek

Kubernetes kümelerinde kaynaklar sınırlı olduğunda, hangi podların daha önemli olduğuna karar vermek kritik hale gelir. Priority (öncelik) ve Preemption (ön alım) mekanizmaları, kritik iş yüklerinin her zaman çalışmasını sağlamak için podlara öncelik atamanıza ve daha az önemli podları tahliye etmenize olanak tanır.

PriorityClass Oluşturma

PriorityClass, podlara atanabilecek bir öncelik seviyesi tanımlayan küme çapında bir nesnedir. Yüksek bir value daha yüksek bir önceliği temsil eder.


apiVersion: scheduling.k8s.io/v1
kind: PriorityClass
metadata:
  name: high-priority
value: 1000000
globalDefault: false
description: "Bu PriorityClass, kritik servisler için kullanılır."
---
apiVersion: scheduling.k8s.io/v1
kind: PriorityClass
metadata:
  name: low-priority
value: 100
globalDefault: false
description: "Bu PriorityClass, arka plan işleri için kullanılır."

Pod'lara Öncelik Atama

Oluşturulan PriorityClass'ları pod tanımınıza priorityClassName alanı ekleyerek podlara atayabilirsiniz.


apiVersion: v1
kind: Pod
metadata:
  name: critical-app
spec:
  containers:
  - name: my-critical-container
    image: critical-app:1.0
  priorityClassName: high-priority


high-priority sınıfına sahip bir pod, low-priority sınıfına sahip bir poddan daha önce zamanlanmaya çalışılacak ve gerektiğinde onu tahliye edebilecektir.

Preemption Mekanizması

Eğer yüksek öncelikli bir pod zamanlanmaya çalışılırken kümede yeterli kaynak yoksa, Kubernetes zamanlayıcısı daha düşük öncelikli podları tahliye (preempt) etmeye çalışır. Zamanlayıcı, yeni podun sığabileceği bir düğüm bulmak için en az sayıda düşük öncelikli podu tahliye etmeye çalışır. Bu, kritik servislerin her zaman çalışır durumda kalmasını garanti eder. Preemption, genellikle düğümde çalışan podların önceliğine göre yapılır.

Özel Zamanlayıcılar ve Genişleticiler: Zamanlama Mantığını Kişiselleştirmek

Kubernetes'in varsayılan zamanlayıcısı birçok senaryo için yeterli olsa da, bazen çok özel veya karmaşık zamanlama gereksinimleri ortaya çıkabilir. Bu durumlarda, özel zamanlayıcılar veya zamanlayıcı genişleticileri (scheduler extenders) devreye girer.

Neden Özel Zamanlayıcıya İhtiyaç Duyarız?

* Özel Donanım Entegrasyonu: GPU'lar, FPGA'lar veya diğer özel donanımlar için karmaşık kaynak yönetimi ve zamanlama algoritmaları.
* Maliyet Optimizasyonu: Farklı bulut sağlayıcılarının fiyatlandırma modellerine göre podları en uygun maliyetli düğümlere yerleştirmek.
* Gelişmiş Kaynak Yönetimi: Küme dışındaki kaynakları (örneğin, dış veritabanları veya lisans sunucuları) dikkate alarak zamanlama yapmak.
* Gelişmiş Topoloji Farkındalığı: Varsayılan topologyKey'lerin ötesinde, özel topoloji kuralları uygulamak.
* Veri Yerelliği: Verilerin bulunduğu depolama birimlerine yakın düğümlere podları yerleştirmek.

Scheduler Extender'lar

Scheduler Extender'lar, Kubernetes'in varsayılan zamanlayıcısını değiştirmeden, zamanlama sürecine harici bir mantık eklemenin bir yoludur. Zamanlayıcı, bir podu zamanlamadan önce veya sonra, harici bir HTTP servisine (extender) bir istek gönderir. Extender, kendi filtreleme, önceliklendirme veya bağlama mantığını uygulayabilir ve zamanlayıcıya geri bildirimde bulunabilir.


apiVersion: kubescheduler.config.k8s.io/v1beta2
kind: KubeSchedulerConfiguration
extenders:
  - urlPrefix: "http://my-scheduler-extender:8080"
    filterVerb: "filter"
    prioritizeVerb: "prioritize"
    weight: 1
    enableHttps: false


Bu konfigürasyon, zamanlayıcının belirli bir URL'deki harici bir servisi filtreleme ve önceliklendirme adımlarında kullanmasını sağlar.

Kendi Zamanlayıcınızı Geliştirmek

En esnek seçenek, sıfırdan kendi Kubernetes zamanlayıcınızı geliştirmektir. Bu, Kubernetes API'si ile etkileşime giren ve podları düğümlere atayan özel bir kontrolör yazmak anlamına gelir. Kendi zamanlayıcınızı kullanmak için pod tanımınıza schedulerName alanını eklersiniz.


apiVersion: v1
kind: Pod
metadata:
  name: my-custom-scheduled-pod
spec:
  schedulerName: my-custom-scheduler
  containers:
  - name: my-container
    image: nginx


Kendi zamanlayıcınızı geliştirmek, yüksek düzeyde kontrol ve özelleştirme sağlar, ancak aynı zamanda daha fazla geliştirme ve bakım çabası gerektirir.

Descheduler: Küme Kaynaklarını Optimize Etmek

Kubernetes zamanlayıcısı, podları düğümlere yerleştirme konusunda mükemmeldir, ancak podlar bir kez yerleştirildikten sonra genellikle orada kalırlar. Düğüm durumu değiştikçe (örneğin, yeni düğümler eklendiğinde, kaynak kullanımı dengesizleştiğinde), küme optimum dağıtımını kaybedebilir. Descheduler, bu sorunu çözmek için tasarlanmış bir araçtır.

Descheduler Nedir ve Nasıl Çalışır?

Descheduler, halihazırda çalışan podları analiz eder ve belirli kurallara göre optimum olmayan yerleşimleri tespit eder. Ardından, bu podları tahliye ederek (evict ederek) Kubernetes zamanlayıcısının onları daha uygun bir düğüme yeniden zamanlamasını sağlar. Descheduler, zamanlayıcı gibi sürekli çalışmak yerine, genellikle periyodik olarak çalıştırılan bir kontrolördür.

Descheduler, genellikle bir Deployment olarak kümede çalışır ve belirli aralıklarla tetiklenir.

Stratejiler ve Konfigürasyon

Descheduler, farklı tahliye stratejilerini destekler:
* RemoveDuplicates: Aynı düğümde birden fazla replikası olan podları tahliye eder.
* LowNodeUtilization: Düşük kaynak kullanımına sahip düğümlerdeki podları tahliye ederek bu düğümlerin boşaltılmasını ve küçültülmesini sağlar.
* HighNodeUtilization: Yüksek kaynak kullanımına sahip düğümlerdeki podları tahliye ederek yükü dengelemeye çalışır.
* PodLifeTime: Belirli bir ömrü aşan podları tahliye eder (örneğin, çok uzun süredir çalışan podları yeniden başlatmak için).
* NodeAffinity / Taints / Labels: Artık node affinity kurallarına uymayan, taints'i tolere etmeyen veya etiketleri değişen düğümlerdeki podları tahliye eder.

Descheduler'ın konfigürasyonu, hangi stratejilerin kullanılacağını ve hangi podların tahliye edileceğini belirler.


apiVersion: apps/v1
kind: Deployment
metadata:
  name: descheduler
spec:
  template:
    spec:
      containers:
      - name: descheduler
        image: registry.k8s.io/descheduler/descheduler:v0.29.0
        args:
          - --policy-config-file=/policy/config.yaml
          - --v=3
        volumeMounts:
          - name: policy-volume
            mountPath: /policy
      volumes:
        - name: policy-volume
          configMap:
            name: descheduler-policy-config
---
apiVersion: v1
kind: ConfigMap
metadata:
  name: descheduler-policy-config
data:
  config.yaml: |
    apiVersion: descheduler/v1alpha1
    kind: DeschedulerPolicy
    strategies:
      "RemoveDuplicates":
        enabled: true
      "LowNodeUtilization":
        enabled: true
        params:
          nodeResourceUtilizationThreshold: 20
          targetThresholds:
            cpu: 50
            memory: 50

Küme Dengesi İçin Önemi

Descheduler, küme kaynaklarının zaman içinde optimum şekilde kullanılmasını sağlayarak maliyetleri düşürebilir ve performansı artırabilir. Özellikle dinamik ve değişken iş yüklerine sahip kümelerde, düğümlerin aşırı yüklenmesini veya yetersiz kullanılmasını önlemek için vazgeçilmez bir araçtır.

Sonuç

Kubernetes'in varsayılan zamanlayıcısı, çoğu senaryo için harika bir başlangıç noktası sunsa da, ileri seviye zamanlama özellikleri uygulamalarınızın dağıtımını ve performansını bir sonraki seviyeye taşıyabilir. Node Affinity, Taints ve Tolerations, Pod Affinity/Anti-Affinity, Topology Spread Constraints, Priority ve Preemption gibi mekanizmalar, pod yerleşimini hassas bir şekilde kontrol etmenizi sağlar. Daha da ötesi, özel zamanlayıcılar ve Descheduler gibi araçlar, en karmaşık senaryolar için bile esneklik ve optimizasyon sunar. Bu "gizli cevherleri" ustaca kullanarak, Kubernetes kümenizin potansiyelini tam olarak ortaya çıkarabilir, uygulamalarınızın yüksek erişilebilirliğini, performansını ve maliyet etkinliğini artırabilirsiniz.

SSS (Sık Sorulan Sorular)

Neden varsayılan Kubernetes zamanlayıcısı her zaman yeterli değildir?

Varsayılan zamanlayıcı, genel amaçlı ve adil bir dağıtım sağlamaya odaklanır. Ancak, belirli donanım gereksinimleri, uygulama bileşenleri arasındaki sıkı bağlantılar, maliyet optimizasyonu, yüksek erişilebilirlik için özel dağıtım desenleri veya karmaşık kurumsal politikalar gibi özel durumlar için daha ince ayarlı kontrollere ihtiyaç duyulabilir.

Hangi durumda özel bir zamanlayıcı kullanmalıyım?

Eğer Node Affinity, Taints/Tolerations, Pod Affinity/Anti-Affinity, Topology Spread Constraints veya Priority/Preemption gibi yerleşik mekanizmalar gereksinimlerinizi karşılamıyorsa, özel bir zamanlayıcı düşünmelisiniz. Bu genellikle çok spesifik donanım entegrasyonu, karmaşık dış sistem bağımlılıkları veya benzersiz maliyet/performans optimizasyon algoritmaları gerektiren durumlarda geçerlidir.

Taints ve Tolerations ile Node Affinity arasındaki temel fark nedir?

Node Affinity, bir pod'un *hangi düğüme* gitmesi gerektiğini belirtir (çekme). Taints ve Tolerations ise bir düğümün *hangi podları* kabul etmeyeceğini belirtir (itme). Node Affinity, pod'u belirli bir düğüm grubuna çekerken, Taints düğümü belirli pod gruplarından uzak tutar. Genellikle, ayrılmış düğümler oluşturmak için Taints ve Tolerations birlikte kullanılır.

Descheduler'ı ne sıklıkla çalıştırmalıyım?

Descheduler'ın çalışma sıklığı, kümenizin dinamikliğine ve iş yüklerinizin değişim hızına bağlıdır. Genellikle, saatte bir veya birkaç saatte bir çalıştırmak yeterli olabilir. Çok dinamik kümelerde daha sık (örneğin 30 dakikada bir), daha statik kümelerde ise daha seyrek (örneğin günde bir) çalıştırılabilir. Aşırı sık çalıştırmak, gereksiz pod tahliyelerine ve küme istikrarsızlığına yol açabilir.

Topology Spread Constraints'in performansa etkisi var mı?

Evet, Topology Spread Constraints kullanmak, zamanlayıcının daha karmaşık hesaplamalar yapmasını gerektirdiği için pod zamanlama süresini bir miktar artırabilir. Ancak, bu etki genellikle küme boyutuna ve kısıtlama sayısına bağlıdır ve çoğu durumda ihmal edilebilir düzeydedir. Asıl faydası, uygulamanızın yüksek erişilebilirliğini ve hata toleransını artırarak genel sistem performansına ve güvenilirliğine olumlu katkı sağlamasıdır.

Yorumlar
İçeriği beğendiniz mi? Bir tartışma başlatın veya görüşlerinizi paylaşın.
Yorum Yaz

Bir yanıt yazın

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

E-posta Bülteni
Yazılım Topluluğuna Katılın
En son güncellemeleri, yaratıcı ipuçlarını ve özel kaynakları doğrudan e-posta kutunuza alın. Tasarım ve inovasyonun geleceğini birlikte keşfedelim.