Kubernetes Deployment Oluşturma, Güncelleme ve Silme Rehberi

Kubernetes ortamında en çok kullanılan kaynak türlerinden biri olan Deployment, uygulamalarınızı yönetmenin temel yapı taşıdır. Bir Deployment oluşturduğunuzda aslında Kubernetes’e “Bu uygulamadan şu kadar kopya çalıştır, bir şey olursa kendini düzelt” diyorsunuz. Bu yazıda Deployment’ların nasıl oluşturulduğunu, güncelleneceğini ve silineceğini gerçek dünya senaryolarıyla birlikte ele alacağız.

Deployment Nedir ve Neden Kullanılır?

Deployment, Pod’larınızı yönetmek için kullanılan bir Kubernetes nesnesidir. Doğrudan Pod oluşturabilirsiniz ama bunu yapmamanız gerekir. Neden mi? Çünkü bir Pod öldüğünde kimse onu diriltmez. Deployment ise sizin için ReplicaSet oluşturur ve ReplicaSet de belirttiğiniz sayıda Pod’un her zaman ayakta olmasını garantiler.

Gerçek hayattan bir örnek düşünelim: Bir e-ticaret uygulaması çalıştırıyorsunuz. Gecenin ikisinde bir Pod crash oluyor. Deployment olmadan sabah işe gelene kadar kullanıcılar hata görür. Deployment ile birkaç saniye içinde yeni bir Pod ayağa kalkar, kimse fark etmez bile.

Deployment’ın sağladığı temel avantajlar şunlardır:

  • Self-healing: Ölen Pod’lar otomatik yeniden başlatılır
  • Scaling: İstediğiniz zaman Pod sayısını artırıp azaltabilirsiniz
  • Rolling Update: Sıfır downtime ile güncelleme yapabilirsiniz
  • Rollback: Bir şeyler ters giderse önceki versiyona dönebilirsiniz

İlk Deployment’ı Oluşturmak

YAML ile Deployment Oluşturma

Deployment oluşturmanın en iyi yolu YAML dosyası kullanmaktır. Komut satırından da oluşturabilirsiniz ama YAML tercih edilir çünkü versiyonlayabilirsiniz, Git’e koyabilirsiniz ve tekrar kullanabilirsiniz.

Basit bir nginx Deployment örneği:

cat <<EOF > nginx-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
  namespace: default
  labels:
    app: nginx
    environment: production
spec:
  replicas: 3
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:1.24
        ports:
        - containerPort: 80
        resources:
          requests:
            memory: "64Mi"
            cpu: "250m"
          limits:
            memory: "128Mi"
            cpu: "500m"
EOF

YAML’ı yazdıktan sonra cluster’a uygulayın:

kubectl apply -f nginx-deployment.yaml

Deployment’ın durumunu kontrol edin:

kubectl get deployment nginx-deployment
kubectl get pods -l app=nginx
kubectl describe deployment nginx-deployment

kubectl describe komutu size Deployment’ın tüm detaylarını gösterir. Event’lara özellikle dikkat edin, sorun yaşandığında ilk bakacağınız yer burasıdır.

Komut Satırından Hızlı Deployment

Bazen test ortamında hızlıca bir şeyler denemek istiyorsunuz. O zaman imperative yaklaşımı kullanabilirsiniz:

kubectl create deployment test-app 
  --image=nginx:1.24 
  --replicas=2 
  --port=80

Ancak bu yöntemi production’da kullanmayın. YAML’ı oluşturmak için dry-run kullanabilirsiniz:

kubectl create deployment test-app 
  --image=nginx:1.24 
  --replicas=2 
  --dry-run=client 
  -o yaml > test-app-deployment.yaml

Bu komut gerçekten bir Deployment oluşturmaz, sadece YAML çıktısı üretir. Bu çıktıyı düzenleyip kubectl apply ile kullanabilirsiniz. Çok pratik bir yöntemdir.

Deployment’ı Güncelleme

Güncelleme işlemleri Deployment’ın en kritik özelliklerinden biridir. Kubernetes varsayılan olarak RollingUpdate stratejisini kullanır. Bu strateji eski Pod’ları yavaş yavaş kapatırken yenilerini ayağa kaldırır. Böylece güncelleme sırasında uygulamanız çalışmaya devam eder.

