Ciao a tutti! Mi chiamo Pavel Agaletsky. Lavoro come team leader nel team che sviluppa il sistema di consegna di Lamoda. Nel 2018 ho parlato alla conferenza HighLoad++, e oggi voglio presentarvi la trascrizione della mia presentazione.
Il mio tema riguarda l'esperienza della nostra azienda nel deploy di sistemi e servizi in diverse ambienti. Cominciando dai nostri tempi preistorici, quando deployavamo tutti i sistemi su normali server virtuali, fino alla transizione graduale da Nomad al deploy su Kubernetes. Parlerò di perché l'abbiamo fatto e quali problemi abbiamo affrontato nel processo.

Deploy delle applicazioni su VM
Tre anni fa, tutti i sistemi e i servizi della nostra azienda venivano distribuiti su normali server virtuali. Dal punto di vista tecnico, era stato organizzato affinché tutto il codice dei nostri sistemi fosse gestito e costruito tramite strumenti di build automatizzati, utilizzando Jenkins. Utilizzando Ansible, veniva distribuito dai nostri sistemi di controllo versione sui server virtuali. Ogni sistema presente nella nostra azienda veniva distribuito almeno su due server: uno di essi era il head e l'altro il tail. Questi due sistemi erano assolutamente identici per quanto riguarda tutte le impostazioni, la potenza, la configurazione e altro. L'unica differenza tra loro era che il head riceveva il traffico degli utenti, mentre il tail non riceveva mai traffico degli utenti.
A cosa serviva questo?
Quando distribuivamo nuove versioni della nostra applicazione, volevamo garantire un rollout senza interruzioni, cioè senza conseguenze visibili per gli utenti. Questo veniva raggiunto distribuendo ogni rilascio assemblato tramite Ansible sul tail. Qui, le persone impegnate nel deployment potevano controllare e verificare che tutto funzionasse correttamente: tutte le metriche, le sezioni e le applicazioni erano operative; venivano eseguiti gli script necessari. Solo dopo essersi assicurati che tutto fosse a posto, il traffico veniva instradato. Quest'ultimo iniziava a fluire verso il server che in precedenza era tail. Mentre quello che prima era head rimaneva senza traffico utente, sfruttando comunque la versione precedente della nostra applicazione.
In questo modo, per gli utenti era senza soluzione di continuità. Poiché il passaggio è immediato, trattandosi semplicemente di un cambio del bilanciatore. È possibile tornare facilmente a una versione precedente semplicemente ripristinando il bilanciatore. Inoltre, potevamo verificare la capacità dell'applicazione in produzione prima che il traffico degli utenti vi affluissi, il che risultava piuttosto comodo.
Quali vantaggi abbiamo riscontrato in tutto questo?
- Innanzitutto, funziona abbastanza semplicemente. A tutti è chiaro come funzioni un sistema di deployment di questo tipo, poiché la maggior parte delle persone ha mai effettuato il deployment su normali server virtuali.
- È abbastanza affidabile, perché la tecnologia di deployment è semplice, testata da migliaia di aziende. Milioni di server vengono distribuiti proprio in questo modo. È difficile rompere qualcosa.
- E infine, abbiamo potuto ottenere deploy atomici. Deployment che avvengono simultaneamente per gli utenti, senza un evidente passaggio tra la vecchia versione e la nuova.
Ma in tutto questo abbiamo anche visto alcuni svantaggi:
- Oltre all'ambiente di produzione e a quello di sviluppo, ci sono anche altri ambienti. Ad esempio, qa e preproduzione. A quel tempo avevamo molti server e circa 60 servizi. Per questo motivo era necessario mantenere la versione appropriata per ogni servizio macchina virtuale. Se desideri aggiornare le librerie o installare nuove dipendenze, devi farlo in tutte le ambienti. È inoltre necessario sincronizzare il momento in cui intendi distribuire una nuova versione della tua applicazione con il momento in cui il team devops eseguirà le necessarie configurazioni dell'ambiente. In questo modo, è facile finire in una situazione in cui l'ambiente differisce in modo significativo tra tutti gli ambienti. Ad esempio, nell'ambiente QA potrebbero esserci versioni di librerie diverse rispetto a quelle in produzione, il che porterà a problemi.
- Difficoltà nell'aggiornamento delle dipendenze della tua applicazione. Questo non dipende da te, ma da un altro team. In particolare, dal team devops che gestisce i server. Devi assegnare loro il compito appropriato e fornire una descrizione di quello che desideri fare.
- All'epoca volevamo anche suddividere i grandi monoliti che avevamo in piccoli servizi, consapevoli che sarebbero diventati sempre più numerosi. A quel tempo, ne avevamo già oltre 100. Era necessario creare una nuova macchina virtuale separata per ogni nuovo servizio, da mantenere e distribuire. Inoltre, non era sufficiente avere una sola macchina, ma almeno due. A tutto ciò si aggiungeva anche un ambiente QA. Questo crea problemi e rende la creazione e l'avvio di nuovi sistemi più complesso, costoso e lungo.
Perciò abbiamo deciso che sarebbe stato più pratico passare dal deployment di normali macchine virtuali al deployment delle nostre applicazioni in container Docker. Con Docker, è necessaria una piattaforma che possa avviare l'applicazione in un cluster, dato che non è possibile avviare un container così facilmente. Di solito, si desidera monitorare quanti container sono attivi affinché vengano avviati automaticamente. Per questo motivo, era necessario scegliere un sistema di gestione.
Abbiamo riflettuto a lungo su quale scegliere. Il fatto è che, a quel tempo, questo stack di deployment su normali server virtuali era un po' obsoleto, poiché presentava versioni di sistema operativo non recenti. A un certo punto, c'era persino FreeBSD, che era poco conveniente da mantenere. Abbiamo capito che era necessario migrare il prima possibile a Docker. I nostri DevOps hanno esaminato la loro esperienza con diverse soluzioni e hanno scelto un sistema come Nomad.
Transizione a Nomad
Nomad è un prodotto dell'azienda "HashiCorp". Sono anche noti per altre loro soluzioni:

