Ciao, Habr!
Presentiamo il team della piattaforma Exness. I nostri colleghi hanno già scritto un articolo riguardo . Oggi vogliamo condividere l'esperienza di migrazione dei servizi su Kubernetes.

Iniziamo fornendo alcune cifre per comprendere meglio di cosa si parlerà:
- Il nostro dipartimento di sviluppo conta oltre 100 persone, tra cui più di 10 team con processi Auto-sufficienti di QA, DevOps e Scrum. Il nostro stack tecnologico include Python, PHP, C++, Java e Golang.
- Le dimensioni dell'ambiente di test e di produzione sono circa 2000 container ciascuno, gestiti tramite Rancher v1.6 sulla propria virtualizzazione e sotto VMware.
Motivazione
Come si dice, nulla è eterno sotto la luna, e Rancher ha annunciato ormai da tempo la cessazione del supporto per la versione 1.6. Sì, in più di tre anni abbiamo imparato a gestirlo e risolvere i problemi che si presentavano, ma sempre più spesso ci siamo imbattuti in questioni che non sarebbero mai state risolte. Inoltre, Rancher 1.6 ha un sistema di autorizzazione rigido, dove o hai quasi tutto o nulla.
La virtualizzazione proprietaria, sebbene fornisse un maggiore controllo sulla sicurezza e sullo storage dei dati, comportava costi operativi difficili da sostenere con la crescita continua dell'azienda, dei progetti e delle loro esigenze.
Volevamo seguire gli standard IaC e ottenere potenza rapidamente, in qualsiasi localizzazione geografica e senza lock-in vendor, così come poter rinunciare a tale potenza con altrettanta facilità.
Primi passi
In primis, volevamo basarci su tecnologie e soluzioni moderne che consentissero ai team di avere cicli di sviluppo più rapidi e minimizzare i costi operativi per interagire con la piattaforma che forniva potenza.
Naturalmente, la prima cosa che ci è venuta in mente è stata Kubernetes, ma non ci siamo affrettati e abbiamo condotto una piccola ricerca per verificare la correttezza della nostra scelta. Abbiamo valutato solo soluzioni opensource, e in una competizione sfrenata ha vinto senza riserve Kubernetes.
Successivamente, ci siamo posti il problema di quale strumento utilizzare per creare cluster. Abbiamo confrontato le soluzioni più popolari: kops, kubespray, kubeadm.
Per iniziare, kubeadm ci è sembrato un percorso troppo complicato, quasi un'invenzione di un 'nuovo mezzo', mentre kops mancava di flessibilità.
Il vincitore è stato:

Abbiamo iniziato a fare esperimenti sulla nostra virtualizzazione e su AWS, cercando di ricreare una somiglianza col nostro precedente modello di gestione delle risorse, dove tutti utilizzavano lo stesso 'cluster'. Così abbiamo creato il nostro primo cluster composto da 10 piccole di macchine virtuali, una delle quali si trova su AWS. Abbiamo iniziato a provare a migrare i team, sembrava che tutto stesse andando 'bene', e la storia potrebbe finire qui, ma...
Primi Problemi
Ansible — su cui si basa kubespray — non è lo strumento più adatto per seguire IaC: durante il provisioning o il decommissioning delle nodi, succedeva sempre qualcosa di imprevisto, richiedendo un'intervento manuale, e l'esecuzione del playbook si comportava in modo diverso a seconda del sistema operativo. Con l'aumentare del numero di team e nodi nel cluster, abbiamo notato che il playbook impiegava sempre più tempo per completarsi, con un nostro record di 3,5 ore. E il vostro? 🙂
E apparentemente kubespray è solo Ansible, e all'inizio sembra tutto chiaro, ma:

All'inizio, il compito era avviare potenza solo su AWS e sulla virtualizzazione, ma poi, come spesso accade, le esigenze sono cambiate.


