Contents

Canary Deployment dan Mirroring Dengan Traefik

Saat kita melakukan deployment aplikasi ke versi terbaru pada Kubernetes, mungkin muncul kecemasan akan adanya insiden tak terduga walaupun versi terbaru sudah lolos tahap testing. Guna mengurangi kemungkinan insiden dalam skala besar, kita dapat memakai skenario bernama Canary.

Canary Idiom

Frasa Canary dalam deployment aplikasi berasal dari sejarah penambang batu bara di awal abad 20. Pekerja tambang membawa burung kenari dalam sangkar ke terowongan bawah tanah, sehingga ketika muncul gas berbahaya seperti karbon monoksida maka burung kenari akan mati dan menjadi peringatan bagi para pekerja untuk segera evakuasi.

Kubernetes’s Canary

Fitur canary pada Kubernetes biasanya tersedia jika kita menggunakan solusi service mesh. Namun sebenarnya canary dapat diimplementasikan tanpanya. Sebagai contohnya adalah menggunakan Ingress Nginx, HAProxy Ingress, hingga Traefik. Jika tertarik, silahkan cari Kubernetes Ingress Controller lainnya yang mendukung fitur canary pada tabel berikut.

Traefik

Traefik adalah Cloud Native Edge Router salah satu reverse proxy dan load balancer. Terlepas dari gimmick cloud-native, yang menjadikan Traefik berbeda dari Nginx, HAproxy, dan yang lain adalah tersedianya configurability secara otomatis dan dinamis. Bagian paling menonjol darinya mungkin adalah kemampuan automatic service discovery. Jika kita menggunakan Traefik di atas Docker, Kubernetes, atau bahkan cara lama seperti sekedar VM dan bare-metal untuk menjajakan service yang berjalan di dalamnya. Layaknya sulap, Traefik akan me-expose service tersebut ke dunia luar. Tentu jika kita mengikuti dokumentasi dengan benar.

/canary-deployment-dan-mirroring-dengan-traefik/traefik-v2-high-level-arch.png
Traefik V2


Prerequisites

Untuk mempersingkat artikel ini, maka saya anggap beberapa hal ini sudah terpenuhi.

  1. Kubernetes cluster telah tersedia.
  2. Traefik sudah terpasang pada Kubernetes.
  3. Pemahaman mengenai Ingress, Service, dan Deployment pada Kubernetes.

Scenario

Tanpa Canary

/canary-deployment-dan-mirroring-dengan-traefik/existing-release.png
Existing release
Pada contoh di atas, terlihat saya mempunyai sebuah service dengan aplikasi versi pertama yang anggaplah sudah mengudara dan menerima request dari user. Kurang lebih seperti inilah bagaimana service tersebut dapat berjalan.

1
2
kubectl create deployment deployment-app-current --image=trianwar/hello-app:1.0 -n default
kubectl expose deployment deployment-app-current --name service-app-current --type ClusterIP --port 8080 -n default

Selanjutnya kita buat sebuah IngressRoute dengan Traefik.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
apiVersion: traefik.containo.us/v1alpha1
kind: IngressRoute
metadata:
  name: ingressroute-app
spec:
  entryPoints:
  - web
  routes:
  - kind: Rule
    match: Host(`app.minikube1.local`)
    services:
    - name: service-app-current
      namespace: default
      port: 8080

Simpan misalnya dengan nama ingressroute-app.yaml dan terapkan konfigurasi di atas

1
kubectl create -f ingressroute-app.yam -n default

Jika dilakukan request dengan curl maka akan menjawab seperti berikut.

/canary-deployment-dan-mirroring-dengan-traefik/without-canary.png
Trafik diarahkan ke versi aplikasi pertama
Dari sini mari kita berasumsi bahwa aplikasi kita telah menerima aliran trafik sepenuhnya. Lalu suatu ketika saya ingin melakukan merilis versi aplikasi kedua.