"Consul" è uno strumento per la scoperta dei servizi.
"Terraform" è un sistema di gestione dei server che consente di configurarli tramite configurazioni, note come infrastructure-as-code.
"Vagrant" permette di distribuire macchine virtuali localmente o nel cloud tramite specifici file di configurazione.
Nomad si è rivelato una soluzione piuttosto semplice da adottare, permettendo un passaggio rapido senza dover modificare completamente l'intera infrastruttura. Inoltre, è abbastanza facile da imparare. È per questo motivo che lo abbiamo scelto come sistema di filtraggio per il nostro container.
Cosa serve per distribuire il vostro sistema su Nomad?
- Prima di tutto, serve un'immagine docker della vostra applicazione. È necessario costruirla e caricarla in un repository di immagini docker. Nel nostro caso, utilizziamo artifactory, un sistema che consente di caricare diversi tipi di artefatti. È capace di memorizzare archivi, immagini docker, pacchetti composer PHP, pacchetti NPM e così via.
- Sono inoltre necessari un file di configurazione, che indica a Nomad cosa, dove e in quale quantità volete distribuire.
Quando parliamo di Nomad, il formato del file di configurazione utilizza il linguaggio HCL, che sta per HashiCorp Configuration Language. Questo è un superinsieme di YAML, che consente di descrivere il vostro servizio in termini di Nomad.

