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
Eseguiremo il Canary deploy manualmente tramite GitOps e creando/modificando le risorse principali di Kubernetes. Questo articolo è principalmente destinato a familiarizzare con il funzionamento del Canary deployment in Kubernetes, poiché ci sono modi più efficaci di automazione che esploreremo nei prossimi articoli.

Distribuzione Canary
Con la strategia di aggiornamento Canary, le modifiche vengono inizialmente applicate solo a una parte degli utenti. Attraverso il monitoraggio, i dati dei log, i test manuali o altri canali di feedback, la versione viene testata prima della sua applicazione a tutti gli utenti.
Kubernetes Deployment (rolling update)
La strategia predefinita per il Kubernetes Deployment è il rolling-update, dove viene avviato un numero definito di pod con nuove versioni delle immagini. Se vengono creati senza problemi, i pod con le vecchie versioni delle immagini si fermano e nuovi pod vengono creati in parallelo.
GitOps
Utilizziamo GitOps in questo esempio, poiché:
- utilizziamo Git come unica fonte di verità
- utilizziamo Git Operations per costruire e distribuire (nessun comando oltre a git tag/merge necessario)
Esempio
Adottiamo una buona pratica: avere un repository per il codice delle applicazioni e uno per l'infrastruttura.
Repository per le applicazioni
Si tratta di una semplice API in Python+Flask, che restituisce una risposta in formato JSON. Creeremo il pacchetto tramite GitlabCI e pubblicheremo il risultato nel Gitlab Registry. Nel registro abbiamo due diverse versioni di rilascio:
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 visualizzare in modo semplice con quale versione stiamo interagendo.
Repository infrastrutturale
In questo repository faremo il deploy tramite GitlabCI in Kubernetes. .gitlab-ci.yml si presenta come segue:
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 avviarlo da solo avrete bisogno di un cluster, potete utilizzare Gcloud:
gcloud container clusters create canary --num-nodes 3 --zone europe-west3-b
gcloud compute firewall-rules create incoming-80 --allow tcp:80Dovete fare un fork e creare una variabile KUBECONFIG in GitlabCI, che conterrà la configurazione per l'accesso kubectl al vostro cluster.
Per informazioni su come ottenere le credenziali per il cluster (Gcloud), puoi leggere .
Yaml infrastrutturale
Nel repository dell'infrastruttura abbiamo il 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 eseguire manualmente il pipeline di GitlabCI nel ramo master. Dopo di che kubectl dovrebbe mostrare quanto segue:

Vediamo app un deployment con 10 repliche e app-canary con 0. C'è anche un LoadBalancer a cui possiamo accedere attraverso 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 deployment 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 modificato 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à avviato il deployment (tramite GitlabCI) e vediamo infine:

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

Lo stato attuale della nostra applicazione (GitOps, preso da Git come unica fonte di verità) è la presenza di due deployments con repliche attive, uno per ogni versione.
~il 10% degli utenti prova la nuova versione e la testa involontariamente. È ora di controllare la presenza di errori nei log e nei dati di monitoraggio per individuare eventuali problemi.
Passo 2: rilasciare una nuova versione per tutti gli utenti
Abbiamo deciso che tutto è andato bene e ora dobbiamo distribuire la nuova versione a tutti gli utenti. Per fare ciò, aggiorniamo semplicemente deploy.yaml installando la nuova versione dell'immagine e impostando il numero delle repliche a 10. In deploy-canary.yaml Impostiamo il numero di repliche a zero. Dopo il deploy il risultato sarà il seguente:

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