Yeni yazı: Konteynerden Orkestrasyona: Kubernetes Ne Zaman Gerekir?
Konteynerden Orkestrasyona: Kubernetes Ne Zaman Gerekir?

Konteynerden Orkestrasyona: Kubernetes Ne Zaman Gerekir?

İçindekiler

Yol haritası yazısında seriyi dört evreye ayırmıştık. Birinci evrenin birinci sorusu şuydu: konteyner tam olarak nedir, ve neden bir noktadan sonra tek başına yetmiyor?

Kubernetes’i anlatan çoğu metin işi yanlış uçtan tutuyor: önce Kubernetes’in ne kadar yetenekli olduğunu sıralıyor, konteyneri bir dipnot gibi geçiyor. Oysa sıra tersidir. Kubernetes bir konteyner çalıştırma aracı değildir — konteyner çalıştırmak zaten tek satır. Kubernetes, o tek satırın cevaplamadığı soruya verilmiş bir cevaptır: o konteyneri kim ayakta tutacak?

Bu yazıda önce konteynerin sanal makineden nerede ayrıldığını komut çıktısıyla kanıtlayacağız. Sonra tek sunucuda Docker’ın tam olarak nerede duvara tosladığını, orkestrasyonun bu duvarı hangi fikirle aştığını ve — en az onun kadar belirleyici olan — Kubernetes’in size gereksiz olduğu durumları ele alacağız.

Aşağıdaki çıktılar argo-lab01 adlı kurgusal bir Debian 12 makinesinden alınmış örnek değerlerdir; PID’ler, kimlikler ve sürüm numaraları sizin sisteminizde farklı olacaktır. Komutlar ve davranışlar gerçektir.

Yazı boyunca geçen terimlerin kısa karşılıkları için sondaki terimler sözlüğüne bakabilirsiniz.

Konteyner Bir Sanal Makine Değildir: Aynı Çekirdek, Ayrı Görüş

İki teknolojiyi ayıran tek bir cümle var, gerisi bunun sonucudur:

Sanal makinenin kendi çekirdeği vardır; konteynerin yoktur.

Sanal makine, hypervisor’ın donanımı taklit etmesiyle çalışır. İçine kurduğunuz Debian kendi çekirdeğini yükler, kendi init sürecini başlatır, kendi disk ve ağ sürücülerini kullanır. Host çekirdeğiyle tek satır kod paylaşmaz. Sanallaştırma yazısında anlatılan model budur.

Konteynerde bu katman yoktur. Konteyner, host çekirdeğinin üzerinde çalışan sıradan bir Linux sürecidir — tek farkı, çekirdeğin ona sistemin geri kalanını göstermemesidir.

flowchart TB
    subgraph SM["Sanal makine"]
        direction TB
        SMD["Donanım"] --> SMH["Host çekirdeği + hypervisor"]
        SMH --> SMV1["Konuk çekirdek<br/>init + kütüphaneler"]
        SMH --> SMV2["Konuk çekirdek<br/>init + kütüphaneler"]
        SMV1 --> SMA1["Uygulama A"]
        SMV2 --> SMA2["Uygulama B"]
    end
    subgraph KN["Konteyner"]
        direction TB
        KND["Donanım"] --> KNK["Tek host çekirdeği<br/>hepsi bunu paylaşır"]
        KNK --> KNR["containerd + runc"]
        KNR --> KNA1["Uygulama A<br/>+ kütüphaneleri"]
        KNR --> KNA2["Uygulama B<br/>+ kütüphaneleri"]
    end
    SM ~~~ KN
    classDef don fill:#f1f5f9,stroke:#64748b,color:#0f172a
    classDef cek fill:#fee2e2,stroke:#dc2626,color:#7f1d1d
    classDef ara fill:#fef3c7,stroke:#d97706,color:#78350f
    classDef uyg fill:#dbeafe,stroke:#2563eb,color:#1e3a8a
    class SMD,KND don
    class SMH,SMV1,SMV2,KNK cek
    class KNR ara
    class SMA1,SMA2,KNA1,KNA2 uyg

Şemada kırmızı kutuları sayın: sanal makine tarafında üç tane var — host çekirdeği ve iki konuk çekirdek. Konteyner tarafında bir tane. Bu yazının kalanı, o farkın faturasını okumaktan ibaret.

Kanıt: Konteynerin İçinden Çekirdeği Sorun

