İçeriğe geç
KubeAtlas
Kubernetes DevOps kubectl Troubleshooting

Kubernetes Mimarisi: Bir Pod Çalışana Kadar Neler Olur

Onur Ömer Tunç 8 dk okuma

kubectl apply -f deployment.yaml yazıyorsunuz ve birkaç saniye sonra pod’lar Running durumunda. Arada ne olduğunu bilmeden de işinizi görürsünüz, ta ki bir pod Pending’de takılana ya da mülakatta “Kubernetes mimarisini anlatır mısınız?” sorusu gelene kadar. Bu yazıda tek bir Deployment’ı baştan sona izliyor, her bileşeni işini yaptığı anda tanıtıyoruz.

Cluster iki bölümden oluşur

Kubernetes dokümanına göre bir cluster, bir control plane ve en az bir worker node’dan oluşur. Control plane cluster hakkındaki kararları verir. Bir pod’un hangi node’da çalışacağını seçer, bir Deployment’ta eksik pod varsa yenisini başlatır. Worker node’lar ise uygulamanızın container’larını çalıştırır.

Eski yazılarda ve mülakat sorularında “master node” ifadesine rastlarsınız. Kubernetes dokümanı bu bölümü bugün control plane diye anlatıyor. Production’da control plane genellikle birden fazla makineye yayılır ve cluster’da birden fazla node çalışır, böylece tek bir makinenin arızası cluster’ı durdurmaz.

Control plane’de kim ne iş yapar

Control plane’de dört ana bileşen var. Akılda tutmanın kolay yolu her birine tek bir görev vermek:

  • kube-apiserver kapıdır. Kubernetes API’sini sunan bileşen odur ve kubectl dahil herkes cluster’la onun üzerinden konuşur. Dokümanda bu düzen “hub-and-spoke” (merkez ve kollar) diye geçer: node’lardan ve pod’lardan gelen bütün API istekleri API server’da biter. Yatay ölçeklenecek şekilde tasarlanmıştır, yani birden fazla kopyası çalıştırılıp trafik aralarında dağıtılabilir.
  • etcd hafızadır. API server’ın bütün verisini tutan anahtar-değer deposudur. Bir Deployment’ın kaç kopya istediği de, bir pod’un hangi node’a atandığı da burada yazar.
  • kube-scheduler yerleştiricidir. Henüz bir node’a atanmamış pod’ları izler ve her biri için uygun bir node seçer.
  • kube-controller-manager denetçidir. İçinde controller’lar (denetleyiciler) çalışır. Bu yazıda Deployment, ReplicaSet ve node controller’larıyla karşılaşacağız. Mantıksal olarak her biri ayrı bir süreçtir, ama işi basitleştirmek için hepsi tek bir programda derlenir ve tek süreç olarak çalışır.

Controller’ın ne yaptığını Kubernetes dokümanı oda termostatıyla anlatıyor. Termostatı 22 dereceye ayarladığınızda ona istediğiniz durumu söylemiş olursunuz. Odanın o anki sıcaklığı ise mevcut durumdur. Termostat ikisini birbirine yaklaştırmak için ısıtıcıyı açıp kapatır. Bir Deployment’a “3 kopya” yazdığınızda da aynısı olur: çalışan pod sayısı ikiye düşerse controller API server’a yeni bir pod oluşturtur.

Dokümana göre etcd’ye erişmek cluster’da root yetkisine sahip olmakla aynı anlama gelir, bu yüzden ona ideal olarak yalnızca API server erişmelidir. Cluster’ın bütün durumu burada durduğu için etcd’nin bir yedekleme planı da olmalı. Bunu yedekleme ve felaket kurtarma yazımızda anlattık.

Cluster bir bulut sağlayıcıda çalışıyorsa beşinci bir bileşen daha olabilir: cloud-controller-manager. Load balancer gibi bulut kaynaklarıyla ilgili controller’ları çalıştırır. Kendi sunucularınızda ya da bilgisayarınızdaki bir deneme cluster’ında bu bileşen yoktur.

