Requisiti per lo sviluppo di un'applicazione in Kubernetes

Oggi ho intenzione di parlare di come scrivere applicazioni e quali sono i requisiti affinché la tua applicazione funzioni bene in Kubernetes. In modo che non ci siano grattacapi con l'applicazione, in modo che tu non debba inventare e costruire alcun "cratch" attorno ad essa - e tutto funzioni come previsto da Kubernetes stesso.

Questa conferenza fa parte di "Scuola serale Slurm su Kubernetes" È possibile visionare le lezioni teoriche aperte della Evening School su Youtube, raggruppati in una playlist. Per coloro che preferiscono il testo piuttosto che il video, abbiamo preparato questo articolo.

Mi chiamo Pavel Selivanov, attualmente sono il principale ingegnere DevOps presso Mail.ru Cloud Solutions, creiamo cloud, creiamo kubernetes di gestione e così via. I miei compiti ora includono l'assistenza allo sviluppo, l'implementazione di questi cloud, l'implementazione delle applicazioni che scriviamo e lo sviluppo diretto degli strumenti che forniamo ai nostri utenti.

Requisiti per lo sviluppo di un'applicazione in Kubernetes

Mi sono occupato di DevOps, penso negli ultimi, probabilmente, tre anni. Ma, in linea di principio, faccio ciò che fa DevOps probabilmente da circa cinque anni. Prima di allora, mi occupavo principalmente di questioni amministrative. Ho iniziato a lavorare con Kubernetes molto tempo fa, probabilmente sono passati circa quattro anni da quando ho iniziato a lavorarci.

In generale, ho iniziato quando Kubernetes era probabilmente la versione 1.3, e forse 1.2, quando era ancora agli inizi. Ora non è più agli inizi ed è ovvio che c'è un'enorme richiesta nel mercato di ingegneri che vorrebbero poter realizzare Kubernetes. E le aziende hanno una domanda molto elevata di queste persone. Pertanto, in effetti, è apparsa questa conferenza.

Se parliamo secondo lo schema di cui parleremo, appare così, tra parentesi è scritto (TL;DR) - “troppo lungo; non leggere". La mia presentazione di oggi sarà composta da elenchi infiniti.

Requisiti per lo sviluppo di un'applicazione in Kubernetes

In effetti, io stesso non mi piacciono tali presentazioni quando vengono fatte, ma questo è un argomento tale che quando stavo preparando questa presentazione, semplicemente non ho capito come organizzare queste informazioni in modo diverso.

Perché, in generale, queste informazioni sono "ctrl+c, ctrl+v", provenienti, tra le altre cose, dal nostro Wiki nella sezione DevOps, dove abbiamo scritto i requisiti per gli sviluppatori: "ragazzi, in modo che lanciamo la vostra applicazione in Kubernetes, dovrebbe essere così."

Ecco perché la presentazione si è rivelata un elenco così ampio. Scusa. Cercherò di raccontare il più possibile in modo che non sia noioso, se possibile.

Cosa vedremo ora:

  • questi sono, in primo luogo, i log (log delle applicazioni?), cosa farne in Kubernetes, cosa farne, cosa dovrebbero essere;
  • cosa fare con le configurazioni in Kubernetes, quali sono i modi migliori e peggiori per configurare un'applicazione per Kubernetes;
  • Parliamo di cosa sono i controlli di accessibilità in generale, come dovrebbero essere;
  • parliamo di cos'è uno spegnimento grazioso;
  • parliamo ancora di risorse;
  • Tocchiamo ancora una volta il tema dell'archiviazione dei dati;
  • e alla fine ti dirò qual è il termine di questa misteriosa applicazione cloud-native. Cloudnativeness, come aggettivo di questo termine.

logs

Suggerisco di iniziare con i log, ovvero dove questi log devono essere inseriti in Kubernetes. Ora hai avviato un'applicazione in Kubernetes. Secondo i classici, in precedenza le applicazioni scrivevano sempre i log da qualche parte in un file. Le applicazioni dannose hanno scritto i registri in un file nella directory home dello sviluppatore che ha avviato l'applicazione. Le buone applicazioni hanno scritto i log in un file da qualche parte /var/log.

Requisiti per lo sviluppo di un'applicazione in Kubernetes

Di conseguenza, inoltre, i bravi amministratori avevano configurato nelle loro infrastrutture alcune cose che questi log potevano ruotare: lo stesso rsyslog, che esamina questi log e quando succede loro qualcosa, ce ne sono molti, crea copie di backup, inserisce i log lì , elimina i vecchi file, più di una settimana, sei mesi e anche di più. In teoria, dovremmo disporre di disposizioni affinché, semplicemente perché l'applicazione scrive i log, lo spazio sui server di produzione (server di combattimento?) non si esaurisca. E, di conseguenza, l'intera produzione non si è fermata a causa dei tronchi.

Quando ci spostiamo nel mondo di Kubernetes e lì eseguiamo la stessa cosa, la prima cosa a cui puoi prestare attenzione è il fatto che le persone, mentre scrivevano i log in un file, continuano a scriverli.

Si scopre che se parliamo di Kubernetes, il posto giusto per scrivere i log da qualche parte da un contenitore docker è semplicemente scriverli dall'applicazione nel cosiddetto Stdout/Stderr, cioè i flussi di output standard del sistema operativo, l'output dell'errore standard. Questo è il modo più corretto, semplice e logico per inserire i log in linea di principio in Docker e nello specifico in Kubernetis. Perché se la tua applicazione scrive log su Stdout/Stderr, spetta a Docker e al componente aggiuntivo Kubernetes decidere cosa fare con questi log. Docker creerà per impostazione predefinita i suoi file speciali in formato JSON.

Qui sorge la domanda: cosa farai dopo con questi registri? Il modo più semplice è chiaro, abbiamo la capacità di farlo kubectl logs e guarda questi log di questi “pod”. Ma, probabilmente, questa non è un'opzione molto buona: è necessario fare qualcos'altro con i registri.

Per ora, parliamo allo stesso tempo, dato che abbiamo toccato l'argomento dei log, di come dovrebbero apparire i log. Cioè, questo non si applica direttamente a Kubernetes, ma quando inizieremo a pensare a cosa fare con i log, sarebbe bene pensare anche a questo.

Abbiamo bisogno di una sorta di strumento, in modo amichevole, che prenda questi log che il nostro docker inserisce nei suoi file e li invii da qualche parte. In generale, di solito lanciamo una sorta di agente all'interno di Kubernetes sotto forma di DaemonSet, un raccoglitore di log, a cui viene semplicemente indicato dove si trovano i log raccolti da Docker. E questo agente di raccolta semplicemente li prende, forse anche in qualche modo li analizza lungo il percorso, forse li arricchisce con alcune meta-informazioni aggiuntive e, alla fine, li invia per l'archiviazione da qualche parte. Le variazioni sono già possibili lì. Il più comune è probabilmente Elasticsearch, dove puoi archiviare i log e recuperarli comodamente da lì. Quindi, utilizzando una richiesta, utilizzando Kibana, ad esempio, crea grafici basati su di essi, crea avvisi basati su di essi e così via.

L'idea più importante, voglio ripeterlo ancora una volta, è che all'interno di Docker, in particolare all'interno di Kubernetes, archiviare i propri log in un file è una pessima idea.