Konuşmak yerine bakalım. argo-lab01 bir Debian 12 makinesi:

root@argo-lab01:~# uname -r
6.1.0-13-amd64

Şimdi üstünde bir Alpine konteyneri çalıştırıp aynı soruyu içeriden soralım:

root@argo-lab01:~# docker run --rm alpine cat /etc/os-release | head -2
NAME="Alpine Linux"
ID=alpine
root@argo-lab01:~# docker run --rm alpine uname -r
6.1.0-13-amd64

İki çıktı birlikte okunmalı. Dağıtım Alpine: farklı paket yöneticisi, farklı libc, farklı dosya düzeni. Çekirdek Debian’ın çekirdeği: aynı sürüm numarası, çünkü zaten aynı çekirdek. Konteyner “içine Alpine kurulmuş küçük bir makine” değil, Alpine’ın kullanıcı alanı dosyalarıyla açılmış bir süreçtir.

Bunun pratikte iki keskin sonucu var:

  • Linux çekirdeği yalnızca Linux konteyneri çalıştırır. Windows konteynerleri Windows çekirdeği ister. Docker Desktop’ın Windows’ta Linux konteyneri çalıştırabilmesinin sebebi bir sihir değil, arkada dönen bir Linux sanal makinesidir (WSL2).
  • Çekirdeği yükseltmek host’u yeniden başlatmak demektir, bu da o host üzerindeki tüm konteynerleri durdurur. Sanal makinede bir konuk çekirdeği yükseltmek yalnızca o VM’i etkiler.

İzolasyonu Kuran İki Mekanizma: namespace ve cgroup

“Çekirdek ona sistemin geri kalanını göstermez” cümlesinin arkasında iki ayrı çekirdek özelliği var ve ikisi farklı işler yapar.

namespace = ne görüyor. Süreç için ayrı bir görüş alanı açar: kendi süreç ağacı, kendi ağ arayüzleri, kendi bağlama noktaları, kendi hostname’i.

cgroup = ne kadar tüketebiliyor. Görüşü değil kaynağı sınırlar: CPU, bellek, disk G/Ç.

Bir konteyner başlatıp ikisini de yerinde görelim:

root@argo-lab01:~# docker run -d --name web -p 8080:80 --memory=256m --cpus=0.5 nginx:1.27-alpine
3f1a9c7d2b84e5f0a1c6d39b7e24f8a05c1b6d93e7f204a8b1c5d6e9f30a7b21

Konteynerin içinden süreç listesi:

root@argo-lab01:~# docker exec web ps
PID   USER     TIME  COMMAND
    1 root      0:00 nginx: master process nginx -g daemon off;
   30 nginx     0:00 nginx: worker process
   31 nginx     0:00 nginx: worker process
   38 root      0:00 ps

Konteyner kendini tek başına bir sistem sanıyor: nginx PID 1, yani init. Şimdi host’tan aynı sürece bakalım:

root@argo-lab01:~# ps -eo pid,ppid,user,args | grep "[n]ginx: master"
  21584   21562 root     nginx: master process nginx -g daemon off;

Aynı süreç, iki farklı numara. İçeride 1, dışarıda 21584. PID namespace’in yaptığı iş tam olarak budur: numaralandırmayı yeniden başlatır. Süreç saklanmış değil — host onu görüyor, kill edebilir, strace edebilir. Bir sanal makinenin içindeki süreci host’un ps çıktısında bulamazsınız; buradaysa buluyoruz.

Ebeveyn süreç 21562 de öğretici:

root@argo-lab01:~# ps -o pid,args -p 21562
    PID COMMAND
  21562 /usr/bin/containerd-shim-runc-v2 -namespace moby -id 3f1a9c7d2b84e5f0a1c6d39b7e24f8a05c1b6d93e7f204a8b1c5d6e9f30a7b21 -address /run/containerd/containerd.sock

nginx’in ebeveyni dockerd değil, containerd-shim. Docker komut satırı sizin muhatabınız; konteyneri fiilen çalıştıran alt katman containerd ve runc. Bu ayrım ileride önem kazanacak: Kubernetes 1.24 ile dockershim kaldırıldığında kubelet’in Docker Engine’e olan bağı koptu, ama konteynerler aynı containerd üzerinde çalışmaya devam etti. Bu konuya yol haritasının 2. başlığında döneceğiz.