Image Güncellemesi

En sık yapılan güncelleme türü image değiştirmektir. Yeni bir versiyon çıktığında bunu birkaç farklı şekilde yapabilirsiniz.

YAML’ı düzenleyip apply etmek:

# nginx-deployment.yaml dosyasında image satırını değiştirin
# image: nginx:1.24  -->  image: nginx:1.25

kubectl apply -f nginx-deployment.yaml

Komut satırından doğrudan güncellemek:

kubectl set image deployment/nginx-deployment nginx=nginx:1.25

Güncelleme durumunu takip etmek:

kubectl rollout status deployment/nginx-deployment

Bu komut güncelleme tamamlanana kadar bekler ve sonucu gösterir. CI/CD pipeline’larında bu komutu kullanarak deployment’ın başarılı olup olmadığını kontrol edebilirsiniz.

Replica Sayısını Değiştirme

Uygulamanıza gelen trafik arttığında Pod sayısını artırmanız gerekir. Bunu yapmak çok basittir:

# Komut satırından scale etmek
kubectl scale deployment nginx-deployment --replicas=5

# YAML'dan scale etmek (replicas: 5 yapıp apply et)
kubectl apply -f nginx-deployment.yaml

Gerçek dünya senaryosu olarak düşünün: Black Friday yaklaşıyor ve normalde 3 replica ile çalışan uygulamanızı 10 replica’ya çıkarmanız gerekiyor. Tek bir komutla bunu yapabilirsiniz.

Rolling Update Stratejisini Yapılandırma

Deployment’ınızın güncelleme davranışını kontrol etmek için strategy bölümünü kullanırsınız:

cat <<EOF > nginx-deployment-v2.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
  namespace: default
spec:
  replicas: 5
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxSurge: 2
      maxUnavailable: 1
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
        version: "1.25"
    spec:
      containers:
      - name: nginx
        image: nginx:1.25
        ports:
        - containerPort: 80
        readinessProbe:
          httpGet:
            path: /
            port: 80
          initialDelaySeconds: 5
          periodSeconds: 3
        livenessProbe:
          httpGet:
            path: /
            port: 80
          initialDelaySeconds: 10
          periodSeconds: 5
EOF

kubectl apply -f nginx-deployment-v2.yaml

Bu YAML’da dikkat etmeniz gereken birkaç nokta var:

  • maxSurge: 2: Güncelleme sırasında istenen replica sayısının kaç tane üzerinde Pod oluşturulabileceği. 5 replica’nız varsa güncelleme sırasında 7 Pod olabilir
  • maxUnavailable: 1: Güncelleme sırasında en fazla kaç Pod kapalı olabilir
  • readinessProbe: Pod’un trafiğe hazır olup olmadığını kontrol eder. Bu çok önemli! Probe başarısız olursa rolling update durur ve eskiler kapatılmaz
  • livenessProbe: Pod’un sağlıklı çalışıp çalışmadığını kontrol eder. Başarısız olursa Pod restart edilir

Readiness probe olmadan rolling update sırasında ciddi sorunlar yaşayabilirsiniz. Yeni Pod ayağa kalktı ama uygulama henüz başlamadı, Kubernetes trafiği oraya yönlendirdi ve kullanıcılar hata aldı. Bu senaryoyu mutlaka önleyin.

Recreate Stratejisi

Eğer uygulamanız aynı anda iki versiyon çalışamıyorsa (örneğin database migration gerektiren durumlar) Recreate stratejisini kullanabilirsiniz. Bu strateji önce tüm eski Pod’ları kapatır, sonra yenileri başlatır. Kısa süreli downtime oluşur ama tutarsız durum yaşanmaz:

spec:
  strategy:
    type: Recreate

Rollback İşlemleri

Güncelleme yaptınız, bir şeyler ters gitti. Panik yapmayın. Kubernetes’in rollback özelliği tam bu durumlar için var.

# Son yapılan güncellemeyi geri al
kubectl rollout undo deployment/nginx-deployment

# Belirli bir versiyona geri dön
kubectl rollout history deployment/nginx-deployment
kubectl rollout undo deployment/nginx-deployment --to-revision=2

Rollout geçmişini daha detaylı görmek için:

kubectl rollout history deployment/nginx-deployment --revision=2