Permette di specificare quanti contenitori si desidera distribuire e di trasmettere vari parametri durante il deployment attraverso le immagini. In questo modo, fornisci questo file a Nomad, il quale avvia i contenitori in produzione in base a esso.
Nel nostro caso, abbiamo capito che scrivere file HCL identici per ogni servizio non sarebbe stato molto pratico, poiché ci sono molti servizi e a volte è necessario aggiornarli. Può capitare che un servizio sia distribuito non in un'unica istanza, ma in diverse. Ad esempio, uno dei sistemi in produzione ha più di 100 istanze attive. Vengono avviati dagli stessi immagini, ma differiscono per impostazioni di configurazione e file di configurazione.
Per questo motivo, abbiamo deciso che sarebbe stato comodo conservare tutti i nostri file di configurazione per il deployment in un unico repository comune. In questo modo, sono diventati consultabili: era facile mantenerli e si poteva vedere quali sistemi abbiamo. In caso di necessità, non è difficile aggiornare o modificare qualcosa. Aggiungere un nuovo sistema non comporta nemmeno difficoltà: basta creare un file di configurazione all'interno di una nuova directory. Al suo interno ci sono i file: service.hcl, che contiene la descrizione del nostro servizio, e alcuni file env, che consentono di configurare il servizio stesso quando viene deployato in produzione.

Tuttavia, alcuni dei nostri sistemi sono deployati in produzione non in un solo esemplare, ma in più contemporaneamente. Per questo motivo, abbiamo deciso che sarebbe stato più comodo conservare non i config in forma grezza, ma la loro versione template. E come linguaggio di templating abbiamo scelto jinja 2. In questo formato, abbiamo archiviati sia i config del servizio stesso che i file env necessari per esso.
Inoltre, abbiamo inserito nel repository comune per tutti i progetti uno script di deployment che consente di avviare e distribuire il tuo servizio in produzione, nell'ambiente desiderato e nel target specifico. Nel caso in cui abbiamo trasformato la nostra configurazione HCL in un modello, il file HCL, che in precedenza era una normale configurazione Nomad, appare ora in modo leggermente diverso.

In altre parole, abbiamo sostituito alcune variabili nella configurazione con inserimenti di variabili provenienti da file env o da altre fonti. Inoltre, abbiamo ottenuto la possibilità di generare file HCL in modo dinamico, consentendo non solo di applicare normali inserimenti di variabili. Poiché jinja supporta i cicli e le condizioni, è possibile creare file di configurazione che cambiano a seconda di dove distribuisci le tue applicazioni.
Ad esempio, desiderate deployare il vostro servizio in preproduzione e in produzione. Supponiamo che in preproduzione non vogliate eseguire script cron, ma semplicemente vedere il servizio su un dominio separato per assicurarvi che funzioni. Per chiunque stia deployando un servizio, il processo appare molto semplice e trasparente. È sufficiente eseguire il file deploy.sh, specificare quale servizio si desidera deployare e in quale target. Ad esempio, si desidera deployare un sistema in Russia, in Bielorussia o in Kazakistan. Per fare ciò, è sufficiente modificare uno dei parametri e otterrete il file di configurazione corretto.
Quando il servizio Nomad è già stato deployato nel cluster, si presenta nel seguente modo.