Namespace’lerin kendisi /proc altında görülebilir:

root@argo-lab01:~# ls -l /proc/21584/ns/
lrwxrwxrwx 1 root root 0 Aug 13 10:06 cgroup -> 'cgroup:[4026532633]'
lrwxrwxrwx 1 root root 0 Aug 13 10:06 ipc -> 'ipc:[4026532571]'
lrwxrwxrwx 1 root root 0 Aug 13 10:06 mnt -> 'mnt:[4026532569]'
lrwxrwxrwx 1 root root 0 Aug 13 10:06 net -> 'net:[4026532574]'
lrwxrwxrwx 1 root root 0 Aug 13 10:06 pid -> 'pid:[4026532572]'
lrwxrwxrwx 1 root root 0 Aug 13 10:06 time -> 'time:[4026531834]'
lrwxrwxrwx 1 root root 0 Aug 13 10:06 user -> 'user:[4026531837]'
lrwxrwxrwx 1 root root 0 Aug 13 10:06 uts -> 'uts:[4026532570]'

Köşeli parantez içindekiler namespace’lerin inode numaralarıdır; aynı numara aynı namespace demektir. Altı tanesi 4026532… ile başlıyor — bunlar konteyner için yeni açılmış. İki tanesi (time ve user) 4026531… ile başlıyor. Bunları host’un PID 1‘iyle karşılaştıralım:

root@argo-lab01:~# ls -l /proc/1/ns/user /proc/21584/ns/user
lrwxrwxrwx 1 root root 0 Aug 13 10:06 /proc/1/ns/user -> 'user:[4026531837]'
lrwxrwxrwx 1 root root 0 Aug 13 10:06 /proc/21584/ns/user -> 'user:[4026531837]'

Numaralar birebir aynı. Yani konteyner varsayılan olarak kendi user namespace’ini almaz: konteynerin içindeki root, host’un root‘udur. Bir sonraki bölümün tamamı bu satırın sonucu.

Kaynak tarafına, yani cgroup’a bakalım. Konteyneri --memory=256m --cpus=0.5 ile başlatmıştık:

root@argo-lab01:~# docker exec web cat /sys/fs/cgroup/memory.max /sys/fs/cgroup/cpu.max
268435456
50000 100000

268435456 bayt = 256 MiB. 50000 100000 ise “her 100 ms’lik dilimde en fazla 50 ms CPU”, yani yarım çekirdek. Sınırı uygulayan Docker değil, çekirdektir; Docker yalnızca değerleri yazar.

Ön koşul: Bu yollar cgroup v2 içindir ve konteynerin kendi cgroup namespace’ini görmesini gerektirir (Docker 20.10+ ile cgroup v2 üzerinde varsayılan). Debian 12 ve güncel dağıtımlar cgroup v2 kullanır. Hâlâ cgroup v1’deyseniz karşılığı /sys/fs/cgroup/memory/memory.limit_in_bytes olur; stat -fc %T /sys/fs/cgroup komutu cgroup2fs derse v2’desiniz.

Farkın Faturası: Neyi Kazanıp Neyi Kaybediyorsunuz

Sanal makine Konteyner
Çekirdek Kendi konuk çekirdeği Host çekirdeği, paylaşımlı
Başlangıç süresi Onlarca saniye: firmware, çekirdek, init, servisler Saniyenin altında: tek süreç başlatma
Disk maliyeti Minimal bir Debian imajı ~1,5 GB nginx:1.27-alpine 52,5 MB
İşletim sistemi çeşitliliği Linux host üzerinde Windows çalışır Linux çekirdeği yalnızca Linux konteyneri çalıştırır
İzolasyon sınırı Hypervisor — donanım destekli Çekirdek — namespace ve cgroup
Çekirdek yükseltmesi VM’i yeniden başlatır, host etkilenmez Host’u yeniden başlatır, üstündeki tüm konteynerler durur

İlk üç satır konteyneri cazip yapan şey. Dördüncü satır kısıt. Beşinci satır ise en çok hafife alınan satırdır.

Paylaşılan Çekirdek Bir Güvenlik Sınırı Değildir

Sanal makinede iki VM arasındaki duvarı hypervisor ve işlemcinin sanallaştırma desteği tutar. Konteynerde o duvarı çekirdeğin kendisi tutar — ve çekirdek her iki tarafta da aynı çekirdektir. Çekirdekte sömürülebilir bir açık varsa, konteynerden çıkış yolu vardır.

