Experiența noastră în dezvoltarea unui driver CSI în Kubernetes pentru Yandex.Cloud

Experiența noastră în dezvoltarea unui driver CSI în Kubernetes pentru Yandex.Cloud

Suntem încântați să anunțăm că Flant își extinde contribuția la instrumentele Open Source pentru Kubernetes prin lansarea versiunea alfa a driverului CSI (Interfață de stocare a containerelor) pentru Yandex.Cloud.

Dar înainte de a trece la detaliile de implementare, să răspundem la întrebarea de ce este nevoie de acest lucru atunci când Yandex are deja un serviciu Serviciu gestionat pentru Kubernetes.

Introducere

De ce asta?

În cadrul companiei noastre, de la începutul utilizării Kubernetes în producție (adică de câțiva ani încoace), am dezvoltat propriul nostru instrument (deckhouse), pe care, apropo, intenționăm să îl punem la dispoziție în curând ca proiect Open Source. . Cu ajutorul acestuia, ne configuram si configuram uniform toate clusterele, iar in prezent exista deja peste 100 dintre ele, pe o mare varietate de configuratii hardware si in toate serviciile cloud disponibile.

Clusterele care folosesc deckhouse au toate componentele necesare funcționării: echilibrare, monitorizare cu diagrame convenabile, metrici și alerte, autentificarea utilizatorilor prin furnizori externi pentru acces la toate tablourile de bord și așa mai departe. Nu are rost să instalați un astfel de cluster „amplificat” într-o soluție gestionată, deoarece acest lucru este adesea imposibil sau va duce la necesitatea dezactivarii a jumătate dintre componente.

NB: Aceasta este experiența noastră și este destul de specifică. Nu sugerăm în niciun caz că toată lumea ar trebui să implementeze clustere Kubernetes pe cont propriu, în loc să utilizeze soluții gata făcute. Apropo, nu avem experiență reală în operarea Kubernetes de la Yandex și nu vom oferi nicio evaluare a acestui serviciu în acest articol.

Ce este și pentru cine?

Deci, am vorbit deja despre abordarea modernă a stocării în Kubernetes: cum funcționează CSI? и cum a venit comunitatea la această abordare.

În prezent, mulți furnizori mari de servicii cloud au dezvoltat drivere pentru utilizarea discurilor lor cloud ca volum persistent în Kubernetes. Dacă furnizorul nu are un astfel de driver, dar toate funcțiile necesare sunt furnizate prin intermediul API-ului, atunci nimic nu vă împiedică să implementați singur driverul. Iată ce s-a întâmplat cu Yandex.Cloud.

Am luat ca bază de dezvoltare Driver CSI pentru cloud DigitalOcean și câteva idei de la drivere pentru GCP, deoarece interacțiunea cu API-ul acestor nori (Google și Yandex) are o serie de asemănări. În special, API și BPSC, și la Yandex returnează un obiect Operation pentru a urmări starea operațiunilor de lungă durată (de exemplu, crearea unui nou disc). Pentru a interacționa cu API-ul Yandex.Cloud, utilizați Yandex.Cloud Go SDK.

Rezultatul muncii depuse publicat pe GitHub și poate fi util pentru cei care, dintr-un motiv oarecare, folosesc propria lor instalare Kubernetes pe mașinile virtuale Yandex.Cloud (dar nu un cluster gestionat gata făcut) și ar dori să folosească (comanda) discuri prin CSI.

punerea în aplicare

Caracteristici cheie

În prezent, driverul acceptă următoarele funcții:

  • Comandarea discurilor în toate zonele clusterului în funcție de topologia nodurilor din cluster;
  • Scoaterea discurilor comandate anterior;
  • Redimensionare offline pentru discuri (Yandex.Cloud nu suporta creșterea discurilor care sunt montate pe mașina virtuală). Pentru informații despre modul în care a trebuit modificat șoferul pentru a face redimensionarea cât mai nedureroasă posibil, consultați mai jos.

În viitor, intenționăm să implementăm suport pentru crearea și ștergerea instantaneelor ​​de disc.

Principala dificultate și cum să o depășim

Lipsa capacității de a crește discurile în timp real în API-ul Yandex.Cloud este o limitare care complică operația de redimensionare pentru PV (Volum persistent): în acest caz, este necesar ca podul aplicației care folosește discul să fie oprit, iar acest lucru poate cauza aplicații de oprire.

În conformitate cu Specificațiile CSI, dacă controlerul CSI raportează că poate redimensiona discurile doar „offline” (VolumeExpansion.OFFLINE), atunci procesul de creștere a discului ar trebui să meargă astfel:

Dacă pluginul are doar VolumeExpansion.OFFLINE capacitatea și volumul de expansiune sunt în prezent publicate sau disponibile pe un nod atunci ControllerExpandVolume TREBUIE apelat NUMAI după:

  • Pluginul are controler PUBLISH_UNPUBLISH_VOLUME capacitatea și ControllerUnpublishVolume a fost invocat cu succes.

SAU

  • Plugin-ul NU are controler PUBLISH_UNPUBLISH_VOLUME capacitate, pluginul are nod STAGE_UNSTAGE_VOLUME capacitatea și NodeUnstageVolume a fost finalizat cu succes.

SAU

  • Plugin-ul NU are controler PUBLISH_UNPUBLISH_VOLUME capacitate, nici nod STAGE_UNSTAGE_VOLUME capacitatea și NodeUnpublishVolume a finalizat cu succes.

