Mi chiamo Sergey, sono della compagnia ITSumma e voglio parlarvi del nostro approccio al disaster recovery in Kubernetes. Negli ultimi tempi, mi sono dedicato molto alla consulenza per l'implementazione di varie soluzioni DevOps per diversi team, e in particolare, lavoro a stretto contatto su progetti che utilizzano K8s. Durante la conferenza Uptime day 4, dedicata al disaster recovery in architetture complesse, ho tenuto una presentazione sul disaster recovery del "cubo", e qui vi propongo una libera rielaborazione. Vorrei avvisarvi in anticipo che non si tratta di una guida pratica, ma piuttosto di un riassunto delle mie considerazioni su questo tema.

In realtà, il monitoraggio e la riserva sono due strumenti fondamentali per aumentare la resilienza di qualsiasi progetto. Ma direte, in Kubernetes tutto si bilancia da solo, tutto si scala da solo, e se succede qualcosa, si risolleverà automaticamente... Quindi, a una prima analisi superficiale del tema, alla domanda su come viene gestita la riserva in K8s, internet mi ha risposto "ma perché?" Molti pensano che Kubernetes sia una di quelle magie che elimina tutti i problemi infrastrutturali e assicura che il progetto non si interrompa mai. Ma... il mondo non è ciò che sembra.
Come approcciavamo il processo di riserva in passato? Avevamo piattaforme identiche per l'hosting — che fossero macchine virtuali o fisiche, server, a cui applicavamo tre pratiche fondamentali:
- sincronizzazione del codice e della statica
- sincronizzazione delle configurazioni
- replica del database
E voilà: in qualsiasi momento possiamo passare alla piattaforma di riserva, tutti sono felici, ci alziamo e ci disperdiamo.

Cosa ci viene offerto per aumentare la disponibilità continua della nostra applicazione Kubernetes? La prima cosa di cui parla la documentazione non ufficiale è di mettere a disposizione molte macchine, creare più master — il loro numero deve soddisfare le condizioni per raggiungere il quorum all'interno del cluster, e su ciascun master deve essere attivato etcd, api, MC, scheduler… E, sembra tutto fantastico: se alcune nodi di lavoro o master escono di servizio, il nostro cluster si riequilibrerà e l'applicazione continuerà a funzionare. Sembra quasi magia! Ma spesso il nostro cluster si trova all'interno di un unico centro di elaborazione dati, il che può sollevare alcune domande. Cosa succede se arriva un escavatore e rovina un cavo, se cade un fulmine, se si verifica un diluvio universale? Tutto andrebbe in mille pezzi, il nostro cluster non esisterebbe più. Come affrontare la questione del backup considerando questo aspetto del problema?
Innanzitutto, è necessario avere un altro cluster in hot standby, ovvero un cluster su cui si può passare in qualsiasi momento. Da un punto di vista di Kubernetes, le infrastrutture devono essere completamente identiche. Ciò significa che se ci sono plugin non standard per lavorare con il file system, soluzioni personalizzate per l'ingress, devono essere assolutamente identiche sui vostri due (o tre, o dieci, a seconda di quanto denaro e sforzi degli amministratori siano disponibili) cluster. È fondamentale definire chiaramente due set di applicazioni (deployment, statefulset, daemonset, cronjob, ecc.): quali di esse possono funzionare costantemente in standby e quali è meglio non avviare fino al momento del passaggio.
Deve quindi il nostro cluster di riserva essere completamente identico al nostro cluster operativo? No. In passato, nel lavoro con progetti monolitici e infrastrutture fisiche, mantenavamo un ambiente praticamente identico, ma nel contesto di Kubernetes, ritengo che ciò non debba accadere. Vediamo perché.
Ad esempio, partiamo dalle entità fondamentali di Kubernetes: i deployments devono essere identici. Devono essere attive applicazioni che possono in qualsiasi momento gestire il traffico e permettere al nostro progetto di continuare a funzionare. Quando parliamo di file di configurazione, dobbiamo valutare se devono essere identici o meno. Quindi, se noi, persone intelligenti, non usiamo sostanze proibite e non manteniamo il database in K8s, le nostre configmaps devono avere le impostazioni di accesso per il database di produzione (il processo di backup è separato). Di conseguenza, per garantire l'accesso al database di backup, dobbiamo avere un file di configurazione separato (configmap). Analogamente, gestiamo anche i secret: le password per accedere al database, le chiavi API; in qualsiasi momento può essere attivo o il secret di produzione o quello di backup. In totale abbiamo già due entità di Kubernetes, le cui versioni di backup non devono essere identiche a quelle di produzione. La prossima entità su cui soffermarsi è il cronjob. I cronjob di backup non devono assolutamente essere identici al set di cronjob del cluster di produzione! Se attiviamo un cluster di backup e lo facciamo partire completamente con tutti i cronjob attivi, ad esempio, le persone riceveranno due email contemporaneamente invece di una. Oppure qualche sincronizzazione dei dati con fonti esterne avverrà due volte, il che ci farà iniziare a soffrire, piangere, urlare e arrabbiarci.