Perché in primo luogo è difficile inserire i log all'interno del contenitore in un file. Devi prima andare nel contenitore, eseguirlo lì e poi guardare i log. Il punto successivo è che se sono presenti log in un file, i contenitori di solito hanno un ambiente minimalista e non ci sono utilità solitamente necessarie per il normale lavoro con i log. Seppelliteli, guardateli, apriteli in un editor di testo. Il momento successivo è quando avremo i log in un file all'interno di un contenitore, se questo contenitore viene eliminato, capisci, i log moriranno insieme ad esso. Di conseguenza, qualsiasi riavvio del contenitore significa che non ci sono più registri. Ancora una volta, pessima opzione.

E l'ultimo punto è che all'interno dei contenitori di solito hai la tua applicazione e basta: di solito è l'unico processo in esecuzione. Non si parla affatto di alcun processo che ruoterebbe i file con i tuoi registri. Non appena i log iniziano a essere scritti su un file, ciò significa che, scusatemi, inizieremo a perdere il server di produzione. Perché, in primo luogo, sono difficili da trovare, nessuno li tiene traccia e nessuno li controlla: di conseguenza, il file cresce all'infinito finché lo spazio sul server non si esaurisce. Pertanto ripeto che accedere a un file in Docker, in particolare in Kubernetes, è una cattiva idea.

Il punto successivo, qui voglio parlarne di nuovo: poiché stiamo toccando l'argomento dei log, sarebbe bene parlare di come dovrebbero apparire i log per rendere conveniente lavorare con loro. Come ho detto, l'argomento non è direttamente correlato a Kubernetes, ma si collega molto bene all'argomento DevOps. Sul tema della cultura dello sviluppo e dell'amicizia tra questi due diversi dipartimenti: Dev e Ops, in modo che tutti si sentano a proprio agio.

Ciò significa che idealmente, oggi, i log dovrebbero essere scritti in formato JSON. Se hai qualche tua applicazione incomprensibile, che scrive log in formati incomprensibili perché inserisci qualche tipo di stampa o qualcosa del genere, allora è il momento di cercare su Google qualche tipo di framework, una sorta di wrapper che ti permetta di implementare il normale logging; abilita lì i parametri di registrazione in JSON, poiché JSON è un formato semplice, analizzarlo è semplice.

Se il tuo JSON non funziona secondo alcuni criteri, nessuno sa quali, almeno scrivi i log in un formato che possa essere analizzato. Qui, piuttosto, vale la pena pensare al fatto che, ad esempio, se stai eseguendo un gruppo di contenitori o solo processi con nginx, e ognuno ha le proprie impostazioni di registrazione, probabilmente ti sembrerà molto scomodo analizzarli. Perché per ogni nuova istanza di nginx devi scrivere il tuo parser, perché scrivono i log in modo diverso. Ancora una volta, probabilmente valeva la pena di assicurarsi che tutte queste istanze nginx avessero la stessa configurazione di registrazione e scrivessero tutti i loro registri in modo assolutamente uniforme. Lo stesso vale per assolutamente tutte le applicazioni.

Alla fine, voglio anche aggiungere benzina sul fuoco dicendo che, idealmente, i registri in formato multilinea dovrebbero essere evitati. Il punto è questo: se hai mai lavorato con i raccoglitori di log, molto probabilmente hai visto ciò che ti promettono, ovvero che possono lavorare con log su più righe, sapere come raccoglierli e così via. In effetti, secondo me, nessun singolo collezionista oggi può raccogliere registri multilinea normalmente, in modo completo e senza errori. In modo umano, in modo che sia comodo e senza errori.

Requisiti per lo sviluppo di un'applicazione in Kubernetes

Ma l'analisi dello stack è sempre log su più righe e come evitarli. La domanda qui è che un log è la registrazione di un evento e stactrace non è in realtà un log. Se raccogliamo log e li inseriamo da qualche parte in Elasticsearch e poi ne ricaviamo grafici, creiamo alcuni report sull'attività dell'utente sul tuo sito, quando ottieni uno stack trace, significa che sta accadendo qualcosa di inaspettato, una situazione non gestita nella tua applicazione. Ed ha senso caricare automaticamente uno stack trace da qualche parte in un sistema in grado di tracciarli.

Questo è un software (lo stesso Sentry) realizzato appositamente per funzionare con l'analisi dello stack. Può creare immediatamente attività automatizzate, assegnarle a qualcuno, avvisare quando si verificano stacttrace, raggruppare queste stacttrace per un tipo e così via. In linea di principio non ha molto senso parlare di stactrace quando parliamo di log, perché dopo tutto si tratta di cose diverse con scopi diversi.

Configurazione

Successivamente parleremo della configurazione in Kubernetes: cosa farne e come dovrebbero essere configurate le applicazioni all'interno di Kubernetes. In generale, di solito dico che Docker non riguarda i container. Tutti sanno che Docker riguarda i container, anche quelli che non hanno lavorato molto con Docker. Ripeto, Docker non riguarda i container.

Docker, secondo me, riguarda gli standard. Ed esistono standard praticamente per tutto: standard per creare la tua applicazione, standard per installarla.

Requisiti per lo sviluppo di un'applicazione in Kubernetes

E questa cosa - l'abbiamo usata prima, è diventata particolarmente popolare con l'avvento dei contenitori - questa cosa si chiama variabili ENV (ambiente), cioè variabili di ambiente che si trovano nel tuo sistema operativo. Questo è generalmente un modo ideale per configurare la tua applicazione, perché se hai applicazioni in JAVA, Python, Go, Perl, Dio non voglia, e possono tutte leggere l'host del database, l'utente del database e le variabili della password del database, allora è l'ideale. Hai applicazioni in quattro lingue diverse configurate nello stesso modo nel piano database. Non ci sono più configurazioni diverse.

Tutto può essere configurato utilizzando le variabili ENV. Quando parliamo di Kubernetes, esiste un ottimo modo per dichiarare le variabili ENV direttamente all'interno del Deployment. Di conseguenza, se parliamo di dati segreti, possiamo immediatamente inserire i dati segreti dalle variabili ENV (password ai database, ecc.) in un segreto, creare un cluster segreto e indicare nella descrizione ENV in Deployment che non stiamo dichiarando direttamente il valore di questa variabile e il valore di questa variabile della password del database verranno letti dal segreto. Questo è il comportamento standard di Kubernetes. E questa è l'opzione più ideale per configurare le tue applicazioni. Proprio a livello di codice, questo vale ancora una volta per gli sviluppatori. Se siete DevOps, potete chiedere: “Ragazzi, per favore insegnate alla vostra applicazione a leggere le variabili di ambiente. E saremo tutti felici."

Se tutti in azienda leggono le stesse variabili di ambiente con lo stesso nome, allora è fantastico. In modo che non succeda che alcuni aspettino il database postgres, altri aspettano il nome del database, altri aspettano qualcos'altro, altri aspettano un dbn di qualche tipo, in modo che, di conseguenza, ci sia uniformità.