Bu komut size o revision’da hangi image kullanıldığını ve ne zaman güncellendiğini gösterir.

Gerçek bir senaryo: Gece 23:00’de yeni versiyon deploy ettiniz. Dakikalar içinde alarm sisteminiz hata oranının yükseldiğini bildirdi. Siz de hemen rollback yaptınız:

kubectl rollout undo deployment/nginx-deployment
kubectl rollout status deployment/nginx-deployment

İki dakika içinde eski versiyona döndünüz ve kullanıcı etkisi minimuma indi.

Rollout geçmişinin tutulması için --record bayrağını kullanabilirsiniz ama bu bayrak deprecated oldu. Bunun yerine annotation kullanın:

kubectl annotate deployment nginx-deployment 
  kubernetes.io/change-cause="nginx 1.24 to 1.25 upgrade"

Deployment’a Environment Variable ve ConfigMap Ekleme

Production’da uygulamalarınız genellikle ortam değişkenlerine ihtiyaç duyar. Bunları doğrudan YAML’a yazmak yerine ConfigMap kullanmak daha sağlıklıdır:

# Önce ConfigMap oluşturun
kubectl create configmap app-config 
  --from-literal=APP_ENV=production 
  --from-literal=LOG_LEVEL=info 
  --from-literal=MAX_CONNECTIONS=100

# Deployment YAML'ında ConfigMap'i kullanın
cat <<EOF > app-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: myapp-deployment
spec:
  replicas: 3
  selector:
    matchLabels:
      app: myapp
  template:
    metadata:
      labels:
        app: myapp
    spec:
      containers:
      - name: myapp
        image: myapp:2.1.0
        envFrom:
        - configMapRef:
            name: app-config
        env:
        - name: POD_NAME
          valueFrom:
            fieldRef:
              fieldPath: metadata.name
        - name: NODE_NAME
          valueFrom:
            fieldRef:
              fieldPath: spec.nodeName
EOF

kubectl apply -f app-deployment.yaml

POD_NAME ve NODE_NAME değişkenlerini uygulamanızın log’larında kullanmak, hangi Pod’dan hangi log geldiğini anlamak için çok işe yarar.

Deployment Silme

Silme işlemi basit ama dikkatli yapılması gereken bir operasyondur. Bir Deployment’ı sildiğinizde bağlı tüm ReplicaSet’ler ve Pod’lar da silinir.

# YAML ile silme (önerilen yöntem)
kubectl delete -f nginx-deployment.yaml

# İsim ile silme
kubectl delete deployment nginx-deployment

# Belirli bir namespace'deki tüm deployment'ları silme
kubectl delete deployments --all -n test-namespace

# Label selector ile silme
kubectl delete deployment -l environment=test

Label selector ile silme özellikle faydalıdır. Test ortamınızdaki tüm kaynakları temizlemeniz gerektiğinde:

kubectl delete all -l environment=test -n test-namespace

Bu komut Pod’ları, Service’leri, ReplicaSet’leri hepsini siler. Dikkatli kullanın.

Silmeden Önce Kontrol

Production’da silme işlemi yapmadan önce mutlaka şunları kontrol edin:

# Deployment'a bağlı Service var mı?
kubectl get service -l app=nginx

# Deployment'ın Pod'larına bağlı PVC var mı?
kubectl get pvc -n default

# Deployment'ı kullanan HPA (HorizontalPodAutoscaler) var mı?
kubectl get hpa -l app=nginx

HPA’yı silmeden önce Deployment’ı silerseniz HPA orphan kalır. Kubernetes bu durumu tolere eder ama temiz bir cluster için önce HPA’yı, sonra Deployment’ı silmek daha iyidir.

Deployment’ı Dondurma ve Sürdürme

Bazen güncelleme yapmak istiyorsunuz ama hemen uygulanmasını istemiyorsunuz. Birden fazla değişiklik yapacaksanız her birinde rolling update tetiklenmesini önlemek için pause kullanabilirsiniz:

# Deployment'ı dondur
kubectl rollout pause deployment/nginx-deployment

# İstediğiniz değişiklikleri yapın
kubectl set image deployment/nginx-deployment nginx=nginx:1.25
kubectl set resources deployment/nginx-deployment 
  -c nginx 
  --limits=cpu=500m,memory=256Mi

