Negli anni di esistenza di Pinterest, 300 milioni di utenti hanno creato oltre 200 miliardi di pin su più di 4 miliardi di bacheche. Per gestire questo esercito di utenti e l'ampia base di contenuti, il portale ha sviluppato migliaia di servizi, partendo da microservizi che possono essere gestiti da alcune CPU, fino a giganteschi monoliti che girano su un intero parco di macchine virtuali. È arrivato il momento in cui l'azienda ha rivolto lo sguardo a k8s. Cosa ha attratto Pinterest verso “il cubo”? Scoprilo nel nostro traduzione di un recente articolo dal .

Quindi, centinaia di milioni di utenti e centinaia di miliardi di pin. Per gestire questo esercito di utenti e l'ampia base di contenuti, abbiamo sviluppato migliaia di servizi, partendo da microservizi che possono essere gestiti da alcune CPU, fino a giganteschi monoliti che girano su un intero parco di macchine virtuali. Inoltre, abbiamo vari framework che possono richiedere anch'essi risorse di CPU, memoria o accesso alle operazioni di input/output.
Nel supportare questo zoo di strumenti, il team di sviluppo si confronta con una serie di sfide:
- Non c'è un modo unificato per avviare l'ambiente di lavoro. I servizi stateless, i servizi stateful e i progetti in fase di sviluppo si basano su stack tecnologici completamente diversi. Ciò ha portato alla creazione di un intero corso di formazione per gli ingegneri e complica notevolmente il lavoro del nostro team di infrastruttura.
- Gli sviluppatori, avendo a disposizione il proprio parco di macchine virtuali, creano un'enorme pressione sugli amministratori interni. Di conseguenza, operazioni semplici come l'aggiornamento del sistema operativo o dell'AMI si allungano per settimane e mesi. Questo porta a un aumento del carico in situazioni apparentemente ordinarie.
- Difficoltà nella creazione di strumenti di gestione dell'infrastruttura globali sopra le soluzioni già esistenti. La situazione è complicata dal fatto che non è facile trovare i proprietari delle macchine virtuali. In altre parole, non sappiamo se possiamo estrarre in modo sicuro queste capacità per lavorare su altre parti della nostra infrastruttura.
I sistemi di orchestrazione dei container sono un modo per unificare la gestione del carico di lavoro. Aprono la strada a un aumento della velocità di sviluppo e semplificano la gestione dell'infrastruttura, poiché tutte le risorse coinvolte nel progetto sono gestite da un unico sistema centralizzato.

Figura 1: Priorità dell'infrastruttura (affidabilità, produttività degli sviluppatori ed efficienza).
Il team della Cloud Management Platform di Pinterest ha iniziato a conoscere K8s nel 2017. Entro la prima metà del 2017, abbiamo documentato la maggior parte delle nostre capacità produttive, inclusi API e tutti i nostri server web. Successivamente, abbiamo effettuato una valutazione attenta dei vari sistemi di orchestrazione delle soluzioni container, costruzione di cluster e interazione con essi. Entro la fine del 2017, abbiamo deciso di utilizzare Kubernetes. Era sufficientemente flessibile e ampiamente supportato dalla comunità di sviluppatori.
Fino ad ora, abbiamo creato i nostri strumenti di bootstrapping del cluster basati su Kops e abbiamo migrato i componenti infrastrutturali esistenti su Kubernetes, come rete, sicurezza, metriche, logging, gestione dell'identità e traffico. Abbiamo anche implementato un sistema di modellazione del carico di lavoro per la nostra risorsa, la cui complessità è nascosta agli sviluppatori. Attualmente ci concentriamo sulla stabilità del cluster, sul suo scaling e sul collegamento di nuovi clienti.
Kubernetes: il percorso di Pinterest
Iniziare a lavorare con Kubernetes a livello di Pinterest, come piattaforma che sarà amata dai nostri ingegneri, ha comportato molte difficoltà.
Come grande azienda, abbiamo investito somme significative in strumenti infrastrutturali. Un esempio sono gli strumenti di sicurezza che gestiscono certificati e distribuiscono chiavi, i componenti di controllo del traffico, i sistemi di rilevamento dei servizi, i componenti di visibilità e invio di log e metriche. Tutto ciò non è stato assemblato per caso: abbiamo seguito un percorso normale di tentativi ed errori, e quindi volevamo integrare tutto questo nel nuovo sistema su Kubernetes invece di reinventare la vecchia ruota su una nuova piattaforma. Questo approccio ha semplificato la migrazione, poiché tutto il supporto alle applicazioni esiste già e non deve essere creato da zero.
D'altra parte, i modelli di previsione dei carichi in Kubernetes (come distribuzioni, job e set Daemon) non sono sufficienti per il nostro progetto. Questi problemi di usabilità rappresentano enormi ostacoli alla transizione verso Kubernetes. Ad esempio, abbiamo sentito sviluppatori di servizi lamentarsi per la mancanza o la scorretta configurazione dell'ingresso. Inoltre, abbiamo riscontrato un uso scorretto dei template, creando Centinaia di copie con specifiche e job identici, il che ha portato a problemi spaventosi di debug.
È stato anche molto difficile mantenere diverse versioni all'interno dello stesso cluster. Immaginate le complessità del supporto clienti quando si deve operare su molteplici versioni della medesima runtime, con tutti i loro problemi, bug e aggiornamenti.
Risorse e controller personalizzati di Pinterest
Per semplificare il processo di implementazione di Kubernetes per i nostri ingegneri, e per semplificare e accelerare l'infrastruttura, abbiamo sviluppato le nostre definizioni di risorse personalizzate (CRD).
Le CRD forniscono le seguenti funzionalità:
- Combinare diverse risorse native di Kubernetes affinché funzionino come un unico carico. Ad esempio, la risorsa PinterestService comprende distribuzione, servizio di ingresso e config map. Questo permette agli sviluppatori di non preoccuparsi della configurazione DNS.
- Implementare il supporto necessario per le applicazioni. L'utente deve concentrarsi solo sulla specifica del contenitore in base alla sua logica di business, mentre il controller CRD implementa tutti i necessari init-container, variabili d'ambiente e specifiche pod. Questo fornisce un livello di comfort sostanzialmente diverso per gli sviluppatori.
- I controller CRD gestiscono anche il ciclo di vita delle proprie risorse e migliorano la disponibilità del debug. Ciò include la riconciliazione delle specifiche desiderate e reali, l'aggiornamento dello stato CRD e il mantenimento di registri di eventi e altro ancora. Senza CRD, gli sviluppatori sarebbero costretti a gestire un numero elevato di risorse, il che aumenterebbe solo la probabilità di errore.
Ecco un esempio di PinterestService e della risorsa interna gestita dal nostro controller:

Come si può vedere sopra, per supportare un contenitore personalizzato, dobbiamo integrare al suo interno un container di inizializzazione e diverse estensioni per garantire sicurezza, visibilità e gestione del traffico di rete. Inoltre, abbiamo creato dei template di config map e implementato supporto per template PVC per job batch, oltre a tracciare molte variabili d'ambiente per monitorare identificazione, consumo di risorse e raccolta di 'spazzatura'.
È difficile immaginare che gli sviluppatori vogliano scrivere questi file di configurazione manualmente senza il supporto delle CRD, per non parlare del successivo supporto e debug delle configurazioni.
Workflow di distribuzione delle applicazioni

Nell'immagine sopra è mostrato come distribuire una risorsa personalizzata Pinterest in un cluster Kubernetes:
- Gli sviluppatori interagiscono con il nostro cluster Kubernetes tramite CLI e interfaccia utente.
- Gli strumenti CLI / UI estraggono i file YAML di configurazione del workflow e altre proprietà di build (lo stesso ID di versione) da Artifactory, quindi li inviano al Job Submission Service. Questo passaggio garantisce che nel cluster vengano distribuite solo versioni funzionanti.
- JSS è un gateway per diverse piattaforme, inclusa Kubernetes. Qui avviene l'autenticazione dell'utente, l'assegnazione di quote e la verifica parziale della configurazione del nostro CRD.
- Dopo la verifica del CRD lato JSS, le informazioni vengono inviate all'API della piattaforma k8s.
- Il nostro controller CRD monitora gli eventi su tutte le risorse personalizzate. Trasforma CR in risorse native k8s, aggiunge i moduli necessari, imposta le variabili d'ambiente appropriate ed esegue altre operazioni ausiliarie, garantendo così un'adeguata supporto infrastrutturale per le applicazioni containerizzate.
- Successivamente, il controller CRD passa i dati all'API Kubernetes affinché possano essere elaborati dallo scheduler e messi in esecuzione.
Nota: questo workflow di distribuzione pre-release è stato creato per i primi utenti della nuova piattaforma k8s. Attualmente siamo nel processo di perfezionamento di questo processo per integrarlo completamente con il nostro nuovo CI/CD. Ciò significa che non possiamo rivelare tutto ciò che riguarda Kubernetes. Non vediamo l'ora di condividere la nostra esperienza e di discutere i progressi del team in questo ambito nel nostro prossimo post sul blog 'Building a CI/CD platform for Pinterest'.
Tipi di risorse speciali
In base alle specifiche esigenze di Pinterest, abbiamo sviluppato i seguenti CRD, adatti per diversi flussi di lavoro:
- PinterestService è un servizio stateless consolidato. Molti dei nostri sistemi principali si basano su un insieme di tali servizi.
- PinterestJobSet modella i job batch a ciclo completo. In Pinterest, c'è uno scenario comune in cui diversi job avviano gli stessi container in parallelo, indipendentemente da altri processi simili.
- PinterestCronJob è ampiamente utilizzato in combinazione con carichi di lavoro periodici leggeri. È un'interfaccia per il lavoro cron nativo con meccanismi di supporto per Pinterest, responsabili della sicurezza, del traffico, dei log e delle metriche.
- PinterestDaemon comprende i Daemon dell'infrastruttura. Questa famiglia continua a crescere man mano che aggiungiamo sempre più supporto per i nostri cluster.
- PinterestTrainingJob si estende ai processi Tensorflow e Pytorch, garantendo lo stesso livello di supporto in fase di esecuzione come tutti gli altri CRD. Poiché Pinterest utilizza attivamente Tensorflow e altri sistemi di machine learning, avevamo motivo di costruire attorno a loro un CRD separato.
Stiamo inoltre lavorando su PinterestStatefulSet, che sarà presto adattato per archiviare dati e altri sistemi stateful.
Supporto dell'ambiente di esecuzione
Quando un modulo applicativo viene avviato in Kubernetes, riceve automaticamente un certificato per identificarsi. Questo certificato viene utilizzato per accedere al deposito segreto o per comunicare con altri servizi tramite mTLS. Nel frattempo, il configuratore di avvio dei container e il Daemon caricheranno tutte le dipendenze necessarie prima dell'avvio dell'applicazione containerizzata. Una volta che tutto è pronto, il sidecar del traffico e il Daemon registreranno l'indirizzo IP del modulo nel nostro Zookeeper affinché i clienti possano scoprirlo. Tutto ciò funzionerà poiché il modulo di rete è stato configurato prima dell'avvio dell'applicazione.
I tratti sopra riportati sono esempi tipici di supporto per carichi di lavoro durante l'esecuzione. Per altri tipi di carichi di lavoro potrebbe essere necessario un supporto leggermente diverso, ma tutti sono rappresentati come pod sidecar, nodi o Daemon a livello di macchina virtuale. Ci assicuriamo che tutto venga distribuito all'interno dell'infrastruttura di gestione e coordinato tra le applicazioni, il che riduce significativamente il carico in termini di lavoro tecnico e supporto clienti.
Testing e QA
Abbiamo costruito una pipeline di test end-to-end sopra l'infrastruttura di test già esistente in Kubernetes. Questi test coprono tutti i nostri cluster. La nostra pipeline ha subito molte modifiche prima di diventare parte del cluster di produzione.
Oltre ai sistemi di test, abbiamo sistemi di monitoraggio e alerting che controllano costantemente lo stato dei componenti del sistema, l'utilizzo delle risorse e altre metriche importanti, avvisandoci solo se è necessario un intervento umano.
Alternative
Abbiamo considerato alcune alternative alle risorse personalizzate, come i controllori di accesso mutativi e i sistemi di templates. Tuttavia, tutte comportano serie difficoltà operative, quindi abbiamo scelto la strada del CRD.
Il controllore di accesso mutativo è stato utilizzato per introdurre sidecar, variabili d'ambiente e altro supporto in fase di esecuzione. Tuttavia, ha incontrato vari problemi, come il binding delle risorse e la gestione del loro ciclo di vita, mentre in CRD non si presentano tali problemi.
Nota: I sistemi di templates, come i diagrammi Helm, sono ampiamente utilizzati per avviare applicazioni con configurazioni simili. Tuttavia, le nostre applicazioni operative sono troppo diverse per essere gestite tramite templates. Inoltre, nel corso del deployment continuo, l'uso di templates produce troppo errori.
Lavori futuri
Attualmente affrontiamo un carico di lavoro misto in tutti i nostri cluster. Per sostenere processi di vari tipi e dimensioni, stiamo lavorando nelle seguenti direzioni:
- La combinazione di cluster distribuisce grandi applicazioni su diversi cluster per garantire scalabilità e stabilità.
- Garantire stabilità, scalabilità e visibilità del cluster per stabilire un collegamento tra l'applicazione e il suo SLA.
- Gestione delle risorse e delle quote, per evitare conflitti tra le applicazioni e monitorare le dimensioni del cluster dalla nostra parte.
- Nuova piattaforma CI/CD per supportare e distribuire applicazioni in Kubernetes.
Fonte: habr.com