Il problema sorge quando hai così tante variabili di ambiente che devi semplicemente aprire Deployment e ci sono cinquecento righe di variabili di ambiente. In questo caso, hai semplicemente superato le variabili ambientali e non hai più bisogno di torturarti. In questo caso, avrebbe senso iniziare a utilizzare configs. Cioè, addestra la tua applicazione a utilizzare le configurazioni.

L'unica domanda è che le configurazioni non sono quello che pensi. Config.pi non è una configurazione comoda da usare. O qualche configurazione nel tuo formato, in alternativa dotata: anche questa non è la configurazione che intendo.

Ciò di cui sto parlando è la configurazione in formati accettabili, ovvero lo standard di gran lunga più popolare è lo standard .yaml. È chiaro come leggerlo, è leggibile dall'uomo, è chiaro come leggerlo dall'applicazione.

Di conseguenza, oltre a YAML, puoi anche utilizzare, ad esempio, JSON, l'analisi è comoda quanto YAML in termini di lettura della configurazione dell'applicazione da lì. È notevolmente più scomodo leggere per le persone. Puoi provare il formato, a la ini. È abbastanza comodo da leggere, da un punto di vista umano, ma potrebbe essere scomodo elaborarlo automaticamente, nel senso che se mai volessi generare le tue configurazioni, il formato ini potrebbe già essere scomodo da generare.

Ma in ogni caso, qualunque sia il formato scelto, il punto è che dal punto di vista Kubernetes è molto conveniente. Puoi inserire l'intera configurazione all'interno di Kubernetes, nel ConfigMap. E poi prendi questa mappa di configurazione e chiedi che venga montata all'interno del tuo pod in una directory specifica, dove la tua applicazione leggerà la configurazione da questa mappa di configurazione come se fosse solo un file. Questo, in effetti, è ciò che è bene fare quando si hanno molte opzioni di configurazione nella propria applicazione. Oppure è solo una sorta di struttura complessa, c'è l'annidamento.

Se disponi di una mappa di configurazione, puoi benissimo insegnare alla tua applicazione, ad esempio, a tenere traccia automaticamente delle modifiche nel file in cui è montata la mappa di configurazione e anche a ricaricare automaticamente la tua applicazione quando le configurazioni cambiano. Questa sarebbe generalmente un'opzione ideale.

Ancora una volta, ne ho già parlato: le informazioni segrete non sono nella mappa di configurazione, le informazioni segrete non sono nelle variabili, le informazioni segrete non sono nei segreti. Da lì, collega queste informazioni segrete alla diplomazia. Di solito memorizziamo tutte le descrizioni di oggetti, distribuzioni, mappe di configurazione e servizi Kubernetes in git. Di conseguenza, inserire la password nel database in Git, anche se è il tuo Git, che hai internamente in azienda, è una cattiva idea. Perché, come minimo, git ricorda tutto e rimuovere semplicemente le password da lì non è così facile.

Controllo sanitario

Il punto successivo è questa cosa chiamata controllo sanitario. In generale, un controllo dello stato verifica semplicemente che l'applicazione funzioni. Allo stesso tempo, parliamo molto spesso di alcune applicazioni web, per le quali, di conseguenza, dal punto di vista del controllo dello stato (è meglio non tradurre qui e oltre) si tratterà di un URL speciale, che elaborano come uno standard, di solito lo fanno /health.

Quando si accede a questo URL, la nostra applicazione dice rispettivamente "sì, okay, per me va tutto bene, 200" oppure "no, per me non va tutto bene, circa 500". Di conseguenza, se la nostra applicazione non è http, non un'applicazione web, ora stiamo parlando di una sorta di demone, possiamo capire come eseguire i controlli di integrità. Cioè non è necessario, se l'applicazione non è http, allora tutto funziona senza controllo sanitario e questo non può essere fatto in alcun modo. Puoi aggiornare periodicamente alcune informazioni nel file, puoi creare qualche comando speciale per il tuo demone, come, daemon status, che dirà "sì, va tutto bene, il demone funziona, è vivo".

Cosa serve? La prima e più ovvia cosa è probabilmente il motivo per cui è necessario un controllo dello stato di salute: per capire se l'applicazione funziona. Voglio dire, è semplicemente stupido, quando è attivo adesso, sembra che funzioni, quindi puoi essere sicuro che funzioni. E si scopre che l'applicazione è in esecuzione, il contenitore è in esecuzione, l'istanza funziona, tutto va bene - e poi gli utenti hanno già escluso tutti i numeri di telefono dal supporto tecnico e dicono "cosa stai..., tu mi sono addormentato, niente funziona."

Un controllo dello stato è proprio un modo per vedere dal punto di vista dell’utente che funziona. Uno dei metodi. Mettiamola così. Dal punto di vista di Kubernetes, questo è anche un modo per capire quando si avvia l'applicazione, perché comprendiamo che c'è differenza tra quando il contenitore è stato lanciato, creato e avviato e quando l'applicazione è stata lanciata direttamente in questo contenitore. Perché se prendiamo un'applicazione Java media e proviamo ad avviarla nel dock, per quaranta secondi, o anche un minuto, o anche dieci, può avviarsi perfettamente. In questo caso puoi almeno bussare alle sue porte, lì non risponderà, cioè non è ancora pronto a ricevere il traffico.

Ancora una volta, con l'aiuto di un controllo dello stato e con l'aiuto del fatto che stiamo girando qui, possiamo capire in Kubernetes che non solo il contenitore è salito nell'applicazione, ma l'applicazione stessa è stata avviata, risponde già al controllo dello stato, il che significa che possiamo inviare traffico lì.

Requisiti per lo sviluppo di un'applicazione in Kubernetes

Ciò di cui sto parlando ora si chiama Readiness/Liveness test all'interno di Kubernetes; di conseguenza, i nostri readiness test sono responsabili della disponibilità dell'applicazione in bilanciamento. Cioè, se vengono eseguiti test di disponibilità nell'applicazione, allora è tutto ok, il traffico client viene inviato all'applicazione. Se i test di disponibilità non vengono eseguiti, l'applicazione semplicemente non partecipa, questa particolare istanza non partecipa al bilanciamento, viene rimossa dal bilanciamento e il traffico client non scorre. Di conseguenza, sono necessari test di attività all'interno di Kubernetes in modo che, se l'applicazione si blocca, possa essere riavviata. Se il test di attività non funziona per un'applicazione dichiarata in Kubernetes, l'applicazione non viene semplicemente rimossa dal bilanciamento, ma viene riavviata.

Ed ecco un punto importante che vorrei menzionare: da un punto di vista pratico, il readiness test viene solitamente utilizzato più spesso ed è più spesso necessario del liveness test. Cioè, dichiarare semplicemente sconsideratamente sia i test di prontezza che quelli di attività, perché Kubernetes può farlo, e usiamo tutto ciò che può fare, non è una buona idea. Spiegherò perché. Perché il punto numero due nei test è che sarebbe una buona idea controllare il servizio sottostante nei controlli sanitari. Ciò significa che se si dispone di un'applicazione Web che fornisce alcune informazioni, che a loro volta, naturalmente, devono essere prese da qualche parte. In un database, ad esempio. Bene, salva le informazioni che arrivano in questa API REST nello stesso database. Quindi, di conseguenza, se il tuo controllo di salute risponde semplicemente come slashhealth contattato, l'applicazione dice "200, okay, va tutto bene" e allo stesso tempo il database della tua applicazione è inaccessibile e l'applicazione di controllo di salute dice "200, okay, va tutto bene" ” - Questo è un pessimo controllo sanitario. Non è così che dovrebbe funzionare.