# Değişiklikleri uygula
kubectl rollout resume deployment/nginx-deployment

Bu yöntem özellikle birden fazla container içeren Deployment’larda çok işe yarar.

Deployment Sorunlarını Giderme

Gerçek hayatta en çok karşılaşılan durumlardan biri Deployment’ın beklenen replica sayısına ulaşamamasıdır.

# Deployment durumunu detaylı incele
kubectl describe deployment nginx-deployment

# Pod'ların neden başlamadığını bul
kubectl get pods -l app=nginx
kubectl describe pod nginx-deployment-xxxx-yyyy

# Pod loglarına bak
kubectl logs nginx-deployment-xxxx-yyyy
kubectl logs nginx-deployment-xxxx-yyyy --previous

# Event'lara bak
kubectl get events --sort-by=.metadata.creationTimestamp -n default

Yaygın sorunlar ve çözümleri:

  • ImagePullBackOff: Image adı yanlış veya registry credentials eksik. kubectl describe pod ile detay alın, imagePullSecrets eklemeyi deneyin
  • CrashLoopBackOff: Uygulama başlayıp hemen kapanıyor. kubectl logs --previous ile son crash log’larına bakın
  • Pending: Node’larda yeterli kaynak yok. kubectl describe pod ile neden schedule edilemediğini görün
  • OOMKilled: Memory limiti aşıldı. Resource limit’leri artırın veya memory leak’i düzeltin

Bir Deployment’ın neden stuck kaldığını anlamak için:

kubectl rollout status deployment/nginx-deployment --timeout=60s

Bu komut 60 saniye bekler, başarılı olmazsa hata verir. Bu çıktıyı CI/CD pipeline’ınızda deployment başarısını kontrol etmek için kullanabilirsiniz.

Production’da Deployment Best Practice’leri

Yıllarca Kubernetes cluster’ı yönettikten sonra öğrendiğim bazı pratikler var:

  • Resource request ve limit her zaman tanımlayın: Tanımlamazsanız bir Pod tüm node kaynaklarını tüketebilir ve diğer Pod’lar evict edilir
  • Pod Disruption Budget (PDB) kullanın: Node maintenance sırasında tüm Pod’larınızın aynı anda silinmesini önler
  • Readiness ve liveness probe zorunlu: Bu ikisi olmadan güvenilir bir deployment yapamazsınız
  • Anti-affinity kuralları ekleyin: Aynı uygulamanın Pod’larının farklı node’lara dağılmasını sağlar, tek node öldüğünde tüm uygulamanın çökmesini önler
  • Image tag olarak latest kullanmayın: Her zaman belirli bir versiyon tag’ı kullanın, aksi halde hangi versiyonun çalıştığını bilemezsiniz
  • Namespace kullanın: Tüm uygulamaları default namespace’e koymayın, ayrıştırın

PDB örneği:

cat <<EOF | kubectl apply -f -
apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
  name: nginx-pdb
spec:
  minAvailable: 2
  selector:
    matchLabels:
      app: nginx
EOF

Bu PDB, en az 2 nginx Pod’unun her zaman ayakta kalmasını garanti eder. Node drain işlemi sırasında Kubernetes bu kurala uyar.

Sonuç

Deployment, Kubernetes’in en temel ve en güçlü kaynaklarından biridir. Bu yazıda oluşturma, güncelleme ve silme adımlarını detaylı olarak ele aldık. Ancak asıl öğrenme gerçek ortamda yaşanan deneyimlerle olur.

Özetlemek gerekirse:

  • YAML’larınızı Git’te tutun, her değişikliği kubectl apply ile yapın
  • Rolling update stratejisini uygulamanızın özelliklerine göre yapılandırın
  • Readiness probe olmadan production’a deployment yapmayın
  • Resource limit’leri her zaman tanımlayın
  • Sorun çıktığında kubectl describe, kubectl logs ve kubectl get events sizin en iyi arkadaşlarınız olacak

Kubernetes öğrenme eğrisi başta sarp görünebilir ama Deployment kavramını iyi anladıktan sonra diğer kaynaklar çok daha kolay oturur. StatefulSet, DaemonSet gibi diğer workload türleri de aynı mantık üzerine kuruludur, sadece farklı use case’leri ele alırlar.

Yorum yapın