Canary Deployment w Kubernetes #1: Gitlab CI

Będziemy używać Gitlab CI oraz ręcznego GitOps do wdrożenia i wykorzystania Canary Deployment w Kubernetes.

Canary Deployment w Kubernetes #1: Gitlab CI

Artykuły z tego cyklu:

Canary deployment będziemy realizować ręcznie poprzez GitOps i tworzenie/zmienianie podstawowych zasobów Kubernetes. Artykuł ten jest przede wszystkim przeznaczony do zapoznania się z tym, jak działa Canary deployment w Kubernetes, ponieważ istnieją bardziej efektywne sposoby automatyzacji, które omówimy w następnych artykułach.


Canary Deployment w Kubernetes #1: Gitlab CI

https://www.norberteder.com/canary-deployment/

Canary Deployment

W strategii Canary najpierw aktualizacje są stosowane wyłącznie do części użytkowników. Poprzez monitorowanie, dane z logów, ręczne testowanie lub inne kanały informacji zwrotnej, wydanie jest testowane przed zastosowaniem dla wszystkich użytkowników.

Kubernetes Deployment (rolling update)

Domyślna strategia dla Kubernetes Deployment to rolling-update, gdzie uruchamiane jest określone ilość podów z nowymi wersjami obrazów. Jeśli zostały one utworzone bez problemów, pody ze starymi wersjami obrazów są kończone, a nowe pody są tworzone równolegle.

GitOps

Używamy GitOps w tym przykładzie, ponieważ:

  • używamy Git jako jedynego źródła prawdy,
  • używamy operacji Git do budowy i wdrożenia (nie są potrzebne żadne komendy, oprócz git tag/merge).

Przykład

Przyjmijmy dobrą praktykę — posiadanie jednego repozytorium dla kodu aplikacji i jednego dla infrastruktury.

Repozytorium dla aplikacji

To bardzo prosty interfejs API w Pythonie+Flask, który zwraca odpowiedź w formacie JSON. Zbudujemy paczkę za pomocą GitlabCI i wypchniemy wynik do Gitlab Registry. W rejestrze mamy dwie różne wersje wydań:

  • wuestkamp/k8s-deployment-example-app:v1
  • wuestkamp/k8s-deployment-example-app:v2

Jedyną różnicą między nimi jest zmiana zwracanego pliku JSON. Używamy tej aplikacji do maksymalnie prostego wizualizowania, z jaką wersją mamy do czynienia.

Repozytorium infrastrukturalne

W tym repozytorium będziemy wdrażać poprzez GitlabCI w Kubernetes, .gitlab-ci.yml wygląda następująco:

image: traherom/kustomize-docker

before_script:
   - printenv
   - kubectl version

stages:
 - deploy

deploy test:
   stage: deploy
   before_script:
     - echo $KUBECONFIG
   script:
     - kubectl get all
     - kubectl apply -f i/k8s

   only:
     - master

Aby go uruchomić samodzielnie, będziesz potrzebować klastra, możesz użyć Gcloud:

gcloud container clusters create canary --num-nodes 3 --zone europe-west3-b

gcloud compute firewall-rules create incoming-80 --allow tcp:80

Musisz zrobić fork https://gitlab.com/wuestkamp/k8s-deployment-example-canary-infrastructure i stworzyć zmienną KUBECONFIG w GitlabCI, która będzie zawierać konfigurację dostępu kubectl do twojego klastra.

O tym, jak uzyskać dane logowania do klastra (Gcloud), można przeczytać tutaj.

Infrastrukturalny Yaml

W repozytorium infrastrukturalnym mamy service:

apiVersion: v1
kind: Service
metadata:
 labels:
   id: app
 name: app
spec:
 ports:
 - port: 80
   protocol: TCP
   targetPort: 5000
 selector:
   id: app
 type: LoadBalancer

I deployment w deploy.yaml:

apiVersion: apps/v1
kind: Deployment
metadata:
 name: app
spec:
 replicas: 10
 selector:
   matchLabels:
     id: app
     type: main
 template:
   metadata:
     labels:
       id: app
       type: main
   spec:
     containers:
     - image: registry.gitlab.com/wuestkamp/k8s-deployment-example-app:v1
       name: app
       resources:
         limits:
           cpu: 100m
           memory: 100Mi

I inny deployment w deploy-canary.yaml:

kind: Deployment
metadata:
 name: app-canary