Ama pratikte insanların başını çekirdek açıkları yakmıyor. Basit bir bayrak yakıyor:

root@argo-lab01:~# docker run --rm -v /:/host alpine ls -l /host/etc/shadow
-rw-r----- 1 root shadow 1042 Aug 12 22:31 /host/etc/shadow

Bir önceki bölümde user namespace’in paylaşıldığını görmüştük; sonucu bu. Konteyner içindeki root host’un root‘u olduğu için, host kök dizinini bağlayan konteyner host’un parola dosyasını okuyabildi. Aynı yöntemle /host/etc/sudoers dosyasına yazabilir, /host/root/.ssh/authorized_keys dosyasına anahtar ekleyebilirdi.

Bu bir açık değil, tasarımın kendisidir — ve şu sonuca varır: docker grubuna üyelik, pratikte parolasız root yetkisidir. Gruplar yazısında bu grubu sudo ile aynı ağırlıkta bir karar olarak işaretlemiştik; kanıtı yukarıdaki üç satır.

Docker’ın bu duruma iki resmî cevabı var ve ikisi de varsayılan değil, açıkça seçilmesi gerekiyor. Rootless mode daemon’ı sıradan bir kullanıcıyla çalıştırır; konteynerdeki root host’ta o kullanıcıya karşılık gelir. Daha eski userns-remap seçeneği ise daemon’ı root bırakıp yalnızca konteynerlerin UID aralığını kaydırır. İkisi de bazı yeteneklerden feragat eder (rootless modda ayrıcalıklı port yayımlamak ve bazı ağ/depolama sürücüleri kısıtlıdır), bu yüzden üretimde açmadan önce uygulamanızın neye ihtiyacı olduğunu bilin.

Çekirdeği hiç paylaşmamak isteyenler için ise ara çözümler var: gVisor kullanıcı alanında bir çekirdek katmanı koyar, Kata Containers her konteyneri hafif bir sanal makineye alır. İkisinin de bedeli performans ve işletme karmaşıklığıdır; çok kiracılı ortamlar dışında karşılığı çıkmaz.

Docker Tek Sunucuda Nereye Kadar Yeter?

Şimdi hikâyenin ikinci yarısına geçelim. argo-lab01 üzerinde üç konteynerli bir uygulama çalışıyor: web, api, db. docker compose up -d diyorsunuz, çalışıyor. Buraya kadar Kubernetes’e ihtiyaç yok — ve bu cümleyi bu yazının en sonunda tekrar edeceğiz.

Sorun, “çalışıyor"un ne kadar sürdüğünde başlıyor.

restart: always Ölen Süreci Kaldırır, Asılı Kalanı Kaldırmaz

Docker’ın yeniden başlatma politikasını herkes bilir:

services:
  api:
    image: ornek/api:1.4.2
    restart: always
    healthcheck:
      test: ["CMD", "wget", "-qO-", "http://localhost:8080/healthz"]
      interval: 10s
      timeout: 2s
      retries: 3

Bir sabah api isteklere cevap vermiyor. Veritabanı bağlantı havuzu tükenmiş, süreç kilitlenmiş. Ama ölmemiş: hâlâ 8080 portunu tutuyor, hâlâ bellekte. Docker ne diyor?

root@argo-lab01:~# docker ps --format 'table {{.Names}}\t{{.Status}}'
NAMES   STATUS
api     Up 22 minutes (unhealthy)
db      Up 22 minutes
web     Up 22 minutes
root@argo-lab01:~# docker inspect -f '{{.RestartCount}}' api
0

Bu iki çıktı birlikte kesin bir şey söylüyor. RestartCount sıfır — yani restart: always hiç devreye girmedi. Girmesi de gerekmezdi: yeniden başlatma politikası sürecin çıkışını izler, süreç çıkmadı. Uygulama kilitlendiğinde çıkış kodu üretmez.

Peki healthcheck ne oldu? Görevini yaptı: durumu unhealthy olarak işaretledi. Docker Engine bu bilgiyle hiçbir şey yapmaz. Sağlık durumuna bakıp konteyneri yeniden başlatan katman Swarm’dır; düz docker run ya da docker compose değil.