Per prima cosa, avete bisogno di un bilanciatore esterno che accetti tutto il traffico degli utenti. Questo funzionerà insieme a Consul e chiederà a questo ultimo dove, su quale nodo, per quale indirizzo IP c'è un servizio specifico che corrisponde a un determinato nome di dominio. I servizi in Consul emergono direttamente da Nomad. Poiché sono prodotti della stessa azienda, sono ben collegati tra loro. Si può dire che Nomad registra automaticamente tutti i servizi avviati al suo interno in Consul.
Una volta che il tuo bilanciatore esterno sa a quale servizio deve inviare il traffico, lo reindirizza nel contenitore corrispondente o in più contenitori associati alla tua applicazione. È fondamentale considerare anche la sicurezza. Anche se tutti i servizi sono avviati sulle stesse macchine virtuali nei contenitori, di solito è necessario vietare l'accesso libero da un servizio a un altro. Abbiamo raggiunto questo obiettivo attraverso la segmentazione. Ogni servizio veniva eseguito nella propria rete virtuale, sulla quale erano definite regole di instradamento e di autorizzazione/divieto di accesso ad altri sistemi e servizi. Questi potevano trovarsi sia all'interno che all'esterno di questo cluster. Ad esempio, se vuoi vietare a un servizio di connettersi a un determinato database, puoi farlo tramite la segmentazione a livello di rete. In altre parole, anche per errore non puoi accidentalmente collegarti dal tuo ambiente di test al tuo database di produzione.
Qual è stato il costo del processo di transizione in termini di risorse umane?
Il passaggio di tutta l'azienda a Nomad ha richiesto circa 5-6 mesi. Siamo transitati servizio per servizio, ma a un ritmo piuttosto veloce. Ogni team doveva creare i propri contenitori per i servizi.
Adottiamo un approccio in cui ogni team è responsabile delle immagini Docker dei propri sistemi. I DevOps forniscono l'infrastruttura generale necessaria per il deployment, cioè il supporto per il cluster stesso, il supporto per il sistema CI e così via. Fino a quel momento, oltre 60 sistemi erano stati trasferiti in Nomad, generando circa 2000 contenitori.
I DevOps si occupano dell'infrastruttura generale relativa al deployment e ai server. Ogni team di sviluppo, a sua volta, è responsabile della realizzazione dei contenitori per il proprio sistema specifico, poiché è il team che sa esattamente di cosa ha bisogno in ogni contenitore.
Motivi per rifiutare Nomad
Quali vantaggi abbiamo ottenuto passando al deployment tramite Nomad e Docker?
- Noi abbiamo garantito condizioni uniformi per tutti gli ambienti. Nello sviluppo, nell'ambiente QA, nella pre-produzione e nella produzione vengono utilizzate le stesse immagini dei container, con le stesse dipendenze. Di conseguenza, avete praticamente zero possibilità che in produzione finisca qualcosa di diverso da ciò che avete testato localmente o nell'ambiente di test.
- Inoltre, abbiamo scoperto che è abbastanza facile aggiungere un nuovo servizio. Qualsiasi nuovo sistema, dal punto di vista del deployment, si avvia molto facilmente. Basta andare nel repository che contiene le configurazioni, aggiungere la nuova configurazione per il vostro sistema e il gioco è fatto. Potete deployare il vostro sistema in produzione senza sforzi aggiuntivi da parte del DevOps.
- Tutti file di configurazione in un unico repository generale risultano visualizzabili. Nel momento in cui abbiamo effettuato il deployment dei nostri sistemi tramite server virtuali, abbiamo utilizzato Ansible, in cui le configurazioni erano tutte nello stesso repository. Tuttavia, per la maggior parte degli sviluppatori, lavorare con questo era un po' più complesso. Qui, il volume di configurazioni e codice necessario per l'implementazione del servizio è notevolmente diminuito. Inoltre, per i DevOps è molto semplice modificarlo o cambiarlo. In caso di aggiornamenti, ad esempio, a una nuova versione di Nomad, possono facilmente aggiornare massivamente tutti i file operativi che si trovano nello stesso posto.
Ma ci siamo anche imbattuti in diversi svantaggi:
Si è rivelato che non siamo riusciti a raggiungere la continuità nelle distribuzioni nel caso di Nomad. Durante il rilascio dei container da condizioni diverse, può accadere che venga avviato e Nomad lo percepisca come pronto a ricevere traffico. Questo avveniva prima che l'applicazione al suo interno avesse avuto il tempo di avviarsi. Per questo motivo, il sistema iniziava a restituire temporaneamente errori 500, poiché il traffico cominciava a dirigersi a un container che non era ancora pronto per riceverlo.
Abbiamo riscontrato alcuni bug. Il principale problema è che Nomad non gestisce bene un grande cluster quando hai molte macchine e contenitori. Quando desideri mettere in manutenzione uno dei server che fa parte del cluster Nomad, c'è una buona probabilità che il cluster non si senta bene e si rompa. Alcuni contenitori potrebbero, ad esempio, andare in crash e non riavviarsi — questo ti costerà molto, soprattutto se tutti i tuoi sistemi in produzione si trovano all'interno di un cluster gestito da Nomad.
Perciò abbiamo deciso di riflettere su quale direzione intraprendere. A quel punto, eravamo molto più consapevoli di ciò che volevamo raggiungere. In particolare: desideravamo affidabilità, un po' più di funzionalità rispetto a quelle fornite da Nomad e un sistema più maturo, più stabile.
In questo senso, la nostra scelta è ricaduta su Kubernetes come la piattaforma più popolare per il lancio di cluster. Soprattutto considerando che la dimensione e il numero dei nostri contenitori erano piuttosto grandi. Per tali scopi, Kubernetes sembrava il sistema più adatto tra quelli che potevamo esaminare.
Transizione a Kubernetes
Parlerò un po' dei concetti fondamentali di Kubernetes e di come si differenziano da Nomad.