In questo contesto, è diventato chiaro che il nostro vecchio modello di unificazione delle risorse in un unico sistema di orchestrazione non era adeguato — specialmente quando i cluster erano distanti e gestiti da diversi provider.
Ma non è finita qui. Quando tutti i team operano all'interno dello stesso cluster, vari servizi con NodeSelector mal configurati possono finire su un 'host' sbagliato di un'altra squadra, consumando risorse, e nel caso di un taint, iniziavano a emergere continue segnalazioni che alcuni servizi non funzionavano correttamente a causa di errori umani. Inoltre, un'altra problematica era il calcolo dei costi, specialmente considerando le difficoltà nella distribuzione dei servizi tra i nodi.
Un'altra questione riguardava l'assegnazione dei permessi ai membri del team: ogni team voleva essere 'alla guida' del cluster e gestirlo completamente, il che poteva portare a un completo collasso, poiché i team sono generalmente indipendenti tra loro.
Cosa fare?
Considerando quanto detto e le richieste dei team di essere più autonomi, abbiamo giunto a una conclusione semplice: un team — un cluster.
Così abbiamo creato il secondo:

E poi un terzo cluster:

Qui abbiamo iniziato a riflettere: supponiamo che tra un anno i nostri team abbiano più di un cluster? In diverse zone geografiche, per esempio, o gestiti da diversi provider? E qualcuno di loro vorrà essere in grado di creare rapidamente un cluster temporaneo per dei test.

Sarebbe un vero e proprio Kubernetes! Si tratta di un MultiKubernetes, dunque.
Nel frattempo, tutti noi dovremo in qualche modo supportare tutti questi cluster, gestire facilmente l'accesso ad essi, nonché creare nuovi cluster e dismettere quelli vecchi senza interazioni manuali.
Da quando abbiamo iniziato il nostro percorso nel mondo di Kubernetes è passato un po' di tempo, e abbiamo deciso di rivedere le soluzioni disponibili. Si è scoperto che sul mercato c'era già qualcosa: Rancher 2.2.

Nella prima fase delle nostre ricerche, Rancher Labs aveva già rilasciato la prima versione 2, ma anche se era possibile avviarla rapidamente, facendo funzionare il container senza dipendenze esterne con un paio di parametri o utilizzando l'HELM Chart ufficiale, ci è sembrata poco matura, e non sapevamo se poter contare su questa soluzione, se sarà sviluppata ulteriormente o rapidamente abbandonata. Anche la stessa logica del cluster = clic nel UI non ci sembrava adatta, e non volevamo legarci a RKE, poiché è uno strumento abbastanza specializzato.
La versione Rancher 2.2 aveva già un aspetto molto più funzionale e, rispetto alla versione precedente, offriva molte interessanti funzionalità di base, come l'integrazione con molti provider esterni, un unico punto di distribuzione dei permessi e dei file kubeconfig, lancio dell'immagine kubectl con le proprie autorizzazioni nell'interfaccia utente, spazi dei nomi nidificati, ovvero progetti.
Inoltre, attorno a Rancher 2 si era già formata una comunità, ed era stato creato un provider HashiCorp Terraform per la sua gestione, che ci ha aiutato a mettere tutto insieme.
Cosa abbiamo ottenuto
Alla fine abbiamo ottenuto un piccolo cluster, in cui è in esecuzione Rancher, accessibile a tutti gli altri cluster, così come molti cluster ad esso associati, a cui si può accedere altrettanto facilmente quanto aggiungere un utente nel catalogo ldap, indipendentemente da dove si trovi e quali risorse utilizzi il provider.
Utilizzando gitlab-ci e Terraform, è stato creato un sistema che consente di creare un cluster di qualsiasi configurazione nei provider cloud o nella nostra infrastruttura, e collegarli a Rancher. Tutto questo è stato realizzato in stile IaC, dove ogni cluster è descritto da un repository, e il suo stato è versionato. Inoltre, la maggior parte dei moduli viene collegata da repository esterni, quindi resta solo da passare le variabili o descrivere la propria configurazione personalizzata per gli istanti, il che aiuta a ridurre la percentuale di ripetizione del codice.

Certo, il nostro viaggio non è affatto finito e ci sono ancora molte sfide interessanti, come un punto unico per lavorare con i log e le metriche di qualsiasi cluster, service mesh, gitops per la gestione dei carichi nel multicluster e molto altro. Speriamo che la nostra esperienza vi risulti interessante!
L'articolo è stato scritto da A. Antipov, A. Ganush, Platform Engineers.
Fonte: habr.com