Çıktının kanıt değeri de buradan geliyor: süreç çökmüş olsaydı RestartCount sıfırdan büyük olurdu ve STATUS sütununda “Up 22 minutes” değil “Up 8 seconds” yazardı. İki senaryo aynı görünmüyor; bu yüzden yukarıdaki çıktı bir şey kanıtlıyor.

Kubernetes’in bu boşluğa verdiği cevabın adı liveness probe‘dur:

livenessProbe:
  httpGet:
    path: /healthz
    port: 8080
  periodSeconds: 10
  failureThreshold: 3

Fark tek kelimede: Kubernetes’te sağlık kontrolünün bir eylemi vardır. Üç kez üst üste cevap alınamazsa kubelet konteyneri öldürür ve yeniden başlatır; sayaç da bunu yazar:

NAME                   READY   STATUS    RESTARTS      AGE
api-6d4b7c8f9d-2xk4z   1/1     Running   1 (34s ago)   22m

RESTARTS sütunundaki 1, Docker tarafındaki RestartCount: 0‘ın tam karşılığıdır. Aynı arıza, iki farklı sonuç.

Sunucu Komple Ölünce Docker’ın Elinden Bir Şey Gelmez

Yeniden başlatma politikası dockerd ayakta olduğu sürece çalışır. Anakart arızalanır, güç kesilir ya da çekirdek panik verirse dockerd de gitmiştir. Konteynerler o sunucuya çivilenmiştir; onları başka bir yere taşıyacak bir mekanizma yoktur, çünkü Docker’ın “başka bir yer” diye bir kavramı yoktur.

Elle çözmeye kalkarsanız, çözmeniz gereken beş ayrı problem çıkar:

  1. Yerleştirme. Yeni konteyner hangi sunucuda başlatılacak? Hangisinde yeterli boş bellek var?
  2. Ayakta tutma. Bir sunucu düştüğünde üstündekileri kim, ne zaman fark edip nereye taşıyacak?
  3. Adres. Konteyner başka sunucuda yeniden doğduğunda IP’si değişir. Ona istek gönderen servis yeni adresi nereden öğrenecek?
  4. Güncelleme. Yeni sürüme kesintisiz nasıl geçilecek, hata çıkarsa eskiye nasıl dönülecek?
  5. Yapılandırma. Veritabanı parolasını on iki sunucuya elle mi dağıtacaksınız, değiştiğinde hepsini tek tek mi güncelleyeceksiniz?

Bu beş maddeyi kendi betiklerinizle çözmeye başladığınız an, farkında olmadan bir orkestrasyon aracı yazmaya başlamış olursunuz. Kubernetes’in var oluş sebebi tam olarak bu listedir.

Orkestrasyonun Fikri: Emir Değil, İstenen Durum

Kubernetes’i “konteynerleri yöneten araç” diye tarif etmek eksik kalır, çünkü asıl yenilik yönetmek değil, yönetme biçimidir.

Docker’da emir verirsiniz: bu konteyneri başlat. Emir anlıktır; sunucu ölünce emri veren de yok olur.

Kubernetes’te durum bildirirsiniz: bu uygulamadan her zaman 3 kopya çalışsın. Bu cümle bir emir değil, kalıcı bir kayıttır. Kümenin içinde çalışan denetleyiciler (controller) sürekli olarak iki şeyi karşılaştırır: ne istendi, ne gözleniyor. Fark varsa kapatırlar.

flowchart LR
    I["İstenen durum<br/>replicas: 3"] --> D{"Denetleyici<br/>farkı hesaplar"}
    G["Gözlenen durum<br/>çalışan: 2"] --> D
    D -->|"fark: 1"| E["Eylem<br/>1 pod oluştur"]
    E --> G
    D -->|"fark: 0"| B["Bir şey yapma"]
    classDef ist fill:#dcfce7,stroke:#16a34a,color:#14532d
    classDef goz fill:#dbeafe,stroke:#2563eb,color:#1e3a8a
    classDef den fill:#fef3c7,stroke:#d97706,color:#78350f
    classDef eyl fill:#fee2e2,stroke:#dc2626,color:#7f1d1d
    class I ist
    class G goz
    class D den
    class E eyl
    class B goz