spec:
 replicas: 0
 selector:
   matchLabels:
     id: app
     type: canary
 template:
   metadata:
     labels:
       id: app
       type: canary
   spec:
     containers:
     - image: registry.gitlab.com/wuestkamp/k8s-deployment-example-app:v2
       name: app
       resources:
         limits:
           cpu: 100m
           memory: 100Mi

Zauważ, że app-deploy nie ma jeszcze zdefiniowanych replik.

Wykonywanie wstępnego deployu

Aby uruchomić początkowy deployment, możesz ręcznie uruchomić pipeline GitlabCI w gałęzi master. Po tym kubectl powinien wyświetlić następujące:

Canary Deployment w Kubernetes #1: Gitlab CI

Widzimy app deployment z 10 replikami i app-canary z 0. Istnieje również LoadBalancer, do którego możemy się odwoływać przez curl przez External IP:

while true; do curl -s 35.198.149.232 | grep label; sleep 0.1; done

Canary Deployment w Kubernetes #1: Gitlab CI

Widzimy, że nasza aplikacja testowa zwraca tylko “v1”.

Wykonywanie Canary deployu

Krok 1: wydać nową wersję dla części użytkowników

Ustawiliśmy liczbę replik na 1 w pliku deploy-canary.yaml i obraz nowej wersji:

kind: Deployment
metadata:
 name: app-canary
spec:
 replicas: 1
 selector:
   matchLabels:
     id: app
     type: canary
 template:
   metadata:
     labels:
       id: app
       type: canary
   spec:
     containers:
     - image: registry.gitlab.com/wuestkamp/k8s-deployment-example-app:v2
       name: app
       resources:
         limits:
           cpu: 100m
           memory: 100Mi

W pliku deploy.yaml zmieniliśmy liczbę replik na 9:

kind: Deployment
metadata:
 name: app
spec:
 replicas: 9
 selector:
   matchLabels:
     id: app
...

Wysyłamy te zmiany do repozytorium, z którego zostanie uruchomiony deploy (przez GitlabCI) i ostatecznie widzimy:

Canary Deployment w Kubernetes #1: Gitlab CI

Nasz Service będzie wskazywał na oba deploye, ponieważ oba mają selektor app. Z powodu losowego rozkładu domyślnego w Kubernetes powinniśmy zobaczyć różne odpowiedzi na ~ 10% zapytań:

Canary Deployment w Kubernetes #1: Gitlab CI

Bieżący stan naszej aplikacji (GitOps, wzięty z Gita jako Single Source Of Truth) to obecność dwóch deploymentów z aktywnymi replikami, po jednym dla każdej wersji.

~10% użytkowników zapoznaje się z nową wersją i niezamierzanie ją testuje. Teraz nastał czas, aby sprawdzić obecność błędów w logach i danych monitorujących w celu wyszukania problemów.

Krok 2: wypuścić nową wersję dla wszystkich użytkowników

Zdecydowaliśmy, że wszystko przebiegło pomyślnie i teraz musimy wdrożyć nową wersję dla wszystkich użytkowników. Aby to zrobić, po prostu aktualizujemy deploy.yaml instalując nową wersję obrazu i liczba replik wynosi 10. W deploy-canary.yaml ustalamy liczbę replik z powrotem na 0. Po wdrożeniu rezultat będzie następujący:

Canary Deployment w Kubernetes #1: Gitlab CI

Podsumowując

Dla mnie ręczne uruchomienie wdrożenia w ten sposób pomaga zrozumieć, jak łatwo można to skonfigurować za pomocą k8s. Ponieważ Kubernetes pozwala na aktualizację wszystkich za pośrednictwem API, te kroki można zautomatyzować za pomocą skryptów.

Jeszcze jedną rzeczą, którą należy wdrożyć, jest punkt wejścia testera (LoadBalancer lub przez Ingress), przez który można uzyskać dostęp tylko do nowej wersji. Może być używany do manualnego podglądu.

W następnych artykułach sprawdzimy inne zautomatyzowane rozwiązania, które wdrażają większość tego, co zrobiliśmy.

Przeczytaj również inne artykuły na naszym blogu:

Źródło: habr.com

Kup solidny hosting stron z ochroną przed DDoS, serwery VPS VDS 🔥 Kup solidny hosting stron z ochroną przed DDoS, serwery VPS VDS | ProHoster