Utilizzeremo Gitlab CI e GitOps manuale per implementare e utilizzare il Canary deployment in Kubernetes

Articoli di questo ciclo:
- (questo articolo)
- Canary Deployment con Istio
- Canary Deployment con Jenkins-X Istio Flagger
Effettueremo il Canary deployment manualmente attraverso GitOps e la creazione/modifica delle risorse principali di Kubernetes. Questo articolo è principalmente destinato a introdurre come funziona il Canary deployment in Kubernetes, poiché ci sono metodi più efficienti di automazione che discuteremo nei prossimi articoli.

Deployment Canary
Con la strategia Canary, gli aggiornamenti vengono applicati inizialmente solo a una parte degli utenti. Attraverso il monitoraggio, i dati dai log, i test manuali o altri canali di feedback, il rilascio viene testato prima di essere applicato a tutti gli utenti.
Kubernetes Deployment (rolling update)
La strategia predefinita per il Kubernetes Deployment è il rolling-update, dove viene eseguito un certo numero di pod con nuove versioni delle immagini. Se vengono creati senza problemi, i pod con le versioni precedenti delle immagini vengono terminati e nuovi pod vengono creati in parallelo.
GitOps
Utilizziamo GitOps in questo esempio, poiché noi:
- utilizziamo Git come unica fonte di verità
- utilizziamo Git Operations per la build e il deploy (nessun comando necessario tranne git tag/merge)
Esempio
Prendiamo una buona pratica: avere un repository per il codice delle applicazioni e uno per l'infrastruttura.
Repository per le applicazioni
Questa è una semplice API su Python+Flask, che restituisce una risposta in formato JSON. Creeremo un pacchetto tramite GitlabCI e caricheremo il risultato nel Gitlab Registry. Nel registry abbiamo due diverse versioni di release:
wuestkamp/k8s-deployment-example-app:v1wuestkamp/k8s-deployment-example-app:v2
L'unica differenza tra di esse è la modifica del file JSON restituito. Utilizziamo questa applicazione per una visualizzazione massima e semplice di quale versione stiamo interagendo.
Repository infrastrutturale
In questo repository faremo il deploy tramite GitlabCI in Kubernetes, .gitlab-ci.yml si presenta nel seguente modo:
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
Per eseguirlo da solo avrai bisogno di un cluster, puoi utilizzare Gcloud:
gcloud container clusters create canary --num-nodes 3 --zone europe-west3-b
gcloud compute firewall-rules create incoming-80 --allow tcp:80È necessario fare un fork e creare una variabile KUBECONFIG in GitlabCI che conterrà la configurazione per l'accesso kubectl al tuo cluster.
Informazioni su come ottenere le credenziali per il cluster (Gcloud) possono essere lette .
Yaml infrastrutturale
Nel repository infrastrutturale abbiamo service:
apiVersion: v1
kind: Service
metadata:
labels:
id: app
name: app
spec:
ports:
- port: 80
protocol: TCP
targetPort: 5000
selector:
id: app
type: LoadBalancerE deployment in 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: 100MiE un altro deployment in 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: 100MiNota che app-deploy attualmente non ha repliche definite.
Esecuzione del deployment iniziale
Per avviare il deployment iniziale, puoi avviare manualmente il pipeline GitlabCI nel ramo master. Dopo di che kubectl dovrebbe restituire quanto segue:

Vediamo app il deployment con 10 repliche e app-canary con 0. C'è anche un LoadBalancer da cui possiamo accedere tramite curl l'IP esterno:
while true; do curl -s 35.198.149.232 | grep label; sleep 0.1; done

Vediamo che la nostra applicazione di test restituisce solo “v1”.
Esecuzione del deploy Canary
Passo 1: rilasciare una nuova versione per una parte degli utenti
Abbiamo impostato il numero di repliche a 1 nel file deploy-canary.yaml e l'immagine della nuova versione:
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: 100MiNel file deploy.yaml abbiamo cambiato il numero di repliche a 9:
kind: Deployment
metadata:
name: app
spec:
replicas: 9
selector:
matchLabels:
id: app
...Stiamo inviando queste modifiche nel repository da cui verrà eseguito il deploy (tramite GitlabCI) e alla fine vediamo:

Il nostro Service punterà a entrambi i deploy, poiché entrambi hanno il selettore app. A causa della distribuzione casuale per impostazione predefinita in Kubernetes, dovremmo vedere risposte diverse su circa il 10% delle richieste:

Lo stato attuale della nostra applicazione (GitOps, preso da Git come Single Source Of Truth) consiste nella presenza di due deployments con repliche attive, una per ogni versione.
~10% degli utenti si familiarize con la nuova versione e la testano involontariamente. È ora di controllare la presenza di errori nei log e nei dati di monitoraggio per identificare eventuali problemi.
Passo 2: rilasciare la nuova versione per tutti gli utenti
Abbiamo deciso che tutto è andato bene e ora dobbiamo distribuire la nuova versione a tutti gli utenti. Per farlo, aggiorniamo semplicemente deploy.yaml installando la nuova versione dell'immagine e impostando il numero di repliche a 10. In deploy-canary.yaml impostiamo il numero di repliche a 0. Dopo il deployment, il risultato sarà il seguente:

In sintesi
Per me, avviare il deployment manualmente in questo modo aiuta a capire quanto possa essere semplice configurarlo con k8s. Poiché Kubernetes consente di aggiornare tutto tramite API, questi passaggi possono essere automatizzati tramite script.
Un'altra cosa da implementare è il punto di ingresso per il tester (LoadBalancer o tramite Ingress), attraverso il quale è possibile accedere solo alla nuova versione. Può essere utilizzato per una visualizzazione manuale.
Negli articoli successivi esploreremo altre soluzioni automatizzate che implementano la maggior parte di ciò che abbiamo fatto.
Leggi anche altri articoli nel nostro blog:
Fonte: habr.com
