
Mi chiamo Dmitrij Sugrobov, sono uno sviluppatore presso «Leroy Merlin». In questo articolo spiegherò a cosa serve Helm, come semplifica il lavoro con Kubernetes, cosa è cambiato nella terza versione e come utilizzarlo per aggiornare le applicazioni in produzione senza interruzioni.
Questa è una sintesi ispirata a un intervento in conferenza eliminando file non necessari dai tuoi set di backup — se non vuoi leggere, guarda il video.

Perché utilizziamo Kubernetes in produzione
«Leroy Merlin» è leader nel mercato del fai-da-te in Russia e in Europa. Nella nostra azienda ci sono più di cento sviluppatori, 33.000 dipendenti interni e un enorme numero di persone che visitano i negozi e il sito web. Per rendere tutti loro felici, abbiamo deciso di aderire a approcci standard del settore. Sviluppiamo nuove applicazioni utilizzando un'architettura a microservizi; per isolare gli ambienti e garantire una consegna corretta utilizziamo container; e per l'orchestrazione utilizziamo Kubernetes. Il costo di utilizzo degli orchestratori sta rapidamente diminuendo: aumenta il numero di ingegneri che conoscono questa tecnologia e stanno emergendo provider che offrono Kubernetes come servizio.
Tutto ciò che fa Kubernetes, ovviamente, può essere fatto in altri modi, ad esempio, usando un Jenkins con script e docker-compose, ma perché complicarsi la vita, se c'è una soluzione pronta e affidabile? Ecco perché ci siamo orientati verso Kubernetes e lo utilizziamo già da un anno in produzione. Attualmente abbiamo ventiquattro cluster Kubernetes, il più vecchio dei quali ha più di un anno e contiene circa duecento pod.
La maledizione del gran numero di file YAML in Kubernetes
Per avviare un microservizio in Kubernetes, creeremo almeno cinque file YAML: per Deployment, Service, Ingress, ConfigMap, Secrets — e li invieremo al cluster. Per la successiva applicazione scriveremo lo stesso pacchetto di file YAML, per la terza — un altro e così via. Moltiplichiamo il numero di documenti per il numero di ambienti e già otteniamo centinaia di file, senza contare gli ambienti dinamici.

Adam Reese, core maintainer di Helm, ha introdotto il concetto di "che appare così:
- Copy YAML — copiare il file YAML.
- Paste YAML — incollarlo.
- Fix Indents — sistemare gli spazi.
- Repeat — ripetere di nuovo.
La variante è funzionante, ma comporta molte copie di file YAML. Per modificare questo ciclo, è stato ideato Helm.
Cos'è Helm
Innanzitutto, Helm è gestore di pacchetti, che aiuta a trovare e installare i programmi necessari. Ad esempio, per installare MongoDB non è necessario andare sul sito ufficiale e scaricare i binari, basta eseguire il comando helm install stable/mongodb.
In secondo luogo, Helm è un templater, che aiuta a parametrizzare i file. Torniamo alla situazione con i file YAML in Kubernetes. È più facile scrivere lo stesso file YAML, aggiungere alcuni segnaposto nei quali Helm inserirà i valori. Quindi, invece di un grande insieme di file YAML, avremo un insieme di template, nei quali verranno inseriti i valori necessari al momento giusto.
In terzo luogo, Helm è un maestro del deployment. Con esso è possibile installare, ripristinare e aggiornare le applicazioni. Cerchiamo di capire come fare.

Come usare Helm per il deployment delle proprie applicazioni
Installiamo il client Helm sul computer, seguendo il . Poi creeremo un insieme di file YAML. Invece di specificare valori concreti, lasceremo dei segnaposto, che in futuro Helm riempirà con le informazioni. Questo insieme di file è chiamato Helm chart. Può essere inviato al client della console Helm in tre modi:
- specificare una cartella con i template;
- impacchettarlo in un archivio .tar e fare riferimento a esso;
- mettere il template in un repository remoto e aggiungere un link al repository nel client Helm.
Serve inoltre un file con i valori — values.yaml. I dati da lì verranno inseriti nel template. Creiamolo anche.

Nella seconda versione di Helm c'è un'applicazione server aggiuntiva — Tiller. Essa risiede all'esterno di Kubernetes e attende richieste dal client Helm, e quando viene chiamata, inserisce i valori necessari nel template e lo invia a Kubernetes.

