Kubernetes Deployment Stratejileri 4

Canary

Deniz TÜRKMEN
5 min readJun 6, 2023

Merhabalar,

Bu yazımda kubernetes de kullanılan deployment stratejilerinden canary deployment’ı inceliycez. Ilk olarak nedir ne amaçla kullanılır buna bakalım.

Canary Deployment: Canary relasease, üretime aşamalar halinde yeni bir kod veya yapılandırma değişikliği sunarak riski yönetmenin bir yoludur. Canary relasease, yeni bir değişikliğin küçük bir yüzdesini kullanıcılarınızın bir alt kümesine dağıttığınız çok aşamalı kullanıma sunmanın ilk aşamasıdır. Bir canary sürümü, temel olarak riski en aza indirmenize yardımcı olabilecek kontrollü bir sürümdür. Canary relasease stratejisi, her kullanıcıyı etkilemeden üretimdeki yeni bir kod değişikliğini test etmek için idealdir. Kuruluşların yeni özellikleri genel kullanıcı tabanlarının küçük bir yüzdesine dağıtmasına ve potansiyel sorunları ve ilk yanıtları/geri bildirimleri belirlemek için davranışlarını izlemesine olanak sağlar. Her şey yolunda görünüyorsa organizasyonlar, kullanıcılarının daha önemli bir yüzdesine multi-stage bir sürümle devam edebilir. Geliştiriciler tarafından yeni sürümlerin uygulamada hiçbir şeyi bozmadığından emin olmak için kullanılan bir teknikti.

Şimdide örneğimize başlayalım. Örneğimizi minikube cluster’ımız üzerinde gerçekleştircez.

Minikube cluster’ımızı başlatmak için;

minikube start --cpus=4 --memory=8192

Ingress aktifleştirelim. Bunun için minikune ingress addons enable edelim. Addons ismine baklamk için;

minikube addons list

Ingress aktif etmek için,

minikube addons enable ingress

Ilk olarak bir tane canary namespace oluşturalım.

Kontrol etmek için;

kubectl get ns

Version_1 deployment’ımız için configmap, deployment ve service manifest’lerine oluşturalım.

apiVersion: v1
kind: ConfigMap
metadata:
name: version-1
namespace: canary
data:
index.html: |
version_1
---
apiVersion: v1
kind: Service
metadata:
name: web-svc-v1
namespace: canary
labels:
app: v1
spec:
type: ClusterIP
selector:
app: v1
ports:
- protocol: TCP
port: 80
targetPort: 80
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: web-version-1
namespace: canary
labels:
app: v1
spec:
replicas: 1
strategy:
rollingUpdate:
maxSurge: 1
maxUnavailable: 0
type: RollingUpdate
selector:
matchLabels:
app: v1
template:
metadata:
labels:
app: v1
spec:
volumes:
- name: version-1
configMap:
name: version-1
containers:
- name: version-1
image: nginx
imagePullPolicy: IfNotPresent
ports:
- containerPort: 80
resources:
limits:
cpu: 500m
memory: 500Mi
requests:
cpu: 50m
memory: 100Mi
readinessProbe:
failureThreshold: 1
periodSeconds: 5
timeoutSeconds: 1
successThreshold: 1
tcpSocket:
port: 80
livenessProbe:
failureThreshold: 3
httpGet:
path: /
port: 80
scheme: HTTP
periodSeconds: 10
successThreshold: 1
timeoutSeconds: 5
startupProbe:
failureThreshold: 10
httpGet:
path: /
port: 80
scheme: HTTP
periodSeconds: 10
successThreshold: 1
timeoutSeconds: 5
volumeMounts:
- name: version-1
mountPath: /usr/share/nginx/html
---
kubectl apply -f v1-dep-svc.yaml 

kubectl get pods,svc -n canary

Version_2 deployment’ımız için configmap, deployment ve service manifest’lerine oluşturalım.

