La nostra esperienza nella sviluppo di un driver CSI in Kubernetes per Yandex.Cloud

La nostra esperienza nella sviluppo di un driver CSI in Kubernetes per Yandex.Cloud

Siamo lieti di annunciare che l'azienda «Flant» sta contribuendo agli strumenti Open Source per Kubernetes, rilasciando la versione alpha del driver CSI (Container Storage Interface) per Yandex.Cloud.

Ma prima di parlare dei dettagli di implementazione, rispondiamo alla domanda: perché è necessario, quando Yandex ha già il servizio Managed Service for Kubernetes.

Introduzione

Perché?

All'interno della nostra azienda, fin dall'inizio dell'uso di Kubernetes in produzione (cioè già da diversi anni), si è sviluppato uno strumento proprietario (deckhouse), che, per inciso, intendiamo rendere disponibile come progetto Open Source a breve. Con questo strumento configurando e impostiamo uniformemente tutti i nostri cluster, e attualmente ne abbiamo più di 100, su varie configurazioni hardware e in tutti i servizi cloud disponibili.

I cluster che utilizzano deckhouse includono tutti i componenti necessari per il funzionamento: bilanciatori, monitoraggio con grafici, metriche e avvisi intuitivi, autenticazione degli utenti tramite fornitori esterni per l'accesso a tutti i dashboard e così via. Non ha senso utilizzare un cluster così "potenziato" in una soluzione gestita, poiché spesso ciò è impossibile o comporta la disattivazione della metà dei componenti.

NB: Questa è la nostra esperienza, che è piuttosto specifica. Non affermiamo in alcun modo che tutti dovrebbero occuparsi della distribuzione dei cluster Kubernetes anziché utilizzare soluzioni pronte. A proposito, non abbiamo esperienze reali di utilizzo di Kubernetes di Yandex e non daremo alcuna valutazione di questo servizio in questo articolo.

Cos'è e per chi?

Quindi, abbiamo già parlato del moderno approccio ai repository in Kubernetes: come funziona il CSI e come la comunità è arrivata a questo approccio.

Attualmente, molti grandi fornitori di servizi cloud hanno sviluppato driver per utilizzare i loro "dischi cloud" come Persistent Volume in Kubernetes. Tuttavia, se il fornitore non dispone di un driver del genere, ma tutte le funzionalità necessarie sono fornite tramite API, nulla impedisce di implementare un driver autonomamente. È esattamente quello che abbiamo fatto con Yandex.Cloud.

Abbiamo preso come base per lo sviluppo il driver CSI per il cloud di DigitalOcean e alcune idee da driver per GCP, poiché l'interazione con le API di questi cloud (Google e Yandex) presenta alcune somiglianze. In particolare, le API sia di GCPche di Yandex restituiscono un oggetto Operazione per tenere traccia dello stato delle operazioni di lunga durata (ad esempio, la creazione di un nuovo disco). Per interagire con l'API di Yandex.Cloud, si utilizza Yandex.Cloud Go SDK.

Il risultato del lavoro svolto è stato pubblicato su GitHub e può essere utile a chi, per qualche motivo, utilizza un'installazione personalizzata di Kubernetes su macchine virtuali di Yandex.Cloud (ma non un cluster gestito pronto all'uso) e desidera utilizzare (richiedere) dischi tramite CSI.

Implementazione

Funzionalità principali

Attualmente, il driver supporta le seguenti funzionalità:

  • Ordine dei dischi in tutte le zone del cluster secondo la topologia dei nodi esistenti nel cluster;
  • Rimozione dei dischi ordinati in precedenza;
  • Ridimensionamento offline per i dischi (Yandex.Cloud non supporta aumento dei dischi che sono montati sulla macchina virtuale). Per ulteriori informazioni su come è stato necessario modificare il driver per eseguire il ridimensionamento in modo il meno possibile doloroso, vedere di seguito.

In futuro, è previsto implementare il supporto per la creazione e la rimozione di snapshot dei dischi.

La principale difficoltà e la sua soluzione

L'assenza nell'API di Yandex.Cloud della possibilità di aumentare i dischi in tempo reale è una limitazione che complica l'operazione di ridimensionamento per PV (Persistent Volume): in questo caso, è necessario che il pod dell'applicazione che utilizza il disco sia fermo, il che può causare un'interruzione dell'applicazione.

Secondo specifiche CSI, se il controller CSI comunica che può eseguire il ridimensionamento dei dischi solo "offline" (VolumeExpansion.OFFLINE), allora il processo di aumento del disco deve avvenire nel seguente modo:

Se il plugin ha solo VolumeExpansion.OFFLINE capacità di espansione e il volume è attualmente pubblicato o disponibile su un nodo, allora ControllerExpandVolume DEVE essere chiamato SOLO dopo che:

  • Il plugin ha controller PUBLISH_UNPUBLISH_VOLUME capacità e ControllerUnpublishVolume è stato invocato con successo.

ALTRIMENTI

  • Il plugin NON ha capacità di controller, il plugin ha nodo PUBLISH_UNPUBLISH_VOLUME STAGE_UNSTAGE_VOLUME STAGE_UNSTAGE_VOLUME capacità, e NodeUnstageVolume è stato completato con successo.

ALTRIMENTI

  • Il plugin NON ha capacità di controller, il plugin ha nodo PUBLISH_UNPUBLISH_VOLUME capacità, né nodo STAGE_UNSTAGE_VOLUME capacità, e NodeUnpublishVolume è stato completato con successo.

Questo significa che è necessario scollegare il disco dalla macchina virtuale prima di ingrandirlo.