Helm 3 è più semplice: invece di elaborare i template sul server, le informazioni vengono ora elaborate interamente lato client di Helm e inviate direttamente all'API di Kubernetes. Questa semplificazione aumenta la sicurezza del cluster e facilita il processo di deployment.
Come funziona tutto questo
Eseguiamo il comando helm install. Indicheremo il nome del rilascio dell'applicazione, daremo il percorso fino a values.yaml. Alla fine indicheremo il repository in cui si trova il chart e il nome del chart. Nell'esempio, questi sono 'lmru' e 'bestchart' rispettivamente.
helm install --name bestapp --values values.yaml lmru/bestchart
L'esecuzione del comando è possibile solo una volta; per eseguire di nuovo bisogna usare install devi usare . Per ulteriori informazioni su come utilizzare il flagcon un'opzione aggiuntiva . Per ulteriori informazioni su come utilizzare il flag --install --install. Al primo avvio, Helm invierà un comando per installare il rilascio e successivamente lo aggiornerà.
helm upgrade --install bestapp --values values.yaml lmru/bestchart
Insidie del deploy di nuove versioni dell'applicazione con Helm
In questo punto della storia, gioco con il pubblico in "Chi vuol essere milionario?", e stiamo scoprendo come costringere Helm ad aggiornare la versione dell'applicazione. .
Quando studiavo il funzionamento di Helm, mi ha sorpreso un comportamento strano quando tentavo di aggiornare le versioni delle applicazioni in esecuzione. Ho aggiornato il codice dell'applicazione, caricato una nuova immagine nel registro Docker, inviato il comando di deploy – e non è successo nulla. Di seguito alcuni modi non molto efficaci per aggiornare le applicazioni. Esaminando ciascuno di essi più in dettaglio, cominci a comprendere il funzionamento interno dello strumento e le ragioni di tale comportamento non intuitivo.
Modo 1. Non cambiare le informazioni dall'ultimo avvio
Come dice Helm, "I chart di Kubernetes possono essere grandi e complessi, quindi Helm cerca di non toccare nulla senza motivo". Pertanto, se aggiorni l'immagine dell'applicazione all'ultima versione nel registro Docker e esegui il comando helm upgrade, non succederà nulla. Helm penserà che non sia cambiato nulla e non sarà necessario inviare a Kubernetes il comando per aggiornare l'applicazione.
Qui e oltre, il tag latest è mostrato esclusivamente a scopo esemplificativo. Specificando questo tag, Kubernetes scaricherà ogni volta l'immagine dal registro Docker, indipendentemente dal parametro imagePullPolicy. L'uso di latest in produzione è sconsigliato e causa effetti collaterali.
Modo 2. Aggiornare LABEL nell'immagine
Come scritto nello stesso , "Helm aggiornerà l'applicazione solo se è cambiata dall'ultimo rilascio". Un'opzione logica per questo sembrerebbe aggiornare il tag LABEL nell'immagine Docker stessa. Tuttavia, Helm non guarda nelle immagini delle applicazioni e non è a conoscenza di eventuali modifiche in esse. Pertanto, aggiornando i tag nell'immagine, Helm non ne verrà a conoscenza e il comando di aggiornamento dell'applicazione in Kubernetes non verrà emesso.
Modo 3. Utilizzare una chiave --force

Rimandiamo ai manuali e cerchiamo la chiave giusta. La chiave che sembra avere più senso è --force. Nonostante il nome eloquente, il comportamento è diverso da quello previsto. Invece di forzare l'aggiornamento dell'applicazione, il suo reale scopo è il ripristino di una release in stato FAILED. Se non si utilizza questa chiave, è necessario eseguire i comandi in sequenza. helm delete && helm install --replace. Invece, si propone di utilizzare la chiave --force, che automatizza l'esecuzione sequenziale di questi comandi. Maggiori informazioni in questo . Per dire a Helm di aggiornare comunque la versione dell'applicazione, sfortunatamente, questa chiave non funzionerà.
Metodo 4. Modificare direttamente le etichette in Kubernetes.

Aggiornare direttamente l'etichetta nel cluster utilizzando il comando kubectl edit è una cattiva idea. Questa azione porterà a una incongruenza delle informazioni tra l'applicazione in esecuzione e ciò che è stato inizialmente inviato per il deployment. Il comportamento di Helm durante il deployment in questo caso differisce dalla sua versione: Helm 2 non farà nulla, mentre Helm 3 deployerà una nuova versione dell'applicazione. Per comprendere la ragione, è necessario capire come funziona Helm.
Come è strutturato Helm.
Per determinare se l'applicazione è cambiata dall'ultima release, Helm può avvalersi di:
- un'applicazione in esecuzione in Kubernetes;
- nuovo values.yaml e chart attuale;
- informazioni interne di Helm sulle release.
Per i più curiosi: dove Helm archivia le informazioni interne sulle release?Eseguendo il comando helm history, otteniamo tutte le informazioni sulle versioni installate tramite Helm.

Ci sono inoltre dettagli sulle template e i valori inviati. Possiamo richiederli:

Nella seconda versione di Helm, queste informazioni si trovano nello stesso namespace in cui è in esecuzione Tiller (di default — kube-system), in un ConfigMap contrassegnato dall’etichetta «OWNER=TILLER»:

Con l'arrivo della terza versione di Helm, le informazioni sono state trasferite nei segreti, nel medesimo namespace in cui è in esecuzione l'applicazione. Questo ha reso possibile eseguire contemporaneamente più applicazioni in diversi namespace con lo stesso nome di release. Nella seconda versione, ciò era un forte mal di testa, poiché i namespace erano isolati, ma potevano influenzarsi reciprocamente.