apiVersion: v1
kind: ConfigMap
metadata:
name: version-2
namespace: canary
data:
index.html: |
version_2
---
apiVersion: v1
kind: Service
metadata:
name: web-svc-v2
namespace: canary
labels:
app: v2
spec:
type: ClusterIP
selector:
app: v2
ports:
- protocol: TCP
port: 80
targetPort: 80
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: web-version-2
namespace: canary
labels:
app: v2
spec:
replicas: 1
strategy:
rollingUpdate:
maxSurge: 1
maxUnavailable: 0
type: RollingUpdate
selector:
matchLabels:
app: v2
template:
metadata:
labels:
app: v2
spec:
volumes:
- name: version-2
configMap:
name: version-2
containers:
- name: version-2
image: nginx
imagePullPolicy: IfNotPresent
ports:
- containerPort: 80
resources:
limits:
cpu: 500m
memory: 500Mi
requests:
cpu: 50m
memory: 100Mi
readinessProbe:
failureThreshold: 1
periodSeconds: 5
timeoutSeconds: 1
successThreshold: 1
tcpSocket:
port: 80
livenessProbe:
failureThreshold: 3
httpGet:
path: /
port: 80
scheme: HTTP
periodSeconds: 10
successThreshold: 1
timeoutSeconds: 5
startupProbe:
failureThreshold: 10
httpGet:
path: /
port: 80
scheme: HTTP
periodSeconds: 10
successThreshold: 1
timeoutSeconds: 5
volumeMounts:
- name: version-2
mountPath: /usr/share/nginx/html
---
kubectl apply -f v2-dep-svc.yaml 

kubectl get pods,svc -n canary

version_1 ve version_2 deployment başarılı şekilde gerçekleştirdik. ClusterIP türünde olduğu için pod’un içerisindeki container’ın çıktısına bakmak için port-forword yararlanabiliriz.

kubectl port-forward -n namespace pods/pod_name host_port:container_port

kubectl port-forward -n canary pods/web-version-1-5f957cc79c-qmnkx 5000:80

kubectl port-forward -n canary pods/web-version-2-dc474bdb6-j9dkx 5001:80

Şimdide ingress deployment’larını yapalım.

  • Version_1 için;
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: ing-web-v1
namespace: canary
labels:
app: v1
spec:
ingressClassName: nginx
rules:
- host: web-canary.com
http:
paths:
- backend:
service:
name: web-svc-v1
port:
number: 80
path: /
pathType: Prefix
kubectl apply -f ingress-v1.yaml
  • Version_2 için;
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: ing-web-v2
namespace: canary
labels:
app: v2
annotations:
nginx.ingress.kubernetes.io/canary: "true"
nginx.ingress.kubernetes.io/canary-weight: "50"
spec:
ingressClassName: nginx
rules:
- host: web-canary.com
http:
paths:
- backend:
service:
name: web-svc-v2
port:
number: 80
path: /
pathType: Prefix
kubectl apply -f ingress-v2.yaml

Kontrol için;

kubectl get ingress -n canary

Görüldüğü gibi iki ingress’in host’unu aynı fakat canary deployment belirtmek için annotions ‘a;

nginx.ingress.kubernetes.io/canary: "true"
nginx.ingress.kubernetes.io/canary-weight: "50"

Weight 50 olduğu için şuan version_1 ve version_2 yarı yarıya trafik yönlenecek. Kontrol için;

Ama öncesinde etc/hosts host’u ekleyelim.

minikube ip

192.168.49.2 web-canary.com
while true; do curl http://web-canary.com && sleep 1 && echo ""; done;

Görüldüğü gibi trafik version_1 ve version_2 arasında gidip geliyor. Şimdide tüm trafiği version_2 yönlendirelim. Bunun için version_2 ingressindeki weight 100 yapıp tekrar deployment yapalım.

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: ing-web-v2
namespace: canary
labels:
app: v2
annotations:
nginx.ingress.kubernetes.io/canary: "true"
nginx.ingress.kubernetes.io/canary-weight: "100"
spec:
ingressClassName: nginx
rules:
- host: web-canary.com
http:
paths:
- backend:
service:
name: web-svc-v2
port:
number: 80
path: /
pathType: Prefix
kubectl apply -f ingress-v2.yaml

Ingress deploy ettikten sonra tekrar script’i çalıştırdığımızda;

Yukarıdaki çıktıda görüldüğü gibi trafik sadece version_2 gitmektedir.

--

--