Il concetto di base in Kubernetes è il pod. Pod è un gruppo di uno o più contenitori che vengono sempre eseguiti insieme. Funzionano come se fossero sempre rigorosamente su una sola macchina virtuale. Possono comunicare tra loro tramite l'indirizzo IP 127.0.0.1 su porte diverse.
Supponiamo di avere un'applicazione PHP composta da nginx e php-fpm – uno schema classico. Probabilmente vorrete che i contenitori nginx e php-fpm siano sempre insieme. Kubernetes consente di raggiungere questo obiettivo descrivendoli come un unico pod. Questo è esattamente ciò che non potevamo ottenere usando Nomad.
Il secondo concetto è deployment. Il pod, di per sé, è un'entità effimera, viene avviato e scompare. Volete eliminare prima tutti i vostri contenitori precedenti e poi avviare nuove versioni, oppure desiderate distribuirle gradualmente? È per questo processo che si parla di deployment. Esso descrive come si deployano i vostri pod, in quale quantità e come aggiornarli.
Il terzo concetto è service. Il tuo service è fondamentalmente il tuo sistema, che riceve un certo traffico e poi lo indirizza a uno o più pod che corrispondono al tuo servizio. Questo significa che puoi specificare che tutto il traffico in entrata per un determinato servizio con un certo nome deve essere inviato esattamente a questi pod. Inoltre, offre bilanciamento del traffico. Puoi avviare due pod della tua applicazione e tutto il traffico in entrata sarà bilanciato uniformemente tra i pod associati a questo servizio.
E il quarto concetto fondamentale — Ingress. Questo è un servizio che viene eseguito in un cluster Kubernetes. Funziona come un bilanciatore di carico esterno, che riceve tutte le richieste. Grazie all'API Kubernetes Ingress, è in grado di determinare dove inviare queste richieste. Lo fa in modo molto flessibile. Puoi specificare che tutte le richieste per questo host e un certo URL devono essere inviate a questo servizio. Mentre queste richieste, che arrivano su questo host e su un altro URL, vengono inviate a un altro servizio.
La cosa più interessante per un sviluppatore è che può gestire tutto autonomamente. Configurando l'Ingress, puoi indirizzare tutto il traffico che arriva su un determinato API a contenitori separati, ad esempio scritti in Go. Mentre quel traffico che arriva sullo stesso dominio, ma su un'altra URL, può essere reindirizzato a contenitori scritti in PHP, dove c'è molta logica, anche se non sono molto veloci.
Se confrontiamo tutti questi concetti con Nomad, possiamo dire che i primi tre concetti si uniscono a formare il Service. L'ultimo concetto, invece, non è presente in Nomad. Noi lo abbiamo sostituito con un bilanciatore esterno: può essere haproxy, nginx, nginx+ e così via. Nel caso del cluster, non è necessario introdurre questo concetto separatamente. Tuttavia, se guardiamo dentro Ingress, vediamo che è o nginx, o haproxy, o traefik, ma integrato in Kubernetes.
Tutti i concetti che ho descritto sono, in sostanza, risorse che esistono all'interno di un cluster Kubernetes. Per descriverli in Kubernetes viene utilizzato il formato yaml, che è più leggibile e familiare rispetto ai file HCL in Nomad. Strutturalmente, descrivono lo stesso concetto, ad esempio, di un pod. Indicano - voglio distribuire questi pod in questo luogo, con queste immagini, in questa quantità.

