Onlarca container’ı tek tek yönetmeye çalıştığınızı düşünün. Her birini ayrı ayrı başlatmak, durdurmak, güncellemek, ölçeklendirmek… Bir noktada bu iş kaosa dönüşüyor. İşte konteyner orkestrasyonu tam olarak bu kaosun önüne geçmek için var. Ve bu alanda konuşmak zorunda olduğumuz tek bir isim var: Kubernetes.
Konteyner Orkestrasyonu Neden Gerekli?
Docker ile tek bir makine üzerinde birkaç container çalıştırmak oldukça kolay. Ama gerçek dünyada işler böyle yürümüyor. Bir e-ticaret uygulaması düşünün: frontend servisi, backend API, ödeme servisi, bildirim servisi, veritabanı… Bunların hepsi ayrı container’larda çalışıyor ve hepsinin birbirleriyle iletişim kurması, belirli kaynak limitlerinde çalışması, çöktüğünde otomatik yeniden başlaması gerekiyor.
Buna bir de ölçeklendirme ihtiyacını ekleyin. Kampanya günü trafik 10 katına çıktığında backend servisini hızlıca 3 instance’tan 20 instance’a çıkarmanız lazım. Ya da bir node’unuz donanım arızasına girdiğinde üzerindeki container’ların başka node’lara taşınması gerekiyor.
Konteyner orkestrasyonunun çözdüğü temel problemler şunlar:
- Scheduling: Container’ları uygun node’lara otomatik yerleştirme
- Self-healing: Çöken container’ları otomatik yeniden başlatma
- Scaling: Yük durumuna göre otomatik ölçeklendirme
- Load balancing: Trafiği instance’lar arasında dağıtma
- Rolling updates: Sıfır downtime ile güncelleme yapma
- Secret ve config yönetimi: Hassas bilgileri güvenli saklama
Kubernetes Nedir?
Kubernetes (K8s olarak da biliniyor, çünkü “ubernete” kısmında 8 harf var), Google’ın kendi iç sistemleri için geliştirdiği Borg sisteminden ilham alınarak açık kaynak olarak 2014’te yayımlandı. Bugün CNCF (Cloud Native Computing Foundation) bünyesinde geliştiriliyor ve sektörün de facto standardı haline geldi.
Kubernetes’in temel felsefesi şu: Siz istediğiniz durumu tanımlarsınız, Kubernetes o durumu gerçekleştirmek ve sürdürmek için gerekeni yapar. Buna “declarative” yaklaşım deniyor. “Şu anda 5 tane çalışan pod var” demiyorsunuz, “5 tane pod çalışıyor olsun” diyorsunuz.
Temel Mimari
Kubernetes cluster’ı iki ana bileşenden oluşuyor: Control Plane ve Worker Node’lar.
Control Plane
Control Plane, cluster’ın beyni. Tüm kararlar burada alınıyor.
- kube-apiserver: Tüm iletişimin geçtiği merkezi API noktası. kubectl komutlarınız buraya gidiyor.
- etcd: Cluster’ın tüm durum bilgisini saklayan dağıtık key-value store. Kritik öneme sahip, mutlaka yedekleyin.
- kube-scheduler: Yeni pod’ları hangi node’a yerleştireceğine karar veriyor. Kaynak gereksinimleri, node affinity kuralları gibi faktörlere bakıyor.
- kube-controller-manager: Çeşitli controller’ları çalıştırıyor. ReplicaSet controller, Node controller, Job controller bunların arasında.
Worker Node’lar
Asıl işin yapıldığı makineler.
- kubelet: Her node üzerinde çalışan agent. Control plane’den gelen talimatları alıp uygular, pod’ların sağlık durumunu raporlar.
- kube-proxy: Node üzerinde network kurallarını yönetir, service’lere erişimi sağlar.
- Container Runtime: Docker, containerd veya CRI-O. Gerçek anlamda container’ları çalıştıran katman.
Temel Kubernetes Kavramları
Pod
Pod, Kubernetes’teki en küçük deploy edilebilir birim. Bir veya birden fazla container barındırabilir. Aynı pod içindeki container’lar aynı network namespace’i paylaşır, yani localhost üzerinden haberleşebilirler.
Çoğu durumda bir pod’da tek container çalıştırırsınız. Ama “sidecar pattern” gibi durumlarda, örneğin bir log toplayıcı ile ana uygulamayı aynı pod’da çalıştırmak mantıklı olabilir.
Basit bir pod tanımı:
cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: Pod
metadata:
name: nginx-test
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.25
ports:
- containerPort: 80
resources:
requests:
memory: "64Mi"
cpu: "250m"
limits:
memory: "128Mi"
cpu: "500m"
EOF
Pod’un durumunu kontrol etmek için:
# Pod listesini görmek
kubectl get pods
# Detaylı bilgi almak
kubectl describe pod nginx-test
# Pod loglarını takip etmek
kubectl logs -f nginx-test
# Pod içine shell açmak
kubectl exec -it nginx-test -- /bin/bash
Deployment
Gerçek dünyada pod’ları doğrudan oluşturmazsınız. Bunun yerine Deployment kullanırsınız. Deployment, pod’larınızın istenen sayıda çalışmasını garanti eder, rolling update ve rollback imkanı sağlar.
cat <<EOF | kubectl apply -f -
apiVersion: apps/v1
kind: Deployment
metadata:
name: web-app
namespace: production
spec:
replicas: 3
selector:
matchLabels:
app: web-app
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 1
maxUnavailable: 0
template:
metadata:
labels:
app: web-app
version: "1.0"
spec:
containers:
- name: web-app
image: mycompany/web-app:1.0
ports:
- containerPort: 8080
env:
- name: ENV
value: "production"
readinessProbe:
httpGet:
path: /health
port: 8080
initialDelaySeconds: 10
periodSeconds: 5
livenessProbe:
httpGet:
path: /health
port: 8080
initialDelaySeconds: 30
periodSeconds: 10
EOF
Deployment yönetimi için sık kullandığım komutlar:
# Deployment'ı ölçeklendirmek
kubectl scale deployment web-app --replicas=5 -n production
# Yeni image ile güncelleme yapmak
kubectl set image deployment/web-app web-app=mycompany/web-app:1.1 -n production
# Güncelleme durumunu izlemek
kubectl rollout status deployment/web-app -n production
# Önceki versiyona geri almak
kubectl rollout undo deployment/web-app -n production
# Belirli bir revizyona geri almak
kubectl rollout undo deployment/web-app --to-revision=2 -n production
Service
Pod’lar geçici. Her yeniden başladığında IP adresleri değişiyor. Service, pod’larınızın önüne stabil bir ağ endpoint’i koyar.
Üç temel Service tipi var:
- ClusterIP: Sadece cluster içinden erişilebilir. Mikroservisler arası iletişim için ideal.
- NodePort: Her node üzerinde belirli bir port’tan dış erişim sağlar. Development ortamları için kullanılabilir.
- LoadBalancer: Cloud provider’ın load balancer’ını kullanır. Production ortamında dış trafik için kullanılır.
cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: Service
metadata:
name: web-app-service
namespace: production
spec:
selector:
app: web-app
type: ClusterIP
ports:
- protocol: TCP
port: 80
targetPort: 8080
EOF
Namespace
Namespace’ler cluster kaynakların mantıksal olarak ayrıştırmanızı sağlar. Genellikle farklı ortamlar (dev, staging, production) veya farklı takımlar için kullanılır.
# Namespace oluşturmak
kubectl create namespace production
kubectl create namespace staging
# Namespace bazlı kaynak görüntüleme
kubectl get all -n production
# Tüm namespace'lerdeki pod'ları görmek
kubectl get pods --all-namespaces
Gerçek Dünya Senaryosu: Mikroservis Uygulaması Deploy Etmek
Bir e-ticaret uygulamasının backend API’sini ve Redis cache’ini Kubernetes’e deploy edelim.
Önce bir namespace oluşturalım:
kubectl create namespace ecommerce
# Context'i bu namespace'e ayarlamak (her komutta -n yazmaktan kurtulmak için)
kubectl config set-context --current --namespace=ecommerce
Redis deployment’ı:
cat <<EOF | kubectl apply -f -
apiVersion: apps/v1
kind: Deployment
metadata:
name: redis
namespace: ecommerce
spec:
replicas: 1
selector:
matchLabels:
app: redis
template:
metadata:
labels:
app: redis
spec:
containers:
- name: redis
image: redis:7.0-alpine
ports:
- containerPort: 6379
resources:
requests:
memory: "128Mi"
cpu: "100m"
limits:
memory: "256Mi"
cpu: "200m"
---
apiVersion: v1
kind: Service
metadata:
name: redis-service
namespace: ecommerce
spec:
selector:
app: redis
ports:
- port: 6379
targetPort: 6379
EOF
API deployment’ı, Redis’e bağlanacak şekilde:
cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: Secret
metadata:
name: api-secrets
namespace: ecommerce
type: Opaque
stringData:
db-password: "supersecretpassword"
redis-url: "redis://redis-service:6379"
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: api
namespace: ecommerce
spec:
replicas: 2
selector:
matchLabels:
app: api
template:
metadata:
labels:
app: api
spec:
containers:
- name: api
image: mycompany/ecommerce-api:2.1
ports:
- containerPort: 3000
env:
- name: REDIS_URL
valueFrom:
secretKeyRef:
name: api-secrets
key: redis-url
- name: DB_PASSWORD
valueFrom:
secretKeyRef:
name: api-secrets
key: db-password
resources:
requests:
memory: "256Mi"
cpu: "500m"
limits:
memory: "512Mi"
cpu: "1000m"
---
apiVersion: v1
kind: Service
metadata:
name: api-service
namespace: ecommerce
spec:
selector:
app: api
type: LoadBalancer
ports:
- port: 80
targetPort: 3000
EOF
HorizontalPodAutoscaler ile Otomatik Ölçeklendirme
Trafik dalgalanmalarını manuel yönetmek yerine Kubernetes’in otomatik ölçeklendirmesinden faydalanabilirsiniz. HPA (HorizontalPodAutoscaler), CPU veya memory kullanımına göre pod sayısını otomatik artırıp azaltır.
cat <<EOF | kubectl apply -f -
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: api-hpa
namespace: ecommerce
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: api
minReplicas: 2
maxReplicas: 10
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 70
- type: Resource
resource:
name: memory
target:
type: Utilization
averageUtilization: 80
EOF
HPA’nın durumunu izlemek için:
kubectl get hpa -n ecommerce
kubectl describe hpa api-hpa -n ecommerce
ConfigMap ile Konfigürasyon Yönetimi
Uygulama konfigürasyonlarını image içine gömmek yerine ConfigMap kullanmak çok daha esnek bir yaklaşım.
cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: ConfigMap
metadata:
name: api-config
namespace: ecommerce
data:
app.properties: |
log.level=INFO
cache.ttl=3600
max.connections=100
ENVIRONMENT: "production"
LOG_LEVEL: "INFO"
EOF
Bu ConfigMap’i deployment’ınızda hem environment variable hem de volume mount olarak kullanabilirsiniz. Environment variable olarak kullanmak için:
# Deployment spec.containers altına eklenecek kısım
# env:
# - name: ENVIRONMENT
# valueFrom:
# configMapKeyRef:
# name: api-config
# key: ENVIRONMENT
# Mevcut configmap'i güncellemek
kubectl edit configmap api-config -n ecommerce
# ConfigMap içeriğini görüntülemek
kubectl get configmap api-config -n ecommerce -o yaml
Kubectl ile Verimli Çalışma İpuçları
Günlük hayatta çok işe yarayan bazı komutlar:
# Tüm kaynakların özetini görmek
kubectl get all -n ecommerce
# Bir node'un kaynak kullanımını görmek (metrics-server kurulu olmalı)
kubectl top nodes
kubectl top pods -n ecommerce
# Pod'un önceki loglarına bakmak (crash sonrası debug için)
kubectl logs --previous pod-adı -n ecommerce
# Belirli label'a sahip pod'ları silmek
kubectl delete pods -l app=api -n ecommerce
# Deployment'ı geçici olarak durdurmak (0 replica)
kubectl scale deployment api --replicas=0 -n ecommerce
# Tüm cluster olaylarını izlemek
kubectl get events --sort-by='.lastTimestamp' -n ecommerce
# Kaynakları YAML formatında dışa aktarmak
kubectl get deployment api -n ecommerce -o yaml > api-deployment.yaml
# Değişiklik yapmadan ne olacağını görmek (dry-run)
kubectl apply -f deployment.yaml --dry-run=client
Yaygın Hatalar ve Çözümleri
Pod sürekli “CrashLoopBackOff” durumuna giriyorsa, önce logları kontrol edin:
kubectl logs pod-adı -n namespace --previous
kubectl describe pod pod-adı -n namespace
Genellikle sebebi şunlardan biri: uygulama hata verip çıkıyor, liveness probe yanlış konfigüre edilmiş, gerekli environment variable veya secret eksik.
“Pending” durumunda kalan pod’lar için describe çıktısının Events kısmına bakın. Sık karşılaşılan sebepler: yetersiz kaynak (CPU/memory), node selector veya affinity kurallarının eşleşmemesi, PersistentVolume beklemesi.
ImagePullBackOff hatası genellikle image adının yanlış yazılması, private registry için pull secret eksikliği veya image tag’inin mevcut olmamasından kaynaklanır.
Local Geliştirme Ortamı Kurulumu
Kubernetes’i öğrenmek için production cluster’ına ihtiyacınız yok. Birkaç seçeneğiniz var:
- minikube: En popüler local Kubernetes. Tek komutla ayağa kalkıyor.
- kind (Kubernetes in Docker): Docker container’ları içinde çalışan cluster. CI/CD pipeline’ları için ideal.
- k3s: Hafif Kubernetes dağıtımı. Raspberry Pi veya edge computing için de kullanılıyor.
minikube ile hızlı başlangıç:
# minikube kurulumu (Linux)
curl -LO https://storage.googleapis.com/minikube/releases/latest/minikube-linux-amd64
sudo install minikube-linux-amd64 /usr/local/bin/minikube
# Cluster başlatmak
minikube start --cpus=2 --memory=4096
# Dashboard açmak
minikube dashboard
# LoadBalancer service'lere local erişim için
minikube tunnel
# Cluster durumunu kontrol etmek
minikube status
kubectl cluster-info
Kubernetes’te Güvenlik Temelleri
Üretime gitmeden önce bazı temel güvenlik önlemlerini almanız şart.
RBAC (Role-Based Access Control) ile kullanıcı ve servis hesaplarının yetkilerini sınırlayın. “Least privilege” prensibini uygulayın.
Network Policy ile pod’lar arası ağ trafiğini kontrol edin. Varsayılan olarak her pod her pod ile konuşabilir, bu production’da kabul edilemez.
Resource limit belirlemeyin. Limitsiz bırakılan bir pod tüm node kaynaklarını tüketebilir.
Container’ları root olmayan kullanıcıyla çalıştırın. Pod spec’ine securityContext ekleyin:
# Deployment spec.template.spec altına eklenecek
# securityContext:
# runAsNonRoot: true
# runAsUser: 1000
# fsGroup: 2000
Sonuç
Kubernetes ilk bakışta karmaşık görünüyor ve bu izlenim yalan değil. Gerçekten dik bir öğrenme eğrisi var. Ama birkaç temel kavramı kavradıktan sonra, yani pod, deployment, service ve namespace’i anladıktan sonra geri kalanı üzerine inşa edilebilir hale geliyor.
Benim tavsiyem şu: minikube veya kind ile local ortam kurun, bu yazıdaki örnekleri sırayla deneyin, her şeyin nasıl çalıştığını gözlemleyin. Kubernetes’i sadece okuyarak öğrenmek mümkün değil, ellerin klavyede olması lazım.
Sonraki adım olarak Ingress kaynaklarını, PersistentVolume yönetimini ve Helm chart’larını incelemenizi öneririm. Helm özellikle production ortamlarında uygulama paketleme ve versiyon yönetimini inanılmaz ölçüde kolaylaştırıyor.
Konteyner orkestrasyonu bir araç, amaç değil. Amacınız uygulamalarınızı güvenilir, ölçeklenebilir ve yönetilebilir şekilde çalıştırmak. Kubernetes bu amaca ulaşmak için bugün elinizde olan en güçlü araçlardan biri.