Cioè, la tua domanda, quando arriva una richiesta /health, non si limita a rispondere "200, ok", prima va, ad esempio, al database, tenta di connettersi ad esso, fa qualcosa di molto semplice lì, come selezionarne uno, controlla solo che ci sia una connessione nel database ed è possibile interrogare il database. Se tutto ciò ha avuto successo, la risposta è “200, ok”. Se non ha successo, dice che c'è un errore, il database non è disponibile.

Pertanto, a questo proposito, torno nuovamente ai test di prontezza/vivacità: perché molto probabilmente hai bisogno di un test di prontezza, ma un test di vitalità è in questione. Perché se descrivi i controlli sanitari esattamente come ho appena detto, si scoprirà che non è disponibile nella parte dell'istanzaв или со всех instancein un database, ad esempio. Quando hai dichiarato un test di disponibilità, i nostri controlli di integrità hanno iniziato a fallire e, di conseguenza, tutte le applicazioni da cui il database non è accessibile, vengono semplicemente disattivate dal bilanciamento e di fatto si "bloccano" proprio in uno stato trascurato e aspettano che i loro database si interrompano. lavoro.

Se abbiamo dichiarato un test di attività, immagina che il nostro database si sia rotto e nel tuo Kubernetes metà di tutto inizi a riavviarsi perché il test di attività fallisce. Ciò significa che è necessario riavviare. Questo non è affatto quello che vuoi, ho anche avuto un'esperienza personale nella pratica. Avevamo un'applicazione di chat scritta in JS e inserita in un database Mongo. E il problema era che all'inizio del mio lavoro con Kubernetes abbiamo descritto la prontezza e la vivacità dei test in base al principio che Kubernetes può farlo, quindi lo useremo. Di conseguenza, ad un certo punto Mongo è diventato un po’ “noioso” e il campione ha cominciato a fallire. Di conseguenza, secondo il test della pioggia, i baccelli hanno iniziato a "uccidere".

Come hai capito, quando vengono "uccisi", questa è una chat, cioè ci sono molte connessioni da parte dei client che vi pendono. Inoltre vengono "uccisi" - no, non client, solo connessioni - non tutti allo stesso tempo, e poiché non vengono uccisi contemporaneamente, alcuni prima, altri dopo, non iniziano allo stesso tempo tempo. Oltre alla casualità standard, non possiamo prevedere ogni volta con precisione al millisecondo l'ora di inizio dell'applicazione, quindi lo fanno un'istanza alla volta. Un infospot si alza, si aggiunge al bilanciamento, tutti i clienti vengono lì, non può sopportare un tale carico, perché è solo e, grosso modo, ce ne sono una dozzina che lavorano lì, e cade. Il prossimo si alza, tutto il carico ricade su di lui, cade anche lui. Ebbene, queste cadute continuano a precipitare. Alla fine, come è stato risolto: abbiamo semplicemente dovuto interrompere rigorosamente il traffico degli utenti verso questa applicazione, lasciare che tutte le istanze aumentassero e quindi avviare tutto il traffico degli utenti contemporaneamente in modo che fosse già distribuito tra tutte e dieci le istanze.

Se non fosse stato per l'annuncio di questo test di attività, che costringerebbe il tutto a riavviarsi, l'applicazione lo avrebbe gestito perfettamente. Ma per noi tutto, dal bilanciamento, è disabilitato, perché i database sono inaccessibili e tutti gli utenti sono “caduti”. Poi, quando questo database diventa disponibile, tutto è incluso nel bilanciamento, ma non è necessario riavviare le applicazioni e non è necessario sprecare tempo e risorse su questo. Sono già tutti qui, sono pronti per il traffico, quindi il traffico si apre, va tutto bene: l'applicazione è a posto, tutto continua a funzionare.

Pertanto, i test di prontezza e di vitalità sono diversi, inoltre, in teoria puoi eseguire diversi controlli di salute, un tipo radii, un tipo liv, ad esempio, e controllare cose diverse. Durante i test di preparazione, controlla i tuoi backend. E in un test di attività, ad esempio, non controlli dal punto di vista che il test di attività è generalmente solo un'applicazione che risponde, se è in grado di rispondere.

Perché il test di vitalità, in generale, avviene quando siamo “bloccati”. È iniziato un ciclo infinito o qualcos'altro e non vengono più elaborate richieste. Pertanto, ha senso anche separarli e implementare in essi una logica diversa.

Riguardo a cosa devi rispondere quando fai un test, quando fai controlli sanitari. È davvero una seccatura. Coloro che hanno familiarità con questo probabilmente rideranno, ma sul serio, nella mia vita ho visto servizi che rispondono "200" nel XNUMX% dei casi. Cioè, chi ha successo. Ma allo stesso tempo nel corpo della risposta scrivono “questo e quell’errore”.

Cioè, lo stato della risposta ti arriva: tutto ha successo. Ma allo stesso tempo devi analizzare il corpo, perché il corpo dice “scusi, la richiesta si è conclusa con un errore” e questa è solo la realtà. L'ho visto nella vita reale.

E affinché alcune persone non lo trovino divertente e altri lo trovino molto doloroso, vale comunque la pena attenersi a una semplice regola. Nei controlli sanitari e, in linea di principio, quando si lavora con le applicazioni web.

Se tutto è andato bene, allora rispondi con la duecentesima risposta. In linea di principio, qualsiasi duecentesima risposta ti andrà bene. Se leggi molto bene Ragsy e sai che alcuni stati di risposta sono diversi da altri, rispondi con quelli appropriati: 204, 5, 10, 15, qualunque cosa. Se non è molto buono, allora solo “due zero zero”. Se tutto va male e il controllo sanitario non risponde, rispondi con un cinquecentesimo qualsiasi. Ancora una volta, se capisci come rispondere, in che modo i diversi stati di risposta differiscono l'uno dall'altro. Se non capisci, allora 502 è la tua opzione per rispondere ai controlli sanitari se qualcosa va storto.

Questo è un altro punto, voglio tornare un po' sul controllo dei servizi sottostanti. Se inizi, ad esempio, a controllare tutti i servizi sottostanti che stanno dietro la tua applicazione, tutto in generale. Ciò che otteniamo dal punto di vista dell'architettura dei microservizi è un concetto come "basso accoppiamento", ovvero quando i tuoi servizi dipendono minimamente l'uno dall'altro. Se uno di essi fallisce, tutti gli altri senza questa funzionalità continueranno semplicemente a funzionare. Alcune funzionalità semplicemente non funzionano. Di conseguenza, se colleghi tutti i controlli sanitari tra loro, finirai con il fatto che una cosa cade nell'infrastruttura e, poiché è caduta, anche tutti i controlli sanitari di tutti i servizi iniziano a fallire - e in generale ci sono più infrastrutture per il intera architettura di microservizi N. Là tutto si oscurò.

Voglio quindi ripetere ancora una volta che è necessario verificare i servizi sottostanti, quelli senza i quali la vostra applicazione nel cento per cento dei casi non può svolgere il proprio lavoro. Cioè, è logico che se si dispone di un'API REST tramite la quale l'utente salva nel database o recupera dal database, in assenza di un database non è possibile garantire il lavoro con i propri utenti.