Acest lucru înseamnă în esență că trebuie să detașați discul de la mașina virtuală înainte de a-l extinde.

Cu toate acestea, din păcate punerea în aplicare Specificația CSI prin sidecars nu îndeplinește aceste cerințe:

  • Într-un container sidecar csi-attacher, care ar trebui să fie responsabil pentru prezența decalajului necesar între monturi, această funcționalitate pur și simplu nu este implementată în redimensionarea offline. S-a inițiat o discuție în acest sens aici.
  • Ce este mai exact un container sidecar în acest context? Pluginul CSI în sine nu interacționează cu API-ul Kubernetes, ci răspunde doar la apelurile gRPC trimise acestuia de containerele sidecar. Cele mai recente sunt în curs de dezvoltare de comunitatea Kubernetes.

În cazul nostru (plugin CSI), operația de creștere a discului arată astfel:

  1. Primim un apel gRPC ControllerExpandVolume;
  2. Încercăm să creștem discul în API, dar primim o eroare despre imposibilitatea efectuării operației deoarece discul este montat;
  3. Stocăm identificatorul discului în hartă, care conține discurile pentru care trebuie efectuată operația de creștere. Mai jos, pentru concizie, vom numi această hartă ca volumeResizeRequired;
  4. Scoateți manual podul care folosește discul. Kubernetes îl va reporni. Pentru ca discul să nu aibă timp să se monteze (ControllerPublishVolume) înainte de a finaliza operația de creștere atunci când încercăm montarea, verificăm dacă discul dat este încă în volumeResizeRequired și returnează o eroare;
  5. Driverul CSI încearcă să execute din nou operația de redimensionare. Dacă operațiunea a avut succes, scoateți discul de pe volumeResizeRequired;
  6. Deoarece ID-ul discului lipsește volumeResizeRequired, ControllerPublishVolume trece cu succes, discul este montat, podul pornește.

Totul pare destul de simplu, dar, ca întotdeauna, există capcane. Mărește discurile redimensionator extern, care în cazul unei erori în timpul operațiunii folosește o coadă cu o creștere exponențială a timpului de expirare până la 1000 de secunde:

func DefaultControllerRateLimiter() RateLimiter {
  return NewMaxOfRateLimiter(
  NewItemExponentialFailureRateLimiter(5*time.Millisecond, 1000*time.Second),
  // 10 qps, 100 bucket size.  This is only for retry speed and its only the overall factor (not per item)
  &BucketRateLimiter{Limiter: rate.NewLimiter(rate.Limit(10), 100)},
  )
}

Acest lucru poate duce periodic la extinderea operațiunii de expansiune a discului cu peste 15 minute și, astfel, podul corespunzător să fie indisponibil.

Singura opțiune care ne-a permis destul de ușor și fără durere să reducem potențialul timp de nefuncționare a fost utilizarea versiunii noastre de redimensionare externă cu o limită maximă de timeout. în 5 secunde:

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

Nu am considerat necesar să inițiem de urgență o discuție și să patchăm external-resizer-ul, deoarece redimensionarea offline a discurilor este o întoarcere care va dispărea în curând de la toți furnizorii de cloud.

Cum să începi să folosești?

Driverul este acceptat pe Kubernetes versiunea 1.15 și o versiune ulterioară. Pentru ca șoferul să funcționeze, trebuie îndeplinite următoarele cerințe:

  • pavilion --allow-privileged setat la valoare true pentru server API și kubelet;
  • Inclus --feature-gates=VolumeSnapshotDataSource=true,KubeletPluginsWatcher=true,CSINodeInfo=true,CSIDriverRegistry=true pentru server API și kubelet;
  • Propagarea montului (propagarea monturii) trebuie să fie activat pe cluster. Când utilizați Docker, demonul trebuie configurat pentru a permite monturi partajate.

Toți pașii necesari pentru instalarea în sine descrise în README. Instalarea implică crearea de obiecte în Kubernetes din manifeste.

Pentru ca șoferul să funcționeze, veți avea nevoie de următoarele:

  • Specificați identificatorul directorului în manifest (folder-id) Yandex.Cloud (vezi documentatia);
  • Pentru a interacționa cu API-ul Yandex.Cloud, driverul CSI utilizează un cont de serviciu. În manifest, Secretul trebuie transmis chei autorizate din contul de serviciu. În documentație descris, cum să creați un cont de serviciu și să obțineți cheile.

În întregime - încercați, și vom fi bucuroși să primim feedback și probleme noidaca intampini vreo problema!

Suport suplimentar

Drept urmare, am dori să menționăm că am implementat acest driver CSI nu dintr-o mare dorință de a ne distra scriind aplicații în Go, ci din cauza unei nevoi urgente în cadrul companiei. Nu ni se pare practic să ne menținem propria implementare, așa că dacă Yandex își arată interesul și decide să continue să sprijine driverul, vom fi bucuroși să le transferăm depozitul.

În plus, Yandex are probabil propria sa implementare a driverului CSI în clusterul Kubernetes gestionat, care poate fi lansat în Open Source. De asemenea, vedem această opțiune de dezvoltare ca fiind favorabilă - comunitatea va putea folosi un driver dovedit de la un furnizor de servicii și nu de la o companie terță.

PS

Citește și pe blogul nostru:

Sursa: www.habr.com

Adauga un comentariu