Inoltre, abbiamo capito che non volevamo creare manualmente ogni singola risorsa: deployment, servizi, Ingress e altro. Invece, volevamo descrivere ogni nostro sistema in termini di Kubernetes al momento della distribuzione, in modo da non dover ricreare manualmente nell'ordine corretto tutte le dipendenze necessarie delle risorse. Per fare questo, abbiamo scelto Helm come sistema.
Concetti fondamentali in Helm
Helm è un gestore di pacchetti per Kubernetes. È molto simile al funzionamento dei gestori di pacchetti nei linguaggi di programmazione. Permettono di archiviare un servizio composto, ad esempio, da un deployment di nginx, un deployment di php-fpm, una configurazione per Ingress, configmaps (un'entità che consente di impostare variabili d'ambiente e altri parametri per il sistema) sotto forma di cosiddetti chart. In questo processo, Helm opera sopra Kubernetes. Cioè, non è un sistema separato, ma solo un altro servizio eseguito all'interno del cluster. Interagisci con esso tramite la sua API attraverso comandi in console. La sua comodità e bellezza risiedono nel fatto che, anche se Helm si guasta o lo rimuovi dal cluster, i tuoi servizi non scompariranno, poiché Helm serve sostanzialmente solo per l'avvio del sistema. La funzionalità e lo stato dei servizi vengono gestiti direttamente da Kubernetes.
Inoltre, abbiamo compreso che la templating, che prima eravamo costretti a fare manualmente tramite l'integrazione di jinja nei nostri configurazioni, è una delle funzionalità principali di helm. Tutte le configurazioni che crei per i tuoi sistemi sono memorizzate in helm come modelli, simili a jinja, ma in realtà utilizzano il sistema di templating del linguaggio Go, su cui helm è scritto, proprio come Kubernetes.
Helm ci aggiunge anche alcuni concetti aggiuntivi.
Chart — è una descrizione del tuo servizio. Negli altri gestori di pacchetti, sarebbe chiamato pacchetto, bundle o qualcosa di simile. Qui si chiama chart.
Values – sono le variabili che vuoi utilizzare per costruire le tue configurazioni dai modelli.
Release. Ogni volta che un servizio viene deployato tramite helm, riceve una versione incrementale del rilascio. Helm ricorda quale fosse la configurazione del servizio nel rilascio precedente, in quello ancora prima, e così via. Pertanto, se è necessario tornare indietro, basta eseguire il comando helm callback specificando la versione precedente del rilascio. Anche se al momento del rollback la configurazione corrispondente non è disponibile nel tuo repository, helm ricorda comunque qual era, e riporterà il tuo sistema allo stato in cui si trovava nel rilascio precedente.
Nel caso in cui utilizziamo helm, le normali configurazioni per Kubernetes si trasformano anche in modelli, nei quali è possibile utilizzare variabili, funzioni e applicare operatori condizionali. In questo modo, puoi assembleare la configurazione del tuo servizio a seconda dell'ambiente.

In pratica, abbiamo deciso di procedere in modo leggermente diverso rispetto a quanto fatto con Nomad. Se in Nomad nel medesimo repository erano memorizzati sia i file di configurazione per il deployment che le variabili n necessarie per il deployment del nostro servizio, qui abbiamo deciso di separarle in due repository distinti. Nel repository "deploy" sono memorizzate solo le variabili n necessarie per il deployment, mentre nel repository "helm" sono conservate le configurazioni o i chart.