Ma se i tuoi utenti, quando li togli dal database, vengono ulteriormente arricchiti con altri metadati, da un altro backend, che inserisci prima di inviare una risposta al frontend - e questo backend non è disponibile, significa che dai il tuo risposta senza alcuna parte dei metadati.

Successivamente, abbiamo anche uno dei problemi dolorosi durante l'avvio delle applicazioni.

In realtà, questo non vale solo per Kubernetes in generale; è successo che la cultura di una sorta di sviluppo di massa e DevOps in particolare ha cominciato a diffondersi nello stesso periodo di Kubernetes. Pertanto, in generale, risulta che è necessario chiudere con garbo la propria applicazione senza Kubernetes. Anche prima di Kubernetes la gente lo faceva, ma con l’avvento di Kubernetes si è cominciato a parlarne in massa.

Arresto aggraziato

In generale, cos'è Graceful Shutdown e perché è necessario? Si tratta di quando la tua applicazione si blocca per qualche motivo, devi farlo app stop - oppure ricevi, ad esempio, un segnale dal sistema operativo, la tua applicazione deve capirlo e fare qualcosa al riguardo. Lo scenario peggiore, ovviamente, è quando la tua applicazione riceve un SIGTERM e dice "SIGTERM, aspettiamo, lavoriamo, non fare nulla". Questa è un'opzione decisamente sbagliata.

Requisiti per lo sviluppo di un'applicazione in Kubernetes

Un'opzione quasi altrettanto negativa è quando la tua applicazione riceve un SIGTERM e dice "hanno detto segterm, significa che stiamo finendo, non ho visto, non conosco alcuna richiesta dell'utente, non so che tipo di richieste su cui sto lavorando in questo momento, hanno detto SIGTERM, ciò significa che stiamo finendo " Anche questa è una cattiva opzione.

Quale opzione è buona? Il primo punto è tenere conto del completamento delle operazioni. Una buona opzione è che il tuo server tenga comunque conto di ciò che fa se riceve un SIGTERM.

SIGTERM è un soft shutdown, è appositamente progettato, può essere intercettato a livello di codice, può essere elaborato, diciamo che ora, aspetta, prima finiremo il lavoro che abbiamo, poi usciremo.

Dal punto di vista di Kubernetes, ecco come appare. Quando diciamo a un pod in esecuzione nel cluster Kubernetes "per favore, fermati, vai via", oppure veniamo riavviati o si verifica un aggiornamento quando Kubernetes ricrea i pod, Kubernetes invia proprio lo stesso messaggio SIGTERM al pod, attende un po' di tempo, e questo è il tempo che aspetta, è anche configurato, c'è un parametro così speciale nei diplomi e si chiama Graceful ShutdownTimeout. Come hai capito, non si chiama così per niente, e non per niente ne stiamo parlando adesso.

Lì possiamo dire specificamente quanto tempo dobbiamo aspettare tra il momento in cui inviamo SIGTERM all'applicazione e quando capiamo che l'applicazione sembra essere impazzita per qualcosa o è "bloccata" e non finirà - e dobbiamo invialo SIGKILL, cioè completa il suo lavoro. Cioè, di conseguenza, abbiamo una sorta di demone in esecuzione, che elabora le operazioni. Comprendiamo che in media le nostre operazioni su cui lavora il demone non durano più di 30 secondi alla volta. Di conseguenza, quando arriva SIGTERM, capiamo che il nostro demone può, al massimo, terminare 30 secondi dopo SIGTERM. Lo scriviamo, ad esempio, 45 secondi per ogni evenienza e diciamo che SIGTERM. Successivamente aspettiamo 45 secondi. In teoria, durante questo periodo il demone avrebbe dovuto completare la sua opera e porre fine a se stesso. Ma se all’improvviso non riesce più, significa che molto probabilmente è bloccato: non elabora più normalmente le nostre richieste. E in 45 secondi puoi tranquillamente inchiodarlo.

E qui, infatti, si possono prendere in considerazione anche 2 aspetti. Innanzitutto, comprendi che se hai ricevuto una richiesta, hai iniziato a lavorarci in qualche modo e non hai dato risposta all'utente, ma hai ricevuto SIGTERM, ad esempio. Ha senso perfezionarlo e dare una risposta all'utente. Questo è il punto numero uno in questo senso. Il punto numero due qui è che se scrivi la tua applicazione, generalmente costruisci l'architettura in modo tale da ricevere una richiesta per la tua applicazione, poi inizi a lavorare, inizi a scaricare file da qualche parte, a scaricare un database e quant'altro. - Quello. In generale, il tuo utente, la tua richiesta rimane bloccata per mezz'ora e aspetta che tu gli risponda, quindi, molto probabilmente, devi lavorare sull'architettura. Cioè, prendi in considerazione anche il buon senso che se le tue operazioni sono brevi, ha senso ignorare SIGTERM e modificarlo. Se le tue operazioni sono lunghe, in questo caso non ha senso ignorare SIGTERM. Ha senso riprogettare l'architettura per evitare operazioni così lunghe. In modo che gli utenti non si limitino a restare ad aspettare. Non lo so, crea una sorta di websocket lì, crea hook inversi che il tuo server invierà già al client, qualsiasi altra cosa, ma non forzare l'utente a rimanere sospeso per mezz'ora e aspetta solo una sessione fino a quando non rispondigli. Perché è imprevedibile dove potrebbe rompersi.

Quando la tua applicazione termina, dovresti fornire un codice di uscita appropriato. Cioè, se alla tua applicazione è stato chiesto di chiudersi, interrompersi ed è stata in grado di arrestarsi normalmente, non è necessario restituire una sorta di codice di uscita 1,5,255 e così via. Tutto ciò che non è zero code, almeno nei sistemi Linux, ne sono certo, è considerato fallito. Cioè, si ritiene che la tua domanda in questo caso sia terminata con un errore. Di conseguenza, in modo amichevole, se la tua applicazione è stata completata senza errori, dici 0 sull'output. Se la tua applicazione fallisce per qualche motivo, dici diverso da 0 nell'output. E puoi lavorare con queste informazioni.

E l'ultima opzione. È brutto quando il tuo utente invia una richiesta e si blocca per mezz'ora mentre la elabori. Ma in generale vorrei anche dire cosa ne vale la pena dal lato del cliente. Non importa se disponi di un'applicazione mobile, front-end, ecc. È necessario tenere conto che in generale la sessione dell’utente può essere terminata, tutto può succedere. Una richiesta inviata potrebbe, ad esempio, essere sottoelaborata e non essere restituita alcuna risposta. Il tuo frontend o la tua applicazione mobile (qualsiasi frontend in generale, diciamo così) dovrebbe tenerne conto. Se lavori con i websocket, questo è generalmente il peggior dolore che abbia mai avuto.