E come ci suggeriscono di organizzare un cluster di prenotazione le persone su Internet? La seconda risposta più popolare dopo «perché?» è l'utilizzo di Kubernetes Federation.
Che cos'è? È, per così dire, un grande meta-cluster. Se pensiamo all'architettura di Kubernetes, dove abbiamo un master e diversi nodi, in termini di federazione abbiamo anch'essa un master e diversi nodi, solo che ogni nodo è un cluster a sé stante. Quindi lavoriamo con le stesse entità, con gli stessi primiti, come in un singolo cluster Kubernetes, solo che gestiamo interi cluster anziché le nostre macchine fisiche. Nell'ambito della federazione, c'è una completa sincronizzazione delle risorse federate dai genitori ai figli. Ad esempio, se avviamo un deployment tramite federazione, questo si installerà su ogni nostro cluster secondario. Se prendiamo un qualsiasi configmap o secret e lo distribuiamo tramite federazione, si propagherà a tutti i nostri cluster secondari; nel contempo, la federazione consente di personalizzare le nostre risorse sui figli. Cioè, prendiamo un configmap, lo distribuiamo tramite federazione e poi, se abbiamo bisogno di apportare delle modifiche su specifici cluster, andiamo a modificarlo su quel cluster specifico, e questa modifica non verrà sincronizzata altrove.
Kubernetes Federation è uno strumento relativamente recente e non supporta ancora l'intero set di risorse fornito da K8s: al momento della pubblicazione di una delle prime versioni della documentazione si menzionava il supporto solo per i config maps, il deployment nel replica set e l' ingresso. I segreti non erano supportati e la gestione dei volumi non era prevista. È un insieme di funzionalità troppo limitato. Specialmente se ci piace divertirci — ad esempio, passando le nostre risorse personalizzate a Kubernetes tramite custom resource definition — non possiamo includerle nella federazione. Insomma, è come avere una soluzione che sembra funzionare, ma ci fa sparare periodicamente nei piedi. D'altra parte, la federazione consente di gestire in modo flessibile il nostro replica set. Ad esempio, se desideriamo avere 10 repliche della nostra applicazione, per default la federazione distribuisce questo numero proporzionalmente tra i cluster. E tutto ciò può anche essere configurato! Possiamo specificare di mantenere 6 repliche della nostra applicazione nel cluster di produzione, mentre nel cluster secondario, per risparmiare risorse o per altri motivi di intrattenimento, solo 4 repliche. È anche piuttosto comodo. Tuttavia, con la federazione dobbiamo adottare nuove soluzioni, implementare qualcosa al volo e costringerci a riflettere un po' di più...
È possibile semplificare il processo di prenotazione di Kubernetes? Quali strumenti abbiamo a disposizione?
Innanzitutto, abbiamo sempre un sistema di CI/CD, quindi non dobbiamo andare manualmente a scrivere sui server create/apply. Il sistema genera file YAML per i nostri contenitori.
In secondo luogo, ci sono diversi cluster, abbiamo uno o più registry (se siamo furbi) che abbiamo anche riservato. E c'è un'ottima utility kubectl, che può lavorare con più cluster contemporaneamente.