1
2
kubectl set image deployment/deployment-app-current hello-app=trianwar/hello-app:2.0 -n default
kubectl rollout restart deployment/deployment-app-current -n default

Kita dapat melakukan rolling release ke versi terbaru tanpa canary, yang hasilnya tentu saja trafik akan sepenuhnya dialirkan ke satu-satunya rilis yang tersedia yaitu misalkan versi 2.0.0 seperti berikut.

/canary-deployment-dan-mirroring-dengan-traefik/without-canary-result.png
Trafik diarahkan ke versi aplikasi kedua

Perhatian
Dari sini, lebih baiknya kita kembalikan image tag dari deployment-app-current ke versi 1.0.0 agar praktik selanjutnya sesuai dengan skenario.

Weighted Canary

Alih - alih langsung mengganti rilis pertama ke versi terbaru sekaligus, di sini kita akan mendeploy aplikasi versi kedua sebagai rilisan baru. Dan selanjutnya kita manipulasi besaran traffic yang dialirkan.

/canary-deployment-dan-mirroring-dengan-traefik/weighted-canary.png
Weighted Canary
Untuk menggunakan fitur canary kita perlu memisahkan rilis terbaru ke deployment dan service baru. Besar aliran trafik akan kita tentukan dengan pembobotan. Pada diagram di atas, terlihat bahwa 80% traffic akan diarahkan ke versi pertama, sisanya sebesar 20% diarahkan ke versi kedua.

1
2
kubectl create deployment deployment-app-canary --image=trianwar/hello-app:2.0 -n default
kubectl expose deployment deployment-app-canary --name service-app-canary --type ClusterIP --port 8080 -n default

Kemudian modifikasi file manifest ingressroute-app.yaml tadi menjadi seperti berikut.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
apiVersion: traefik.containo.us/v1alpha1
kind: IngressRoute
metadata:
  name: ingressroute-app
spec:
  entryPoints:
  - web
  routes:
  - kind: Rule
    match: Host(`app.minikube1.local`)
    services:
    - name: service-app-current
      namespace: default
      port: 8080
      weight: 80
    - name: service-app-canary
      namespace: default
      port: 8080
      weight: 20

Jangan lupa kita terapkan perubahannya.

1
kubectl appy -f ingressroute-app.yaml

Mari kita jalankan 100 request dengan menggunakan curl seperti berikut.

1
for i in {1..100}; do curl -s app.minikube1.local | grep Version; done | sort | uniq -c

Akan terhitung bahwa trafik sebanyak 80% dialirkan ke aplikasi versi pertama, dan sisanya 20% ke versi kedua.

/canary-deployment-dan-mirroring-dengan-traefik/weighted-canary-result.png
Weighted Canary Result

Canary by Header

Semisal yang kita inginkan adalah melakukan canary namun bukan untuk end-user langsung, melainkan untuk kebutuhan testing. Traefik juga mendukung manipulasi trafik berdasarkan Request Header dengan menggunakan objek Middleware.

/canary-deployment-dan-mirroring-dengan-traefik/canary-by-header.png
Canary by Header

Contoh file manifest untuk membuat middleware adalah sebagai berikut, simpan dengan nama misalnya middleware-app-canary.yaml.

1
2
3
4
5
6
7
8
apiVersion: traefik.containo.us/v1alpha1
kind: Middleware
metadata:
  name: middleware-app-canary
spec:
  headers:
    customRequestHeaders:
      X-Canary: "enabled"

Kemudian modifikasi file ingressroute-app.yaml tadi menjadi seperti di bawah ini.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
apiVersion: traefik.containo.us/v1alpha1
kind: IngressRoute
metadata:
  name: ingressroute-app
spec:
  entryPoints:
  - web
  routes:
  - kind: Rule
    match: Host(`app.minikube1.local`)
    services:
    - name: service-app-current
      namespace: default
      port: 8080
  - kind: Rule
    match: Host(`app.minikube1.local`) && HeadersRegexp(`X-Canary`, `enabled`)
    services:
    - name: service-app-canary
      namespace: default
      port: 8080

