Kubernetes Deployment Stratejileri 2
A/B Testing
Merhabalar,
Bu yazımda kubernetes de kullanılan deployment stratejisi olan A/B testing’i inceliycez.
A/B Testing deployment nedir veya biz nasıl kullanabiliriz ?
- A/B testing genellikle kullanıcı davranışlarını ilişkin toplanan verilere dayalı olarak alınır ve daha iyi business kararları almak için kullanılır.
- Kullanıcılar A/B testing periyotunda yeni eklenen feature genellikle haberdar değillerdir. Bu nedenlede gerçek test yapabilirler ve eski versiyon ile yeni versiyomu kullanan kullanıcılar arasındaki deneyimleri karşılaştırabilirler.
- Kubernetes A/B testing en önemli kullanılmasının sebebi yeni gelen bir özelliğin birkaç farklı seçeneğini test etmektir. Kullanıcılar gerekli testlerini yaptıktan sonra hangi çzellik veua versiyon ile devam edeceğin kararını verirler.
- A/B deployments istio yada flagger kullanılarak otomatikleştirebilirsiniz.
Ş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 namespace oluşturalım.
Kontrol etmek için;
kubectl get ns
Şimdide version1 için deployment,service ve configmap manifest’lermizi deploy yapalım.
apiVersion: v1
kind: ConfigMap
metadata:
name: version-1
namespace: abtesting
data:
index.html: |
<style>html,body{display:flex;align-items:center;justify-content:center;font-size:25vh}</style>
version_1
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: web-version-1
namespace: abtesting
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
---
apiVersion: v1
kind: Service
metadata:
name: web-svc-v1
namespace: abtesting
labels:
app: v1
spec:
type: ClusterIP
selector:
app: v1
ports:
- protocol: TCP
port: 80
targetPort: 80
Deployment ve service apply yapalım ve kontrol için;
kubectl apply -f version_1-dep-svc.yaml
kubectl get pods,svc,configmap -n abtesting
Şimdide version_2 için olan deployment, service ve configmap manifest’imiz deploy yapalım.
apiVersion: v1
kind: ConfigMap
metadata:
name: version-2
namespace: abtesting
data:
index.html: |
<style>html,body{display:flex;align-items:center;justify-content:center;font-size:25vh}</style>
version_2
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: web-version-2
namespace: abtesting
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
---
apiVersion: v1
kind: Service
metadata:
name: web-svc-v2
namespace: abtesting
labels:
app: v2
spec:
type: ClusterIP
selector:
app: v2
ports:
- protocol: TCP
port: 80
targetPort: 80
Deployment ve service apply yapalım ve kontrol için;
kubectl apply -f version_2-dep-svc.yaml
kubectl get pods,svc,configmap -n abtesting
Şimdi version_1 için olan ingress oluşturalım.
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: ing-web-v1
namespace: abtesting
labels:
app: v1
spec:
ingressClassName: nginx
# tls:
# - hosts:
# - ing-abtesting.com
rules:
- host: ing-abtesting.com
http:
paths:
- backend:
service:
name: web-svc-v1
port:
number: 80
path: /
pathType: Prefix
kubectl apply -f ingress-v1.yaml
kubectl get ingresses.networking.k8s.io -n abtesting
Note: Ingress içerisindeki host name’i localinizdeki /etc/hosts eklemelisiniz.
sudo vim /etc/hosts
Şimdi de version_2 için olan ingress manifest’imizi oluşturalım.
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: ing-web-v2
namespace: abtesting
labels:
app: v2
annotations:
nginx.ingress.kubernetes.io/canary: "true"
nginx.ingress.kubernetes.io/canary-weight: "50"
spec:
ingressClassName: nginx
# tls:
# - hosts:
# - ing-abtesting.com
rules:
- host: ing-abtesting.com
http:
paths:
- backend:
service:
name: web-svc-v2
port:
number: 80
path: /
pathType: Prefix
kubectl apply -f ingress-v2.yaml
kubectl get ingresses.networking.k8s.io -n abtesting
Görüldüğü gibi iki ingress aynı host’a gittiğiniz görüyoruz. Burada a/b testing aktif etmek için annotations ekleme yapıyoruz. Ingress türü nginx-ingress olduğu için burada nginx-ingress ile ilgili key-value çiftlerini giriyoruz.
nginx.ingress.kubernetes.io/canary: "true"
ve
nginx.ingress.kubernetes.io/canary-weight: "50"
Weight trafiğin hangi service oradan da hangi pod’a daha çok trafik veya daha az trafik gideceği beliriliyoruz. Şuan %50 olduğu için trafik yarı yarıya version_1 ve version_2 podunda gidip gelecektir. Kontrol için;
while true; do curl http://ing-abtesting.com && sleep 1 && echo ""; done;
Görüldüğü gibi trafik version_1 ve version_2 arasında ingress yönlendirme yapıyor. Şimdide tüm trafiği sadece version_2 yönlendirelim. Bunun için ingress içindeki weight %100 yapıp tekrar deploy edelim.
nginx.ingress.kubernetes.io/canary-weight: "100"
Evet görüldüğü gibi tüm trafik version_2 pod’una yönlendirmiş olduk.
Bu yazımızın da sonuna gelmiş bulunmaktayız. Araştırmalarım ve sektörde karşılaştığım senaryolar üzerine yazılarımı yazmaya devam edeceğim. Umarım faydalı bir yazı olmuştur. Yazımı okuduğunuz için teşekkürler.
Referanslar;