
Suntem încântați să anunțăm că compania „Flant” își aduce contribuția la instrumentele Open Source pentru Kubernetes, lansând (Container Storage Interface) pentru Yandex.Cloud.
Dar înainte de a intra în detalii despre implementare, să răspundem la întrebarea: de ce este necesar acest lucru, având în vedere că Yandex oferă deja serviciul .
Introducere
De ce este necesar?
În cadrul companiei noastre, încă de la începutul utilizării Kubernetes în producție (deci, de câțiva ani), s-a dezvoltat un instrument propriu (deckhouse), pe care, de fapt, intenționăm în curând să-l facem disponibil ca proiect Open Source. Cu ajutorul său, configurăm și setăm uniform toate clusterele noastre, iar în prezent avem deja peste 100, pe cele mai variate configurații hardware și în toate serviciile cloud disponibile.
Clusterele care folosesc deckhouse au toate componentele necesare pentru funcționare: balansatoare de încărcare, monitorizare cu grafice, metrici și alerte convenabile, autentificare a utilizatorilor prin furnizori externi pentru acces la toate dashboard-urile etc. Un astfel de cluster „avansat” nu are rost să fie instalat într-o soluție gestionată, deoarece de cele mai multe ori fie este imposibil, fie va necesita dezactivarea jumătate din componente.
NB: Aceasta este experiența noastră, și este destul de specifică. Nu afirmăm că toată lumea ar trebui să se ocupe de desfășurarea clustrelor Kubernetes în loc să folosească soluții gata făcute. De altfel, nu avem experiență reală în utilizarea Kubernetes de la Yandex și nu vom face nicio evaluare a acestui serviciu în acest articol.
Ce este și pentru cine?
Așadar, am vorbit deja despre abordarea modernă a stocării în Kubernetes: și la această abordare.
În prezent, mulți furnizori mari de servicii cloud au dezvoltat drivere pentru a utiliza disquele lor „cloud” ca Volume Persistent în Kubernetes. Dacă însă un astfel de driver nu există la furnizor, dar toate funcțiile necesare sunt oferite prin API, nimic nu împiedică implementarea unui driver propriu. Așa a fost și cazul nostru cu Yandex.Cloud.
Ca bază pentru dezvoltare am luat și câteva idei din , deoarece interacțiunea cu API-urile acestor cloud-uri (Google și Yandex) are anumite similitudini. În special, atât API-ul cât și , și returnează un obiect Operațiune pentru a urmări starea operațiunilor de lungă durată (de exemplu, crearea unui nou disco). Pentru interacțiunea cu API-ul Yandex.Cloud se utilizează .
Rezultatul muncii efectuate și poate fi util celor care, din diverse motive, folosesc propriile instalări Kubernetes pe mașini virtuale în Yandex.Cloud (dar nu un cluster gestionat gata) și ar dori să folosească (să comande) discuri prin CSI.
Implementarea
Funcționalități principale
În prezent, driverul suportă următoarele funcții:
- Comandarea de discuri în toate zonele cluster-ului conform topologiei nodurilor existente în cluster;
- Ștergerea discurilor comandate anterior;
- Redimensionare offline pentru discuri (Yandex.Cloud creșterea dimensiunii discurilor care sunt montate pe mașina virtuală). Despre cum a fost necesar să se modifice driverul pentru a efectua redimensionarea cât mai fără probleme, vedeți mai jos.
În viitor se preconizează implementarea suportului pentru crearea și ștergerea instantaneelor de discuri.
Dificultatea principală și depășirea acesteia
Lipsa în API-ul Yandex.Cloud a posibilității de a crește dimensiunea discurilor în timp real — o restricție care complică operația de redimensionare pentru PV (Persistent Volume): deoarece, în acest caz, trebuie să se oprească podul aplicației care utilizează discul, ceea ce poate provoca oprirea aplicației.
Conform , dacă controllerul CSI comunică că poate efectua redimensionarea discurilor doar „în offline” (VolumeExpansion.OFFLINE), atunci procesul de creștere a discului trebuie să decurgă astfel:
Dacă pluginul are doar
VolumeExpansion.OFFLINEcapabilitatea de expansiune și volumul este în prezent publicat sau disponibil pe un nod, atunciControllerExpandVolumeTREBUIE să fie apelat NUMAI după ce fie:
- Pluginul are controller
PUBLISH_UNPUBLISH_VOLUMEcapabilitate șiControllerUnpublishVolumea fost invocat cu succes.SAU ALTFEL
- Pluginul nu are capacitate de controller, pluginul are nod
PUBLISH_UNPUBLISH_VOLUMESTAGE_UNSTAGE_VOLUMEcapabilitate șiNodeUnstageVolumea fost finalizat cu succes.capabilitate, nici nodulSAU ALTFEL
- Pluginul nu are capacitate de controller, pluginul are nod
PUBLISH_UNPUBLISH_VOLUMENodeUnpublishVolumecapabilitate șiNodeUnstageVolumenu a fost finalizat cu succes.Practic, aceasta înseamnă că este necesar să deconectați discul de la mașina virtuală înainte de a-l crește.
Din păcate,
implementarea specificației CSI prin sidecar-uri nu corespunde acestor cerințe: În containerul sidecar
- csi-attacher
csi-attacher, care ar trebui să fie responsabil pentru prezența intervalului necesar între montări, deoarece această funcionalitate pur și simplu nu este implementată în cazul redimensionării offline. Discuția despre acest subiect a fost inițiată de . - Ce este, de fapt, un container sidecar în acest context? În sine, pluginul CSI nu interacționează cu API-ul Kubernetes, ci doar răspunde la apelurile gRPC pe care le trimite containerul sidecar. Acestea de comunitatea Kubernetes.
În cazul nostru (pluginul CSI), operațiunea de creștere a discului arată astfel:
- Primim apelul gRPC
ControllerExpandVolume; - Încercăm să creștem discul în API, dar primim o eroare cu privire la imposibilitatea de a efectua operația, deoarece discul este montat;
- Salvăm identificatorul discului într-o mapă care conține discurile pentru care trebuie să efectuăm operația de creștere. Vom denumi această mapă pentru scurt
volumeResizeRequired; - Ștergem manual podul care utilizează discul. Kubernetes îl va reporni. Pentru a ne asigura că discul nu este montat (
ControllerPublishVolume) înainte de finalizarea operației de creștere, verificăm că acest disc se află în continuare învolumeResizeRequiredși returnăm o eroare; - Driverul CSI încearcă să reia operația de redimensionare. Dacă operația a fost efectuată cu succes, atunci ștergem discul din
volumeResizeRequired; - Fiindcă identificatorul discului este absent în
volumeResizeRequired,ControllerPublishVolumeoperația se desfășoară cu succes, discul este montat, podul este repornit.
Totul pare destul de simplu, dar ca de obicei, există capcane. Creșterea discurilor este responsabilitatea , care în cazul unei erori în timpul execuției operației cu o creștere exponențială a timpului de așteptare până la 1000 de secunde:
func DefaultControllerRateLimiter() RateLimiter {
return NewMaxOfRateLimiter(
NewItemExponentialFailureRateLimiter(5*time.Millisecond, 1000*time.Second),
// 10 qps, 100 bucket size. Aceasta este doar pentru viteza de retry și este doar factorul general (nu pe element)
&BucketRateLimiter{Limiter: rate.NewLimiter(rate.Limit(10), 100)},
)
}Aceasta poate duce periodic la o întindere a operației de creștere a discului pe 15+ minute și, prin urmare, la indisponibilitatea podului corespunzător.
Singura opțiune care ne-a permis să reducă destul de ușor și fără durere timpul potențial de nefuncționare a fost utilizarea propriei versiuni a external-resizer cu o limitare maximă a timpului de așteptare :
workqueue.NewItemExponentialFailureRateLimiter(5*time.Millisecond, 5*time.Second)Nu am considerat necesar să inițiem o discuție de urgență și să patch-uim external-resizer, deoarece redimensionarea offline a discurilor este un atavism care în curând va dispărea din toate serviciile cloud.
Cum să începi să folosești?
Driverul este compatibil cu Kubernetes versiunea 1.15 și mai sus. Pentru a funcționa, driverul trebuie să respecte următoarele cerințe:
- Steagul
--allow-privilegedeste setat latruepentru API-server și kubelet; - Inclusiv
--feature-gates=VolumeSnapshotDataSource=true,KubeletPluginsWatcher=true,CSINodeInfo=true,CSIDriverRegistry=truepentru API-server și kubelet; - Propagarea montării () trebuie să fie activată în cluster. Atunci când utilizați Docker, demonul trebuie să fie configurat pentru a permite montările partajate.
Toți pașii necesari pentru instalare . Instalarea constă în crearea de obiecte în Kubernetes din manifesturi.
Pentru ca driverul să funcționeze, aveți nevoie de următoarele:
- Specificați în manifest ID-ul folderului (
folder-id) din Yandex.Cloud (); - Pentru a interacționa cu API-ul Yandex.Cloud în driverul CSI, este utilizat un cont de serviciu. În manifestul Secret, trebuie să transmiteți de la contul de serviciu. În documentație , cum să creați un cont de serviciu și să obțineți cheile.
În general, , iar noi vom fi bucuroși să primim feedback și , dacă vă confruntați cu probleme!
Suportul ulterior
În concluzie, am dori să subliniem că acest driver CSI a fost realizat nu din dorința de a ne distra scriind aplicații în Go, ci din necesitatea acută din interiorul companiei. A păstra propria noastră implementare nu ni se pare rentabil, așa că, dacă Yandex ar manifesta interesul și ar decide să continue suportul pentru driver, ne vom bucura să transferăm repository-ul în grija lor.
În plus, probabil că Yandex are în clusterul Kubernetes gestionat propria implementare a driverului CSI, pe care ar putea să o elibereze în Open Source. Această variantă ne-ar părea, de asemenea, favorabilă — comunitatea va putea beneficia de un driver verificat de la furnizorul de servicii, și nu de la o companie terță.
P.S.
Citiți și în blogul nostru:
- «»;
- «»;
- «»;
- «».
Sursa: habr.com
