Konteyner Orkestrasyon Nedir: Kubernetes’e Giriş

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.

Yorum yapın