Kubernetes Deployment Stratejileri 2

A/B Testing

Deniz TÜRKMEN
5 min readMay 15, 2023

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.

--

--