Il secondo Helm, quando cerca di capire se è necessario un aggiornamento, utilizza solo due fonti di informazione: ciò che gli è stato fornito ora e le informazioni interne sulle release, che si trovano nel ConfigMap.

Il terzo Helm utilizza una strategia di merge a tre vie: oltre alle informazioni già disponibili, tiene conto anche dell'applicazione che è attualmente in esecuzione su Kubernetes.

Per questo motivo, la vecchia versione di Helm non farà nulla, poiché non considera le informazioni sull'applicazione nel cluster, mentre Helm 3 riceverà le modifiche e invierà una nuova applicazione per il deployment.
Metodo 5. Utilizzare la chiave —recreate-pods
Con la chiave --recreate-pods è possibile ottenere ciò che si voleva inizialmente raggiungere con la chiave --force. I contenitori verranno riavviati e, secondo la politica imagePullPolicy: Always per il tag latest (come indicato nella nota sopra), Kubernetes scaricherà e avvierà una nuova versione dell'immagine. Questo avverrà in modo non ottimale: ignorando il StrategyType del deployment, spegnerà brutalmente tutte le vecchie istanze dell'applicazione e procederà ad avviare quelle nuove. Durante il riavvio, il sistema non sarà operativo e gli utenti subiranno disagi.
Nel Kubernetes stesso, un problema simile è esistito a lungo. E così, dopo 4 anni dall'apertura , il problema è stato risolto e a partire dalla versione 1.15 di Kubernetes è disponibile la possibilità di riavvio rolling dei pod.
Helm invece spegne semplicemente tutte le applicazioni e avvia nuovi contenitori accanto a quelle esistenti. In produzione non è possibile farlo, per non provocare inattività dell'applicazione. Questo è qualcosa che va fatto solo per esigenze di sviluppo, e può essere eseguito solo in ambienti di staging.
Come aggiornare la versione dell'applicazione con Helm?
Modificheremo i valori inviati a Helm. Di solito, questi valori sono quelli che sostituiscono il tag dell'immagine. Nel caso di latest, frequentemente utilizzato per ambienti non produttivi, l'informazione modificabile consiste in un'annotazione, che per Kubernetes è inutile, ma per Helm sarà un segnale della necessità di aggiornare l'applicazione. Ecco alcune varianti per compilare il valore dell'annotazione:
- Valore casuale utilizzando la funzione standard —
{{ randAlphaNum 6 }}.
C'è un dettaglio: dopo ogni deployment utilizzando un chart con tale variabile, il valore dell'annotazione sarà unico, e Helm penserà che ci siano modifiche. Così facendo, riavvieremo sempre l'applicazione, anche se non abbiamo cambiato la sua versione. Questo non è critico, poiché non ci sarà inattività, ma è comunque fastidioso. - Inserire l'attuale data e ora —
{{ .Release.Date }}.
Questa opzione è simile al valore casuale con una variabile sempre unica. - Un modo più corretto è utilizzare somme di controllo. Questo è l'immagine SHA o SHA dell'ultimo commit in git —
{{ .Values.sha }}.
Devono essere calcolate e inviate al client Helm sul lato chiamante, ad esempio in Jenkins. Se l'applicazione cambia, anche la somma di controllo cambierà. Pertanto, Helm aggiornerà l'applicazione solo quando necessario.
Riassumiamo i nostri tentativi
- Helm apporta modifiche nel modo meno invasivo possibile, quindi qualsiasi cambiamento a livello di immagine dell'applicazione nel Docker Registry non porterà a un aggiornamento: dopo l'esecuzione del comando, non succede nulla.
- Chiave
--forceviene utilizzato per ripristinare le release problematiche e non è collegato a un aggiornamento forzato. - Chiave
--recreate-podsforzerà l'aggiornamento delle applicazioni, ma lo farà in modo distruttivo: spegnerà bruscamente tutti i container. Questo danneggerà gli utenti; non è consigliabile farlo in produzione. - Non bisogna apportare modifiche direttamente al cluster Kubernetes con il comando
kubectl edit: comprometteremmo la consistenza e il comportamento varierà a seconda della versione di Helm. - Con l'uscita della nuova versione di Helm sono emersi molti dettagli. I problemi nel repository di Helm sono descritti in modo chiaro e aiuteranno a comprendere i dettagli.
- Aggiungere un'annotazione modificabile nel chart lo renderà più flessibile. Questo consentirà di implementare l'applicazione correttamente, senza tempi di inattività.
Un pensiero del tipo 'pace nel mondo' che funziona in tutti gli ambiti della vita: leggi le istruzioni prima dell'uso, non dopo. Solo possedendo tutte le informazioni, è possibile costruire sistemi affidabili e rendere felici gli utenti.
Altri collegamenti sull'argomento:
Questa presentazione è stata pronunciata per la prima volta a by Mail.ru Cloud Solutions. Guarda altre presentazioni e iscriviti agli annunci di eventi su Telegram .
Fonte: habr.com