Her worker node’da üç parça çalışır

  • kubelet, her node’da çalışan ajandır. O node’a atanmış pod’ların tanımını API server’dan alır ve tanımdaki container’ların çalıştığından ve sağlıklı olduğundan emin olur.
  • Container runtime, container’ı gerçekten çalıştıran yazılımdır. containerd ve CRI-O bunun örnekleridir. kubelet runtime ile CRI (Container Runtime Interface, kubelet ile runtime arasındaki standart arayüz) üzerinden konuşur.
  • kube-proxy, Service’lerin çalışması için node’daki ağ kurallarını yönetir. ClusterIP yazımızda anlattığımız gibi, Service’in sanal adresine gelen isteği bir pod’a ileten bileşen odur. Bazı ağ eklentileri bu işi kendileri yaptığı için her cluster’da kube-proxy bulunmaz.

Pod’lara IP adresini veren ve birbirleriyle konuşmalarını sağlayan ise ağ eklentisidir (CNI, Container Network Interface standardını uygulayan yazılım).

kubectl apply dediğinizde sırayla ne olur

Üç kopyalı bir Deployment uyguladığınızı düşünün:

kubectl apply -f deployment.yaml
  1. kubectl isteği API server’a gönderir. API server Deployment nesnesini etcd’ye kaydeder. Bu noktada hiçbir container çalışmıyor, yalnızca istediğiniz durum kayda geçti.
  2. Deployment controller yeni Deployment’ı görür ve bir ReplicaSet oluşturur.
  3. ReplicaSet controller istenen üç pod ile var olan sıfır pod arasındaki farkı görür ve API server’a üç pod nesnesi oluşturtur. Bu pod’ların henüz bir node’u yok.
  4. Scheduler node’u olmayan bu pod’ları görür. Önce pod’un ihtiyacını karşılamayan node’ları eler (filtreleme), kalanları puanlar ve en yüksek puanı alan node’u seçer. Kararını API server’a bildirir. Dokümanda bu adımın adı binding (bağlama).
  5. Seçilen node’daki kubelet kendisine yeni bir pod atandığını görür. Container runtime’a imajı çektirir ve container’ları başlattırır.
  6. Container’lar başlayınca pod Pending durumundan Running durumuna geçer.

Bileşenler birbirleriyle API server üzerinden haberleşir. Her biri API server’ı izler, kendini ilgilendiren bir değişiklik görünce işini yapar ve sonucu yine oraya yazar. Örneğin scheduler pod’a bir node yazar, kubelet de bunu API server’dan okur.

Akılda tutmak için tek satır: kubectl API server’a yazar, API server etcd’ye kaydeder, controller pod’ları oluşturtur, scheduler node seçer, kubelet container’ı çalıştırır.

Bu zinciri kendi cluster’ınızda görün

Bu bileşenler yaptıkları işi olay (event) olarak kaydeder. Bir Deployment açın ve olaylara zaman sırasıyla bakın. -o wide eklerseniz SOURCE sütununda olayı hangi bileşenin yazdığı da görünür:

kubectl create deployment web --image=nginx --replicas=3
kubectl get events -o wide --sort-by=.metadata.creationTimestamp

Üç pod’un olayları birbirine karışır, ama sıra kabaca şöyledir:

REASONSOURCENe oldu
ScalingReplicaSetdeployment-controllerReplicaSet oluşturuldu
SuccessfulCreatereplicaset-controllerPod nesneleri oluşturuldu
Scheduleddefault-schedulerPod bir node’a atandı
Pulling, Pulledkubeletİmaj çekildi
Created, StartedkubeletContainer başladı

İmaj o node’da zaten varsa Pulling satırını görmezsiniz, Pulled olayının mesajında imajın makinede zaten bulunduğu yazar.

Control plane bileşenlerini de pod olarak görebilirsiniz, ama yalnızca bazı kurulumlarda. kubeadm bu bileşenleri static pod (API server yerine doğrudan kubelet’in yönettiği pod) olarak çalıştırır ve tanım dosyalarını control plane node’unda /etc/kubernetes/manifests dizinine koyar. Yerel denemelerde sık kullanılan kind de node’ları kubeadm ile kurar:

kubectl get pods -n kube-system

Listede kube-apiserver, etcd, kube-scheduler ve kube-controller-manager ile başlayan ve sonunda node adı olan pod’lar görürsünüz. Bulut sağlayıcının yönettiği bir cluster’da bu pod’lar genellikle listede olmaz, çünkü control plane’i sağlayıcı sizin yerinize çalıştırır.