Terapkan konfigurasi di atas pada Kubernetes.

1
kubectl apply -f middleware-app-canary.yaml -f ingressroute-app.yaml -n default

Sekarang mari kita lakukan pengujian dengan melakukan 10 request tanpa header, dan 10 request lagi dengan menggunakan header.

/canary-deployment-dan-mirroring-dengan-traefik/canary-by-header-result.png
Canary by Header result

Mirroring

Sekenario lainnya yang disediakan adalah melakukan mirroring atau shadowing.

/canary-deployment-dan-mirroring-dengan-traefik/traffic-mirroring.png
Traffic Mirroring

Selain dialirkan ke service - service canary tadi, Traefik juga dapat memanipulasi trafik yang lewat untuk menciptakan bayangannya, dan bayangan itu akan dialirkan ke service versi lain dengan persentase yang bisa ditentukan juga.

1
2
kubectl create deployment deployment-app-mirror --image=trianwar/hello-app:3.0 -n default
kubectl expose deployment deployment-app-mirror --name service-app-mirror --type ClusterIP --port 8080 -n default

Modifikasi file ingressroute-app.yaml yang telah dibuat sebelumnya.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
apiVersion: traefik.containo.us/v1alpha1
kind: IngressRoute
metadata:
  name: ingressroute-app
spec:
  entryPoints:
  - web
  routes:
  - kind: Rule
    match: Host(`app.minikube1.local`)
    services:
    - name: mirroring-app
      namespace: default
      kind: TraefikService

Untuk menerapkan mirroring, kita juga perlu membuat objek bertipe TraefikService (bukan kubernetes service, kali ini adalah Custom Resource Definition milik Traefik).

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
apiVersion: traefik.containo.us/v1alpha1
kind: TraefikService
metadata:
  name: canary-app
  namespace: default
spec:
  weighted:
    services:
      - name: service-app-current
        port: 8080
        weight: 80
      - name: service-app-canary
        weight: 20
        port: 8080

---
apiVersion: traefik.containo.us/v1alpha1
kind: TraefikService
metadata:
  name: mirroring-app
  namespace: default
spec:
  mirroring:
    name: canary-app
    kind: TraefikService
    mirrors:
      - name: service-app-mirror
        percent: 10
        port: 8080

Simpan saja misalnya dengan nama traefikservice-app.yaml kemudian terapkan ke kubernetes.

1
kubectl apply -f ingressroute-app.yaml -f traefikservice-app.yaml -n default

Lalu kita uji dengan melakukan 10 kali request.

1
for i in {1..10}; do curl -s app.minikube1.local | grep Version; done; kcmini logs $(kcmini get pods -l app=deployment-app-mirror -o name)

Akan terlihat bahwa rilis versi pertama menerima 8 request, sedangkan sisanya sebanyak 2 request ditangani oleh rilis versi kedua. Sementara itu, traffic sebanyak 10% atau dalam kasus ini setara 1 request dibuat bayangannya dan dialirkan ke rilis mirror.

/canary-deployment-dan-mirroring-dengan-traefik/mirror-traffic-result.png
Hasil Mirroring
Dengan mirroring service akan menerima bayangan request dari user, aplikasi akan melayaninya. Namun user tidak akan menerima balikan dari service mirror karena traffic yang mengalir hanyalah sebuah request bayangan.


Advantages

Beberapa manfaat yang kita peroleh dari penerapan canary dan traffic mirroring adalah sebagai berikut:

  1. Minimalisir resiko/insiden dari rilisan baru di environment production.
  2. Reduksi cost dan effort karena tidak perlu membangun cluster lain untuk environment pre-production.
  3. Mengalirkan sebagian kecil realtime traffic ke rilisan baru untuk testing.
  4. Mempercepat identifikasi terhadap Bug/Issue aplikasi.

References