Dunque, a mio avviso, la soluzione più semplice e corretta per costruire un cluster di backup è un deployment parallelo primitivo. Abbiamo una pipeline nel sistema CI/CD; prima compiliamo i nostri container, testiamo e distribuiamo le applicazioni tramite kubectl su più cluster indipendenti. Possiamo effettuare deploy simultanei su diversi cluster. Di conseguenza, gestiamo anche la distribuzione delle configurazioni in questa fase. Possiamo definire in anticipo un insieme di configurazioni per il nostro cluster di produzione, un insieme di configurazioni per il cluster di backup e, a livello di sistema CI/CD, distribuire l'ambiente di produzione nel cluster di produzione e l'ambiente di backup nel cluster di backup. A differenza della federazione, non è necessario andare a ogni cluster secondario dopo aver definito la risorsa federativa e ridefinire qualcosa. Lo abbiamo fatto in anticipo. Che bravi che siamo.
Ma… c'è… io avevo scritto, c'è il «cuore di tutti i mali», ma in realtà ce ne sono due. Prima di tutto, il filesystem. C'è una sorta di PV, oppure usiamo uno storage esterno. Se conserviamo i file all'interno del cluster, dobbiamo seguire le vecchie pratiche rimaste dai tempi delle infrastrutture hardware: per esempio, sincronizzare con lsync. O con qualsiasi altro strumento che preferite. Distribuiamo il tutto su altre macchine e andiamo avanti.
In secondo luogo, e, in realtà, un punto di attrito ancora più importante è il database. Se siamo persone intelligenti e non teniamo il database in Kubernetes, il processo di backup dei dati seguirà la vecchia schematizzazione: replica master-slave, poi switch, raggiungiamo la replica e vivremo bene. Ma se manterremo il nostro DB all'interno del cluster, ci sono molte soluzioni pronte per organizzare la stessa replica master-slave, molte soluzioni per sollevare DB all'interno di Kubernetes.
Sulla riserva delle basi dati sono stati letti un miliardo di rapporti e scritti un miliardo di articoli, non c'è realmente nulla di nuovo. In generale, seguite il vostro sogno, vivete come volete, inventatevi anche qualche complicato espediente, ma pensate sempre a come gestirete il tutto in termini di riserva.
Ora parliamo di come avverrà in linea di massima il processo di switch su una piattaforma di backup in caso di incendio. Iniziamo con il deploy parallelo delle applicazioni stateless. Queste non influenzano la logica aziendale delle nostre applicazioni e del nostro progetto; possiamo mantenere due set di applicazioni in esecuzione e queste possono iniziare a ricevere traffico. È molto importante, durante il processo di switch sulla piattaforma di backup, controllare se è necessario ridefinire le configurazioni. Ad esempio, abbiamo un cluster Kubernetes in produzione, un cluster Kubernetes secondario, un database master esterno e un database master di backup. Ci sono quattro modalità in cui queste applicazioni in produzione possono iniziare a interagire tra loro. Possiamo cambiare il database, e così dovremmo reindirizzare il traffico sul cluster di produzione verso il nuovo database, oppure il cluster potrebbe andare in crash — e migriamo sul backup, ma continuiamo a lavorare con il database di produzione. Infine, c'è la terza opzione, in cui entrambe le componenti si guastano, e dobbiamo reindirizzare entrambe le applicazioni e ridefinire la nostra configurazione in modo che le nuove applicazioni funzionino con il nuovo database.
E, quindi, quali conclusioni possiamo trarre da tutto questo?

Prima conclusione: vivere con un backup è positivo. Ma è costoso. Idealmente, non dovremmo avere solo un backup. In teoria, dovremmo vivere con più riserve. Innanzitutto, il backup deve trovarsi in almeno un altro data center, e in secondo luogo, deve essere con un altro fornitore. Spesso è accaduto — e nella mia esperienza è successo. Purtroppo non posso nominare i progetti, proprio quando ci fu l'incendio nel data center... Io dicevo: passiamo al backup! E i server di riserva erano nella stessa rack...
Oppure immaginate che Amazon venga bloccato in Russia (e questo è successo). E tutto qui: che utilità ha il nostro backup in un altro amazon se non è accessibile? Quindi ripeto: manteniamo il backup, almeno in un altro data center e, se possibile, con un altro fornitore.
Second takeaway: if you have an application in Kubernetes that communicates with external sources (this can be a database or an external API), make sure to define it as a service with an external endpoint, so you don’t have to redeploy 15 of your applications that connect to the same database during a switch. Define the database as a separate service, access it as if it were inside your cluster: if the database goes down, you can change the IP in one place and continue to operate smoothly.
And finally: I love 'K8s', as well as experimenting with it. I also enjoy sharing the results of these experiments and my personal experiences. That’s why I recorded a series of webinars about K8s, welcome to for more details.
Fonte: habr.com
