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 podile detay alın, imagePullSecrets eklemeyi deneyin - CrashLoopBackOff: Uygulama başlayıp hemen kapanıyor.
kubectl logs --previousile son crash log’larına bakın - Pending: Node’larda yeterli kaynak yok.
kubectl describe podile 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
latestkullanmayın: Her zaman belirli bir versiyon tag’ı kullanın, aksi halde hangi versiyonun çalıştığını bilemezsiniz - Namespace kullanın: Tüm uygulamaları
defaultnamespace’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 applyile 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 logsvekubectl get eventssizin 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.