Quando gli sviluppatori di alcune chat regolari non lo sanno, si scopre che il websocket può rompersi. Per loro, quando succede qualcosa al proxy, cambiamo semplicemente la configurazione e viene ricaricato. Naturalmente, in questo caso tutte le sessioni di lunga durata vengono strappate. Gli sviluppatori corrono da noi e dicono: "Ragazzi, cosa state facendo, la chat si è interrotta per tutti i nostri clienti!" Diciamo loro: “Cosa state facendo? I tuoi client non riescono a riconnettersi? Dicono: “No, abbiamo bisogno che le sessioni non vengano strappate”. In breve, questa è in realtà una sciocchezza. Il lato client deve essere preso in considerazione. Soprattutto, come ho detto, con sessioni di lunga durata come i websocket, può rompersi e, senza che l'utente se ne accorga, è necessario essere in grado di reinstallare tali sessioni. E poi è tutto perfetto.

Ресурсы

In realtà, qui ti racconterò semplicemente una storia semplice. Ancora una volta dalla vita reale. La cosa più disgustosa che abbia mai sentito riguardo alle risorse.

Risorse in questo caso, intendo qualche tipo di richiesta, limiti che puoi inserire nei pod nei tuoi cluster Kubernetes. La cosa più divertente che ho sentito da uno sviluppatore... Uno dei miei colleghi sviluppatori in un precedente posto di lavoro una volta ha detto: "La mia applicazione non si avvia nel cluster". Ho guardato per vedere che non si avviava, ma o non rientrava nelle risorse, oppure avevano fissato limiti molto piccoli. In breve, l'applicazione non può essere avviata a causa delle risorse. Io dico: “Non inizierà a causa delle risorse, decidi tu quanto ti serve e stabilisci un valore adeguato”. Dice: “Che tipo di risorse?” Ho iniziato a spiegargli che bisogna impostare Kubernetes, limiti alle richieste e bla, bla, bla. L’uomo ha ascoltato per cinque minuti, ha annuito e ha detto: “Sono venuto qui per lavorare come sviluppatore, non voglio sapere nulla di nessuna risorsa. Sono venuto qui per scrivere codice e basta.” È triste. Questo è un concetto molto triste dal punto di vista di uno sviluppatore. Soprattutto nel mondo moderno, per così dire, dei devops progressisti.

Perché sono necessarie le risorse? Esistono 2 tipi di risorse in Kubernetes. Alcune sono chiamate richieste, altre sono chiamate limiti. Per risorse capiremo che fondamentalmente ci sono sempre solo due restrizioni fondamentali. Ovvero, limiti di tempo della CPU e limiti di RAM per un contenitore in esecuzione in Kubernetes.

Un limite pone un limite superiore al modo in cui una risorsa può essere utilizzata nell'applicazione. Cioè, se dici 1 GB di RAM nei limiti, la tua applicazione non sarà in grado di utilizzare più di 1 GB di RAM. E se all'improvviso vuole e prova a farlo, allora un processo chiamato oom killer, memoria esaurita, cioè, arriverà e ucciderà la tua applicazione, cioè si riavvierà semplicemente. Le applicazioni non verranno riavviate in base alla CPU. In termini di CPU, se un'applicazione tenta di utilizzarne molta, più di quanto specificato nei limiti, la CPU verrà semplicemente selezionata rigorosamente. Ciò non comporta riavvii. Questo è il limite, questo è il limite superiore.

E c'è una richiesta. Una richiesta è il modo in cui Kubernetes comprende come i nodi nel tuo cluster Kubernetes vengono popolati con le applicazioni. Cioè, una richiesta è una sorta di commit della tua applicazione. Dice cosa voglio usare: "Vorrei che mi riservassi questa quantità di CPU e questa memoria". Un'analogia così semplice. E se avessimo un nodo che ha, non so, 8 CPU in totale. E lì arriva un pod, le cui richieste dicono 1 CPU, il che significa che al nodo sono rimaste 7 CPU. Cioè, non appena 8 pod arrivano a questo nodo, ognuno dei quali ha 1 CPU nelle proprie richieste, il nodo, come se dal punto di vista di Kubernetes, avesse esaurito la CPU e non è possibile inviare più pod con richieste lanciato su questo nodo. Se tutti i nodi esauriscono la CPU, Kubernetes inizierà a dire che non ci sono nodi adatti nel cluster per eseguire i tuoi pod perché la CPU è esaurita.

Perché sono necessarie le richieste e perché senza richieste penso che non sia necessario avviare nulla in Kubernetes? Immaginiamo una situazione ipotetica. Avvia la tua applicazione senza richieste, Kubernetes non sa quanto di ciò che hai, a quali nodi puoi inviarlo. Bene, spinge, spinge, spinge sui nodi. Ad un certo punto, inizierai a ricevere traffico verso la tua applicazione. E una delle applicazioni inizia improvvisamente a utilizzare le risorse fino ai limiti che ha in base ai limiti. Si scopre che c'è un'altra applicazione nelle vicinanze e anch'essa necessita di risorse. Il nodo inizia effettivamente a esaurire fisicamente le risorse, ad esempio OP. Il nodo inizia effettivamente a esaurire fisicamente le risorse, ad esempio la memoria ad accesso casuale (RAM). Quando un nodo si esaurisce, prima di tutto la finestra mobile smetterà di rispondere, poi il cubelet, quindi il sistema operativo. Diventeranno semplicemente incoscienti e TUTTO smetterà definitivamente di funzionare per te. Cioè, questo porterà il tuo nodo a bloccarsi e dovrai riavviarlo. Insomma, la situazione non è delle migliori.

E quando hai richieste, i limiti non sono molto diversi, almeno non molte volte superiori ai limiti o alle richieste, quindi puoi avere un riempimento così normale e razionale delle applicazioni attraverso i nodi dei cluster Kubernetes. Allo stesso tempo, Kubernetes è approssimativamente consapevole di quanto di ciò che mette dove, di quanto di ciò che viene utilizzato dove. Cioè, è proprio un momento del genere. È importante capirlo. Ed è importante controllare che questo venga indicato.

Archiviazione dei dati

Il nostro prossimo punto riguarda l'archiviazione dei dati. Cosa farne e in generale cosa fare con la persistenza in Kubernetes?

Penso, ancora una volta, all'interno del ns Scuola serale, c'era un argomento sul database in Kubernetes. E mi sembra di sapere anche approssimativamente cosa ti hanno detto i tuoi colleghi quando ti è stato chiesto: "È possibile eseguire un database in Kubernetes?" Per qualche ragione, mi sembra che i tuoi colleghi avrebbero dovuto dirti che se ti stai chiedendo se è possibile eseguire un database in Kubernetes, allora è impossibile.

La logica qui è semplice. Per ogni evenienza, lo spiegherò ancora una volta, se sei una persona davvero in gamba in grado di costruire un sistema di archiviazione di rete distribuito abbastanza tollerante ai guasti, capisci come adattare un database in questo caso, come dovrebbe funzionare il cloud nativo nei contenitori in un database in generale. Molto probabilmente, non hai domande su come eseguirlo. Se hai una domanda del genere e vuoi assicurarti che tutto si svolga e resista fino alla morte nella produzione e non cada mai, allora questo non accadrà. Con questo approccio sei sicuro di darti la zappa sui piedi. Quindi è meglio non farlo.

Cosa dovremmo fare con i dati che la nostra applicazione vorrebbe archiviare, alcune immagini caricate dagli utenti, alcune cose che la nostra applicazione genera durante il suo funzionamento, ad esempio all'avvio? Cosa farne in Kubernetes?