Node’ların kalp atışını (heartbeat) da görebilirsiniz:

kubectl get leases -n kube-node-lease

Her node için bu namespace’te aynı adı taşıyan bir Lease nesnesi vardır. kubelet bu nesneyi düzenli olarak güncelleyerek node’un ayakta olduğunu bildirir.

Bir node çöktüğünde ne olur

Üç worker node’dan biri aniden kapandı diyelim:

  1. O node’daki kubelet kalp atışı göndermeyi bırakır, Lease nesnesi artık güncellenmez.
  2. Node controller node’ları varsayılan olarak 5 saniyede bir kontrol eder. Node’a ulaşılamadığını görünce Ready durumunu Unknown yapar ve node’a bir taint (node’a pod konmasını engelleyen işaret) ekler. Scheduler bundan sonra o node’a yeni pod koymaz. kubectl get nodes çıktısında node NotReady görünür.
  3. Node varsayılan olarak 5 dakika Unknown kalırsa node controller oradaki pod’lar için tahliye (eviction) başlatır.
  4. ReplicaSet controller çalışan pod sayısının istenenin altına düştüğünü görür ve yeni pod’lar oluşturtur. Scheduler bunları sağlam node’lara yerleştirir, oradaki kubelet’ler container’ları başlatır.

Bu senaryo sık yanlış anlatılır: “pod başka bir node’a taşınır.” Kubernetes dokümanına göre bir pod hiçbir zaman başka bir node’a yeniden yerleştirilmez, yerine farklı bir UID ile neredeyse aynı yeni bir pod açılır. Bu yüzden Deployment gibi bir controller’a bağlı olmadan tek başına oluşturduğunuz bir pod, node’u gidince geri gelmez. Onu yeniden oluşturacak bir controller yoktur.

Container çökmesi başka bir durumdur. Node ayaktayken çöken container’ı aynı pod içinde, aynı node’da kubelet yeniden başlatır. restartPolicy varsayılan olarak Always’tır ve kubelet her denemede bekleme süresini artırır: 10 saniye, 20 saniye, 40 saniye ve en fazla 5 dakika. kubectl get pods çıktısındaki RESTARTS sayısı bu yüzden artar. Node gittiğinde ise container’ı yeniden başlatacak bir kubelet kalmaz ve iş controller’lara düşer.

Mülakatta mimariyi nasıl anlatırsınız

“Kubernetes mimarisini anlatır mısınız?” sorusuna bileşenleri sayarak cevap vermek kolaydır, ama bileşenleri bir akışın içinde anlatan cevap daha iyidir. Şu sıra işinizi görür:

  1. İki bölümü söyleyin: kararları veren control plane ve iş yükünü çalıştıran worker node’lar.
  2. Bir kubectl apply isteğini yukarıdaki tek satırlık zincirle baştan sona izleyin.
  3. Kubernetes’in kendini nasıl onardığını istenen durum ile mevcut durum arasındaki fark üzerinden anlatın. Termostat örneği burada işe yarar.
  4. Bir arıza senaryosuyla bitirin: container çökerse ne olur, node çökerse ne olur.

Arkasından gelen sorular genelde bu zincirin bir halkasını sorar: pod neden Pending’de kalabilir (uygun node bulunamamış ya da imaj hâlâ iniyor olabilir), node çökünce pod taşınır mı, API server tek kopya mı çalışmak zorunda.

Sırada ne var

Olay alıştırmasını kind ile açtığınız çok node’lu bir deneme cluster’ında yapın. Ardından bir worker node’u durdurup kubectl get nodes -w ile izleyin: node NotReady olur ve varsayılan ayarlarla birkaç dakika sonra pod’larının yerine diğer node’larda yenileri açılır. Sonraki konu, scheduler’ın node seçerken neye baktığı: kaynak istekleri, taint ve toleration, affinity.

Kubernetes’i bu tür alıştırmalarla, gerçek cluster’lar üzerinde uygulamalı öğrettiğimiz bir DevOps eğitim programımız var. Müfredat ve başvuru: kubeatlas.com/egitimler/devops-egitimi

Kaynaklar

Etiketler Kubernetes DevOps kubectl Troubleshooting