Tuttavia, sfortunatamente, implementazione le specifiche CSI tramite i sidecar non soddisfano questi requisiti:

  • Nel contenitore sidecar csi-attacher, che deve garantire la necessaria pausa tra i montaggi, questa funzionalità non è semplicemente realizzata durante il ridimensionamento offline. La discussione su questo è stata avviata qui.
  • Che cos'è esattamente un contenitore sidecar in questo contesto? Il plugin CSI non interagisce con l'API di Kubernetes, ma risponde solo alle chiamate gRPC che gli inviano i contenitori sidecar. Questi ultimi vengono sviluppati dalla comunità di Kubernetes.

Nel nostro caso (plugin CSI) l'operazione di ingrandimento del disco appare come segue:

  1. Riceviamo una chiamata gRPC ControllerExpandVolume;
  2. Proviamo ad aumentare il disco nell'API, ma riceviamo un errore che indica che l'operazione non può essere eseguita poiché il disco è montato;
  3. Salviamo l'identificativo del disco in una mappa contenente i dischi per i quali è necessaria l'operazione di ingrandimento. Per brevità, ci riferiremo a questa mappa come volumeResizeRequired;
  4. Rimuoviamo manualmente il pod che utilizza il disco. Kubernetes lo riavvierà. Per evitare che il disco venga montato (ControllerPublishVolume) prima del completamento dell'operazione di aumento durante il tentativo di montaggio, verifichiamo che questo disco sia ancora in volumeResizeRequired e restituiamo un errore;
  5. il driver CSI tenta di rieseguire l'operazione di ridimensionamento. Se l'operazione ha avuto successo, rimuoviamo il disco da volumeResizeRequired;
  6. Poiché l'identificatore del disco è assente in volumeResizeRequired, ControllerPublishVolume l'operazione riesce, il disco viene montato e il pod viene avviato.

Tutto sembra abbastanza semplice, ma come sempre ci sono insidie. L'aumento dei dischi è gestito da external-resizer, che in caso di errore durante l'esecuzione dell'operazione utilizza una coda con un aumento esponenziale del tempo di timeout fino a 1000 secondi:

func DefaultControllerRateLimiter() RateLimiter {
  return NewMaxOfRateLimiter(
  NewItemExponentialFailureRateLimiter(5*time.Millisecond, 1000*time.Second),
  \/\/ 10 qps, 100 bucket size. Questo è solo per la velocità di ripetizione e il suo unico fattore complessivo (non per ogni elemento)
  &BucketRateLimiter{Limiter: rate.NewLimiter(rate.Limit(10), 100)},
  )
}

Questo può causare periodicamente il prolungamento dell'operazione di aumento del disco per 15+ minuti e, di conseguenza, la non disponibilità del pod corrispondente.

L'unica opzione che ci ha permesso di ridurre facilmente e senza problemi il potenziale tempo di inattività è stata l'implementazione della nostra versione di external-resizer con un limite massimo di timeout. di 5 secondi:

workqueue.NewItemExponentialFailureRateLimiter(5*time.Millisecond, 5*time.Second)

Non abbiamo ritenuto necessario avviare una discussione urgente e patchare external-resizer, poiché il ridimensionamento offline dei dischi è un retaggio che presto sparirà per tutti i fornitori di cloud.

Come iniziare a utilizzare?

Il driver è supportato in Kubernetes versione 1.15 e superiore. I seguenti requisiti devono essere soddisfatti per il funzionamento del driver:

  • Flag --allow-privileged impostato su true per l'API server e kubelet;
  • Abilitati --feature-gates=VolumeSnapshotDataSource=true,KubeletPluginsWatcher=true,CSINodeInfo=true,CSIDriverRegistry=true per l'API server e kubelet;
  • La propagazione del montaggio (mount propagation) deve essere abilitata nel cluster. Quando si utilizza Docker, il demone deve essere configurato in modo da consentire oggetti di montaggio condivisi (shared mounts).

Tutti i passaggi necessari per l'installazione stessa sono descritti nel README. L'installazione comporta la creazione di oggetti in Kubernetes da manifesti.

Per far funzionare il driver, avrai bisogno di quanto segue:

  • Specificare nell'manifesto l'ID della cartella (folder-id) di Yandex.Cloud (vedi la documentazione);
  • Per interagire con l'API di Yandex.Cloud nel driver CSI, viene utilizzato un account di servizio. Nel manifesto Secret è necessario fornire le chiavi autorizzate dell'account di servizio. Nella documentazione è descritto, come creare un account di servizio e ottenere le chiavi.

In generale — prova, e saremo felici di ricevere feedback e nuovi issues, se incontri dei problemi!

Supporto ulteriore

In conclusione, vorremmo sottolineare che questo driver CSI è stato realizzato non per il puro piacere di scrivere applicazioni in Go, ma per un'esigenza urgente all'interno dell'azienda. Non ci sembra sensato mantenere la nostra implementazione, quindi, se Yandex manifesterà interesse e deciderà di continuare a supportare il driver, saremo felici di trasferire il repository a loro.

Inoltre, è probabile che Yandex abbia una propria implementazione del driver CSI nel cluster Kubernetes gestito, che potrebbe essere rilasciata in Open Source. Questa opzione per noi è vista positivamente: la comunità potrà usare un driver collaudato fornito dal fornitore di servizi, piuttosto che da una terza parte.

P.S.

Leggete anche nel nostro blog:

Fonte: habr.com

Acquista hosting affidabile per siti web con protezione DDoS, VPS VDS server 🔥 Acquista hosting affidabile per siti web con protezione DDoS, VPS VDS server | ProHoster