In generale, idealmente sì, certo, Kubernetes è molto ben progettato ed è stato inizialmente concepito per applicazioni stateless. Cioè, per quelle applicazioni che non memorizzano affatto le informazioni. Questo è l'ideale.

Ma, ovviamente, non sempre esiste l’opzione ideale. E allora? Il primo e più semplice punto è prendere una sorta di S3, non solo fatto in casa, di cui non è chiaro come funzioni, ma da qualche provider. Un fornitore buono e normale e insegna alla tua applicazione a utilizzare S3. Cioè, quando il tuo utente desidera caricare un file, dì "qui, per favore, caricalo su S3". Quando vuole riceverlo, dì: "Ecco un collegamento a S3 e prendilo da qui". Questo è l'ideale.

Se improvvisamente per qualche motivo questa opzione ideale non è adatta, hai un'applicazione che non hai scritto, non sviluppi, o è una sorta di terribile eredità, non può utilizzare il protocollo S3, ma deve funzionare con le directory locali in cartelle locali. Prendi qualcosa di più o meno semplice, distribuisci Kubernetes. Cioè, schermare immediatamente Ceph per alcuni compiti minimi, mi sembra, è una cattiva idea. Perché Ceph, ovviamente, è bravo e alla moda. Ma se non capisci veramente cosa stai facendo, una volta che hai messo qualcosa su Ceph, puoi facilmente e semplicemente non tirarlo mai più fuori. Perché, come sai, Ceph memorizza i dati nel suo cluster in forma binaria e non sotto forma di semplici file. Pertanto, se improvvisamente il cluster Ceph si guasta, c'è un'alta probabilità che non riceverai mai più i tuoi dati da lì.

Faremo un corso su Ceph, puoi farlo familiarizzare con il programma e inviare una domanda.

Pertanto, è meglio fare qualcosa di semplice come un server NFS. Kubernetes può funzionare con loro, puoi montare una directory su un server NFS: la tua applicazione è proprio come una directory locale. Allo stesso tempo, naturalmente, devi capire che, ancora una volta, devi fare qualcosa con il tuo NFS, devi capire che a volte potrebbe diventare inaccessibile e considerare la questione di cosa farai in questo caso. Forse dovrebbe essere eseguito il backup da qualche parte su una macchina separata.

Il punto successivo di cui ho parlato è cosa fare se la tua applicazione genera alcuni file durante il funzionamento. Ad esempio, all'avvio, genera dei file statici, che si basano su alcune informazioni che l'applicazione riceve solo al momento del lancio. Che momento. Se non ci sono molti di questi dati, non devi preoccuparti affatto, installa questa applicazione da solo e lavora. L'unica domanda qui è cosa, guarda. Molto spesso, tutti i tipi di sistemi legacy, come WordPress e così via, specialmente con plugin intelligenti modificati, sviluppatori PHP intelligenti, spesso sanno come fare in modo da generare qualche tipo di file per se stessi. Di conseguenza, uno genera un file, il secondo genera un secondo file. Sono diversi. Il bilanciamento avviene nel cluster Kubernetes dei clienti semplicemente per caso. Di conseguenza, si scopre che, ad esempio, non sanno come lavorare insieme. Uno fornisce un'informazione, l'altro fornisce all'utente un'altra informazione. Questo è qualcosa che dovresti evitare. Cioè, in Kubernetes, tutto ciò che avvii può funzionare in più istanze. Perché Kubernetes è una cosa in movimento. Di conseguenza, può spostare qualsiasi cosa, quando vuole, senza chiedere nulla a nessuno. Pertanto, devi contare su questo. Tutto ciò che viene avviato in un'istanza prima o poi fallirà. Più prenotazioni hai, meglio è. Ma ancora una volta, dico, se hai alcuni di questi file, puoi metterli proprio sotto di te, pesano una piccola quantità. Se ce ne sono un po’ di più, probabilmente non dovresti spingerli all’interno del contenitore.

Vorrei avvisare che c'è una cosa meravigliosa in Kubernetes, puoi usare il volume. In particolare è presente un volume di tipo vuoto dir. Cioè, è solo che Kubernetes creerà automaticamente una directory nelle sue directory di servizio sul server da cui hai iniziato. E te lo darà affinché tu possa usarlo. C'è solo un punto importante. Cioè, i tuoi dati non verranno archiviati all'interno del contenitore, ma piuttosto sull'host su cui stai utilizzando. Inoltre, Kubernetes può controllare tali directory vuote nella normale configurazione ed è in grado di controllare la loro dimensione massima e non consentirne il superamento. L'unico punto è che ciò che hai scritto nella directory vuota non viene perso durante il riavvio del pod. Cioè, se il tuo pod cade per errore e si rialza, le informazioni nella directory vuota non andranno da nessuna parte. Può usarlo di nuovo in un nuovo inizio - e questo è positivo. Se il tuo pod parte da qualche parte, naturalmente se ne andrà senza dati. Cioè, non appena il pod dal nodo in cui è stato lanciato con la directory vuota scompare, la directory vuota viene eliminata.

Cos'altro c'è di buono nella directory vuota? Ad esempio, può essere utilizzato come cache. Immaginiamo che la nostra applicazione generi qualcosa al volo, lo fornisca agli utenti e lo faccia per molto tempo. Pertanto, l'applicazione, ad esempio, lo genera e lo fornisce agli utenti, e allo stesso tempo lo memorizza da qualche parte, in modo che la prossima volta che l'utente verrà per la stessa cosa, sarà più veloce darlo immediatamente generato. È possibile chiedere a Kubernetes di creare una directory vuota in memoria. Pertanto, le tue cache possono generalmente funzionare alla velocità della luce, in termini di velocità di accesso al disco. Cioè, hai una directory vuota in memoria, nel sistema operativo è archiviata in memoria, ma per te, per l'utente all'interno del pod, sembra solo una directory locale. Non hai bisogno dell'app per insegnare specificamente la magia. Prendi e inserisci direttamente il tuo file in una directory, ma, in effetti, nella memoria del sistema operativo. Questa è anche una funzionalità molto conveniente in termini di Kubernetes.

Che problemi ha Minio? Il problema principale con Minio è che affinché funzioni, deve essere in esecuzione da qualche parte e deve esserci una sorta di file system, cioè spazio di archiviazione. E qui incontriamo gli stessi problemi di Ceph. Cioè, Minio deve archiviare i suoi file da qualche parte. È semplicemente un'interfaccia HTTP per i tuoi file. Inoltre, la funzionalità è chiaramente inferiore a quella dell'S3 di Amazon. In precedenza, non era in grado di autorizzare correttamente l'utente. Adesso, per quanto ne so, può già creare bucket con autorizzazioni diverse, ma ancora una volta mi sembra che il problema principale sia, per così dire, il sistema di storage sottostante come minimo.

In che modo la directory vuota in memoria influisce sui limiti? Non influisce in alcun modo sui limiti. Si trova nella memoria dell'host e non nella memoria del tuo contenitore. Cioè, il tuo contenitore non vede la directory vuota in memoria come parte della sua memoria occupata. L'host lo vede. Di conseguenza, sì, dal punto di vista di Kubernetes, quando inizi a usarlo, sarebbe bene capire che stai dedicando parte della tua memoria alla dir vuota. E di conseguenza, comprendi che la memoria può esaurirsi non solo a causa delle applicazioni, ma anche perché qualcuno scrive in queste directory vuote.