Bu döngü hiç durmaz. Bir sunucu öldüğünde kimse “taşı” komutu vermez; gözlenen kopya sayısı 3’ten 2’ye düştüğü için döngü kendiliğinden bir kopya daha oluşturur. Aynı döngü, bir pod’u siz elle sildiğinizde de çalışır — bu yüzden Deployment’ın pod’unu kubectl delete pod ile silmek işe yaramaz, saniyeler içinde yenisi gelir.

Önceki bölümdeki beş problemin karşılıkları da bu modelin üstünde durur:

Tek sunucuda elle yaptığınız iş Kubernetes’teki karşılığı Seride nerede
Hangi sunucuda çalışacağına karar vermek scheduler 2.1 ve 9.3
Ölen konteyneri kaldırmak kubelet + ReplicaSet 5.1
Kaç kopya çalışacağını sabitlemek Deployment replicas 5.1
Değişmeyen bir adres vermek Service ve CoreDNS 6.2 ve 6.3
Kesintisiz güncelleme ve geri dönüş Deployment rolling update 5.2
Parola ve ayar dağıtmak ConfigMap ve Secret 8.1 ve 8.2
Asılı kalan süreci fark etmek livenessProbe 5.5

Bu tablodaki her satır yol haritasının bir başlığına denk geliyor; sağ sütun hangi yazıda ele alınacağını gösteriyor.

Kubernetes de Sihir Değil: Ölü Düğümün Pod’ları Ne Zaman Taşınır?

Uzlaşma döngüsünü anlattıktan sonra en sık düşülen yanılgıyı da hemen düzeltelim: Kubernetes bir düğüm kaybını saniyeler içinde değil, dakikalar içinde toparlar. Zincir şöyle işler:

Adım Kim yapar Varsayılan süre
Düğüm durumunu bildirmek kubelet → apiserver her 10 saniyede bir
Sessiz kalan düğümü NotReady işaretlemek kube-controller-manager --node-monitor-grace-period
Pod’ları tahliye etmek taint tabanlı tahliye tolerationSeconds, varsayılan 300 saniye

İkinci satırın varsayılanı uzun süredir 40 saniye civarındadır, ama bu değer sürümden sürüme değişebiliyor; sayıyı ezberlemek yerine kendi kümenizde kube-controller-manager bayraklarından okuyun. Üçüncü satırın 300 saniyesi ise apiserver’ın --default-not-ready-toleration-seconds ve --default-unreachable-toleration-seconds bayraklarından gelir. Toplam: bir düğüm elektriğini kaybettiğinde pod’ları beş dakikadan önce başka yere taşınmaz.

Bu bilinçli bir tercihtir. Kısa bir ağ kesintisiyle gerçek bir sunucu ölümünü uzaktan ayırt etmek mümkün değildir; eşik kısaltılırsa küme her ağ hıçkırığında sağlıklı pod’ları katletmeye başlar.

Pratik sonucu şudur: kesintisizlik, tek kopyanın hızlı taşınmasından değil, kopyaların baştan farklı düğümlerde durmasından gelir. Üç kopyayı üç ayrı düğüme dağıtırsanız bir düğüm öldüğünde kalan ikisi hizmeti sürdürür; taşıma işlemi arka planda, kimse fark etmeden tamamlanır. Bunu sağlayan topologySpreadConstraints ve anti-affinity kuralları serinin 9.3 başlığında.

Bir uç durum daha var: kalıcı diski olan StatefulSet pod’ları ulaşılamayan bir düğümde Terminating durumunda takılı kalır ve otomatik olarak yeniden oluşturulmaz. Sebebi mantıklı — aynı diski iki düğümün birden bağlaması veri kaybı demektir ve Kubernetes düğümün gerçekten öldüğünü uzaktan bilemez. Kubernetes 1.28’de kararlı hâle gelen node.kubernetes.io/out-of-service taint’i, “bu düğüm gerçekten öldü, kilidi aç” demenin resmî yoludur.

Kubernetes’e Gerçekten İhtiyacınız Var mı?

Buraya kadar Kubernetes’in hangi problemi çözdüğünü gördük. Şimdi asıl soru: o problem sizde var mı?

Basitten Karmaşığa Merdiven