Cosa ci ha dato questo?
Nonostante nei file di configurazione non memorizziamo dati realmente sensibili, come ad esempio le password per i database, che vengono conservate come secrets in Kubernetes, ci sono comunque elementi a cui non desideriamo dare accesso indiscriminato. Pertanto, l'accesso al repository "deploy" è più limitato, mentre il repository "helm" contiene semplicemente una descrizione del servizio. Per questo motivo, è possibile concedere accesso a un numero maggiore di persone in modo sicuro.
Poiché abbiamo non solo un ambiente di produzione, ma anche altri ambienti, grazie a questa separazione possiamo riutilizzare i nostri helm chart per distribuire i servizi non solo in produzione, ma anche, ad esempio, nell'ambiente QA. Anche per implementarli localmente, usando Minikube — è uno strumento per l'esecuzione locale di Kubernetes.
All'interno di ogni repository abbiamo mantenuto una suddivisione in directory separate per ogni servizio. In altre parole, all'interno di ogni directory ci sono i modelli relativi al chart corrispondente che descrivono le risorse necessarie per avviare il nostro sistema. Nel repository "deploy" abbiamo lasciato solo le variabili ambientali. In questo caso non abbiamo utilizzato la templating con jinja, perché helm fornisce già la templating out of the box – è una delle sue principali funzionalità.
Abbiamo fornito uno script per il deployment – deploy.sh, che semplifica e standardizza l'avvio per il deployment con helm. In questo modo, per chiunque desideri effettuare un deployment, l'interfaccia di deployment appare esattamente come nel caso del deployment tramite Nomad. Lo stesso deploy.sh, il nome del tuo servizio e il luogo in cui vuoi effettuare il deployment. Questo fa sì che all'interno venga avviato helm. Esso raccoglie i file di configurazione dai modelli, inserisce i file values necessari e poi effettua il deployment, rilasciandoli in Kubernetes.
Conclusioni
Il servizio Kubernetes appare più complesso rispetto a Nomad.

Qui il traffico in uscita arriva nell'Ingress. Questo funge da controller frontale, che riceve tutte le richieste e poi le inoltra ai servizi corrispondenti ai dati della richiesta. Li determina in base alle configurazioni, che fanno parte della descrizione della tua applicazione in helm e che i programmatori impostano autonomamente. Il servizio invia le richieste ai propri pod, cioè ai contenitori specifici, bilanciando il traffico in entrata tra tutti i contenitori associati a quel servizio. E, ovviamente, non dobbiamo dimenticare che la sicurezza a livello di rete è fondamentale. Pertanto, nel cluster Kubernetes viene implementata una segmentazione basata sulla marcatura. Tutti i servizi hanno determinati tag, a cui sono associate le autorizzazioni di accesso ai vari risorse esterne/interne all'interno o all'esterno del cluster.
Durante la transizione, abbiamo notato che Kubernetes offre tutte le funzionalità di Nomad, che avevamo utilizzato in precedenza, aggiungendo anche molte novità. È possibile espanderlo tramite plugin e, di fatto, tramite tipi di risorse personalizzati. Ciò significa che non solo è possibile utilizzare ciò che è fornito in Kubernetes di default, ma si può creare una risorsa e un servizio personalizzati che leggono la vostra risorsa. Questo offre ulteriori opportunità per espandere il vostro sistema senza dover reinstallare Kubernetes o effettuare modifiche.
Un esempio di tale utilizzo è Prometheus, che viene eseguito all'interno del nostro cluster Kubernetes. Per iniziare a raccogliere metriche da un servizio, dobbiamo aggiungere alla descrizione del servizio un tipo di risorsa aggiuntivo, noto come service-monitor. Prometheus, essendo in grado di leggere tipi di risorse personalizzati mentre è in esecuzione su Kubernetes, inizia automaticamente a raccogliere metriche dal nuovo sistema. Questo è molto comodo.
Il primo deploy che abbiamo fatto in Kubernetes risale a marzo 2018. Da allora, non abbiamo mai riscontrato problemi. Funziona in modo piuttosto stabile senza bug significativi. Inoltre, possiamo espanderlo ulteriormente. Oggi abbiamo a disposizione tutte le funzionalità che ci servono, e siamo molto soddisfatti del ritmo di sviluppo di Kubernetes. Attualmente, più di 3000 contenitori sono attivi in Kubernetes. Il cluster utilizza diversi nodi. È gestibile, stabile e altamente controllato.
Fonte: habr.com