Natività del cloud

E l'argomento secondario finale è cosa è Cloudnative. Perché è necessario? Natività del cloud e così via.

Cioè, quelle applicazioni che sono capaci e scritte per funzionare in una moderna infrastruttura cloud. Ma in realtà Cloudnative ha un altro aspetto simile. Che questa non sia solo un'applicazione che tiene conto di tutti i requisiti di una moderna infrastruttura cloud, ma sa anche come lavorare con questa moderna infrastruttura cloud, approfitta dei vantaggi e degli svantaggi del fatto che funziona in questi cloud. Non esagerare e lavorare nel cloud, ma sfrutta i vantaggi di lavorare nel cloud.

Requisiti per lo sviluppo di un'applicazione in Kubernetes

Prendiamo come esempio Kubernetes. La tua applicazione è in esecuzione in Kubernetes. La tua applicazione può sempre, o meglio gli amministratori della tua applicazione, possono sempre creare un account di servizio. Cioè, un account per l'autorizzazione nello stesso Kubernetes nel suo server. Aggiungi alcuni diritti di cui abbiamo bisogno lì. E puoi accedere a Kubernetes dall'interno della tua applicazione. Cosa puoi fare in questo modo? Ad esempio, dall'applicazione, ricevi dati su dove si trovano le tue altre applicazioni, altre istanze simili e insieme in qualche modo si raggruppano sopra Kubernetes, se ce n'è bisogno.

Ancora una volta, di recente abbiamo letteralmente avuto un caso. Abbiamo un controller che monitora la coda. E quando in questa coda compaiono nuove attività, queste vanno a Kubernetes e all'interno di Kubernetes crea un nuovo pod. Assegna a questo pod qualche nuovo compito e, nell'ambito di questo pod, il pod esegue l'attività, invia una risposta al controller stesso e il controller quindi fa qualcosa con queste informazioni. Ad esempio, aggiunge un database. Questo è, ancora una volta, un vantaggio che la nostra applicazione viene eseguita in Kubernetes. Possiamo utilizzare la funzionalità Kubernetes integrata stessa per espandere e rendere più conveniente in qualche modo la funzionalità della nostra applicazione. Cioè, non nascondere alcuna magia su come avviare un'applicazione, come avviare un lavoratore. In Kubernetes, invii semplicemente una richiesta nell'app se l'applicazione è scritta in Python.

Lo stesso vale se andiamo oltre Kubernetes. Abbiamo i nostri Kubernetes in esecuzione da qualche parte: va bene se è in una sorta di cloud. Ancora una volta, possiamo utilizzare, e credo anche dovremmo utilizzare, le funzionalità del cloud stesso in cui operiamo. Dalle cose elementari che il cloud ci fornisce. Bilanciamento, cioè possiamo creare bilanciatori cloud e utilizzarli. Questo è un vantaggio diretto di ciò che possiamo usare. Perché il bilanciamento del cloud, in primo luogo, ci rimuove semplicemente stupidamente la responsabilità di come funziona, di come è configurato. Inoltre è molto conveniente, perché i normali Kubernetes possono integrarsi con i cloud.

Lo stesso vale per il ridimensionamento. Kubernetes normali possono integrarsi con i fornitori di servizi cloud. Sa come capire che se il cluster esaurisce i nodi, ovvero lo spazio dei nodi è esaurito, è necessario aggiungere: Kubernetes stesso aggiungerà nuovi nodi al tuo cluster e inizierà ad avviare pod su di essi. Cioè, quando arriva il tuo carico, il numero di focolari inizia ad aumentare. Quando i nodi del cluster esauriscono questi pod, Kubernetes avvia nuovi nodi e, di conseguenza, il numero di pod può ancora aumentare. Ed è molto conveniente. Questa è un'opportunità diretta per ridimensionare il cluster al volo. Non velocissimo, nel senso che non è un secondo, è più un minuto per aggiungere nuovi nodi.

Ma dalla mia esperienza, ancora una volta, è la cosa più bella che abbia mai visto. Quando il cluster Cloudnative è stato ridimensionato in base all'ora del giorno. Era un servizio di backend utilizzato dalle persone nel back office. Cioè, arrivano al lavoro alle 9 del mattino, iniziano ad accedere al sistema e, di conseguenza, il cluster Cloudnative, dove tutto è in esecuzione, inizia a gonfiarsi, lanciando nuovi pod in modo che tutti coloro che vengono al lavoro possano lavorare con l'applicazione. Quando escono dal lavoro alle 8:6 o alle 30:XNUMX, i cluster Kubernetes si accorgono che nessuno utilizza più l'applicazione e iniziano a ridursi. È garantito un risparmio fino al XNUMX%. All’epoca funzionava in Amazon; a quel tempo non c’era nessuno in Russia che potesse farlo così bene.

Te lo dico chiaramente, il risparmio è del 30% semplicemente perché utilizziamo Kubernetes e sfruttiamo le funzionalità del cloud. Ora questo può essere fatto in Russia. Non farò pubblicità a nessuno, ovviamente, ma diciamo solo che ci sono fornitori che possono farlo, fornendolo immediatamente con un pulsante.

C’è un ultimo punto su cui vorrei attirare la vostra attenzione. Affinché la tua applicazione, la tua infrastruttura sia Cloudnative, è opportuno iniziare finalmente ad adattare l’approccio chiamato Infrastructure as a Code. Ciò significa cioè che la tua applicazione, o meglio la tua infrastruttura, è necessaria esattamente allo stesso modo codice Descrivi la tua applicazione, la tua logica aziendale sotto forma di codice. E lavorarci come codice, ovvero testarlo, distribuirlo, archiviarlo in git, applicarvi CICD.

Ed è proprio questo che ti permette, in primis, di avere sempre il controllo sulla tua infrastruttura, di capire sempre in che stato si trova. In secondo luogo, evitare operazioni manuali che causano errori. In terzo luogo, evita semplicemente quello che viene chiamato turnover, quando devi svolgere costantemente le stesse attività manuali. In quarto luogo, consente di recuperare molto più rapidamente in caso di guasto. In Russia, ogni volta che ne parlo, c’è sempre un numero enorme di persone che dicono: “Sì, è chiaro, ma avete degli approcci, insomma, non c’è bisogno di aggiustare nulla”. Ma è vero. Se qualcosa non funziona nella tua infrastruttura, dal punto di vista dell'approccio Cloudnative e dal punto di vista dell'Infrastructure as a Code, invece di ripararlo, andare al server, capire cosa è rotto e risolverlo, è più facile per eliminare il server e crearlo di nuovo. E farò restaurare tutto questo.

Tutti questi problemi sono discussi in modo più dettagliato in Videocorsi Kubernetes: Junior, Basic, Mega. Seguendo il collegamento puoi familiarizzare con il programma e le condizioni. La cosa comoda è che puoi padroneggiare Kubernetes studiando da casa o lavorando per 1-2 ore al giorno.

Fonte: habr.com

Aggiungi un commento