Altyapı kararları merdiven gibi düşünülmeli. Bir üst basamağa yalnızca alt basamak somut bir sorunu çözemediğinde çıkın — merak ettiğiniz için değil.

  1. systemd servisi. Tek uygulama, tek sunucu. Restart=always ve journalctl çoğu iç aracın ihtiyacını karşılar.
  2. docker compose + restart: unless-stopped. Birkaç servis, hâlâ tek sunucu. Bağımlılıkları imaja gömer, kurulumu tekrarlanabilir kılar.
  3. İki sunucu + önünde bir yük dengeleyici. İlk gerçek kesinti toleransı. Kubernetes’in en çok reklamı yapılan faydasının büyük kısmı bu basamakta, çok daha ucuza elde edilir.
  4. Yönetilen bir PaaS. Ekibiniz altyapı işletmek istemiyorsa dürüst cevap budur.
  5. k3s veya tek düğümlü Kubernetes. Öğrenmek için, ya da küçük ekiplerin Kubernetes ekosisteminden (Helm chart’ları, operator’ler) yararlanması için.
  6. Tam Kubernetes. Üç control plane düğümü ve n worker, ya da yönetilen bir servis.

Kubernetes’in Kendisi de Bir İş Yüküdür

Kubernetes’in maliyeti kurulum değil, işletmedir. Kümeyi kurmak bir öğleden sonra sürer; ayakta tutmak süreklidir:

  • Yüksek erişilebilirlik üç control plane düğümü ister. etcd çoğunluk (quorum) ile çalışır ve çoğunluk (n/2)+1‘dir: 3 düğüm bir kaybı tolere eder, 2 düğüm hiçbirini. Yani ikinci düğüm eklemek erişilebilirliği artırmaz, üçüncü artırır.
  • Yükseltme takvimi sizi bekler. Kubernetes yılda üç minor sürüm çıkarıyor ve her sürüm yaklaşık 14 ay yama alıyor. Yükseltmeyi ertelemek, bir gün desteklenmeyen bir sürümde kalmak demek.
  • Sertifikaların ömrü var. Küme içi sertifikalar süreli üretilir; kimse yenilemezse bir sabah küme kendi kendisiyle konuşamaz hâle gelir.
  • etcd yedeği ve geri dönüş tatbikatı gerekir. Yedeği olmayan etcd, kümenin tamamının tek arıza noktasıdır.
  • Yönetilen servis işin yarısını alır. EKS, GKE ve AKS control plane’i devralır; ağ eklentisi, depolama sınıfları, RBAC, kaynak limitleri ve yükseltme kararları sizde kalır.

Kabaca bir ölçüt: bu işlerle ilgilenecek kimse yoksa, Kubernetes ekibinize güvenilirlik değil, yeni bir nöbet listesi ekler.

Karar Soruları

Dört soru, kararı büyük ölçüde belirler:

  • Uygulamanız tek bir sunucunun kaybına dayanmak zorunda mı? Değilse merdivenin ilk iki basamağı yeterli.
  • Kaç servis, kaç ekip? Tek ekip ve üç servis için Kubernetes’in getirdiği soyutlama katmanı, kazandırdığından fazlasını götürür.
  • Yükünüz değişken mi? Sabit yükte otomatik ölçeklemenin karşılığı yoktur; sabit kapasite daha ucuzdur.
  • Kümeyi kim işletecek? Bu sorunun cevabı bir isim değilse, cevap “henüz değil"dir.

Bunların hepsine “hayır” diyorsanız Kubernetes size gerekmiyor demektir — ama öğrenmek için ihtiyaç şartı yok. kind veya k3s ile dizüstü bilgisayarınızda dakikalar içinde bir küme kurulur ve serinin çoğu konusu orada denenebilir. Serinin bir sonraki evresinde tam olarak bunu yapacağız.

Sonuç

  • Konteyner hafif bir sanal makine değil, çekirdeğin görüşünü ve kaynağını sınırladığı sıradan bir süreçtir. Host’un ps çıktısında görünmesi ve uname -r‘ın host çekirdeğini yazması bunun kanıtı; paylaşılan çekirdek hem hızın hem de zayıf izolasyon sınırının sebebi.
  • Konteynerin içindeki root, host’un root‘udur. User namespace varsayılan olarak ayrılmaz; bu yüzden docker grubuna üyelik vermek, sudo yetkisi vermekle aynı ağırlıkta bir karardır.
  • Kubernetes konteyner çalıştırmak için değil, konteyneri sizin yerinize ayakta tutmak için var. Farkı yaratan mekanizma emir değil, istenen durumla gözlenen durumu sürekli karşılaştıran uzlaşma döngüsüdür.
  • restart: always yalnızca ölen süreci kaldırır, asılı kalanı kaldırmaz. Sağlık kontrolüne eylem bağlayan katman Kubernetes’te livenessProbe’dur; Docker Engine unhealthy yazar ve durur.
  • Kubernetes’in maliyeti kurmak değil, işletmektir. Tek sunucuda çalışan üç servis için merdivenin alt basamağı hâlâ doğru cevaptır.

Sıradaki yazıda kümenin kapağını açıyoruz: control plane hangi bileşenlerden oluşuyor, kubectl apply dediğinizde istek hangi duraklardan geçiyor ve uzlaşma döngüsünü fiilen kim çeviriyor? Serinin tamamı için Kubernetes Öğrenme Yolculuğu sayfasına bakabilirsiniz.

Ek: Terimler Sözlüğü

Terim Karşılığı
İmaj (image) Uygulamanın ve bağımlılıklarının salt okunur katmanlardan oluşan paketi. Çalışmıyor, diskte duruyor.
Konteyner Bir imajın üstüne yazılabilir katman eklenip namespace ve cgroup ile sınırlandırılarak başlatılmış hâli.
namespace Çekirdek özelliği. Sürecin ne gördüğünü sınırlar: süreç ağacı, ağ, bağlama noktaları, hostname.
cgroup Çekirdek özelliği. Sürecin ne kadar tükettiğini sınırlar: CPU, bellek, disk G/Ç.
OCI Open Container Initiative. İmaj biçimini ve çalışma zamanı davranışını standartlaştıran belirtim; Docker ile üretilen imajın Kubernetes’te çalışmasının sebebi.
runc / containerd Konteyneri fiilen başlatan alt katman. runc namespace ve cgroup’ları kurar, containerd yaşam döngüsünü yönetir.
Orkestrasyon Konteynerleri birden çok sunucu üzerinde yerleştirme, ayakta tutma, adresleme ve güncelleme işi.
Control plane / düğüm (node) Kümenin karar veren beyni ile iş yüklerini fiilen çalıştıran sunucular.
Pod Kubernetes’in en küçük zamanlama birimi. Ağ ve depolamayı paylaşan bir veya birkaç konteyner.
Uzlaşma döngüsü İstenen durum ile gözlenen durumu sürekli karşılaştırıp farkı kapatan denetleyici mantığı.
Paylaş :

İlgili Yazılar

Longhorn: Kubernetes Ortamları İçin Devrimsel Depolama Çözümü

Longhorn: Kubernetes Ortamları İçin Devrimsel Depolama Çözümü

Bu yazı Kubernetes Öğrenme Yolculuğu serisinin bir parçasıdır. Günümüzde, konteyner teknolojileri ve mikro hizmet mimarileri, yazılım geliştirme ve dağıtım süreçlerini dönüştürmekte. Bu dönüşüm, depolama çözümlerine yönelik ihtiyaçları da yeniden şekillendiriyor. Kubernetes ekosistemi içinde yer alan Longhorn, bu yeni ihtiyaçlara cevap veren açık kaynaklı bir projedir. Bu yazıda, Longhorn’un ne olduğunu, ne işe yaradığını ve sunduğu faydaları detaylıca ele alacağız.

Evdeki Veri Merkezi: Proxmox ile Kendi Homelab'inizi Kurun

Evdeki Veri Merkezi: Proxmox ile Kendi Homelab'inizi Kurun

Homelab kuran çoğu kişi işe kurmak istediği uygulamadan başlar: bir medya sunucusu, bir Nextcloud, bir oyun sunucusu. Sonra bir şey bozulur ve ortaya çıkar ki logu tutan yoktur, hangi servisin ne zaman düştüğünü kimse bilmez, IP’ler elle dağıtıldığı için de hangi makinenin ne olduğu belirsizdir.

Kubernetes Öğrenme Yolculuğu

Kubernetes Öğrenme Yolculuğu

Kubernetes öğrenmeye çalışan çoğu kişi aynı yerden başlıyor: internetten bir YAML dosyası kopyalıyor, kubectl apply diyor, çalışınca seviniyor, çalışmayınca ne olduğunu anlamıyor. Ben de öyle başladım. Sorun şu ki Kubernetes bir komut seti değil, bir model; o modeli anlamadan ezberlenen komutlar ilk arızada işe yaramıyor.