Vores erfaring med at udvikle en CSI-driver i Kubernetes til Yandex.Cloud

Vores erfaring med at udvikle en CSI-driver i Kubernetes til Yandex.Cloud

Vi er glade for at kunne meddele, at Flant udvider sit bidrag til Open Source-værktøjer til Kubernetes ved at frigive alfa-version af CSI-driveren (Container Storage Interface) til Yandex.Cloud.

Men før vi går videre til implementeringsdetaljerne, lad os besvare spørgsmålet, hvorfor det overhovedet er nødvendigt, når Yandex allerede har en tjeneste Administreret service til Kubernetes.

Indledning

Hvorfor er det?

Inden for vores virksomhed har vi lige fra begyndelsen af ​​at bruge Kubernetes i produktionen (dvs. i flere år nu) udviklet vores eget værktøj (dækhus), som vi i øvrigt også planlægger snart at gøre tilgængeligt som et Open Source-projekt . Med dens hjælp konfigurerer og konfigurerer vi alle vores klynger ensartet, og i øjeblikket er der allerede mere end 100 af dem, på en lang række hardwarekonfigurationer og i alle tilgængelige cloud-tjenester.

Klynger, der bruger dækshus, har alle de komponenter, der er nødvendige for driften: balancerer, overvågning med praktiske diagrammer, metrikker og advarsler, brugergodkendelse gennem eksterne udbydere for adgang til alle dashboards og så videre. Det nytter ikke at installere sådan en "pumpet op" klynge i en administreret løsning, da dette ofte enten er umuligt eller vil føre til behovet for at deaktivere halvdelen af ​​komponenterne.

NB: Dette er vores erfaring, og det er ret specifikt. Vi foreslår på ingen måde, at alle skal implementere Kubernetes-klynger på egen hånd i stedet for at bruge færdige løsninger. Forresten har vi ingen reel erfaring med at betjene Kubernetes fra Yandex, og vi vil ikke give nogen vurdering af denne tjeneste i denne artikel.

Hvad er det og for hvem?

Så vi har allerede talt om den moderne tilgang til opbevaring i Kubernetes: hvordan virker CSI? и hvordan fællesskabet kom til denne tilgang.

I øjeblikket har mange store cloud-tjenesteudbydere udviklet drivere til at bruge deres cloud-diske som persistent volumen i Kubernetes. Hvis leverandøren ikke har en sådan driver, men alle de nødvendige funktioner leveres via API'en, så forhindrer intet dig i selv at implementere driveren. Dette er, hvad der skete med Yandex.Cloud.

Vi tog udgangspunkt i udviklingen CSI-driver til digitalocean cloud og et par ideer fra drivere til GCP, da interaktion med disse skyers API (Google og Yandex) har en række ligheder. Især API og GCPog kl Yandex returnere et objekt Operation for at spore status for langvarige operationer (f.eks. oprettelse af en ny disk). For at interagere med Yandex.Cloud API skal du bruge Yandex.Cloud Go SDK.

Resultatet af det udførte arbejde udgivet på GitHub og kan være nyttige for dem, der af en eller anden grund bruger deres egen Kubernetes-installation på Yandex.Cloud virtuelle maskiner (men ikke en færdiglavet administreret klynge) og gerne vil bruge (bestille) diske gennem CSI.

implementering

Nøglefunktioner

I øjeblikket understøtter driveren følgende funktioner:

  • Ordre diske i alle zoner i klyngen i henhold til topologien af ​​noderne i klyngen;
  • Fjernelse af tidligere bestilte diske;
  • Offline ændring af størrelse på diske (Yandex.Cloud ikke understøtter forøgelse af de diske, der er monteret på den virtuelle maskine). For information om, hvordan driveren skulle modificeres for at gøre størrelsesændring så smertefri som muligt, se nedenfor.

I fremtiden planlægger vi at implementere support til oprettelse og sletning af disk-snapshots.

Den største vanskelighed og hvordan man overvinder den

Manglen på evnen til at øge diske i realtid i Yandex.Cloud API er en begrænsning, der komplicerer størrelsesændringen for PV (Persistent Volume): i dette tilfælde er det nødvendigt, at den applikationspod, der bruger disken, stoppes, og dette kan forårsage nedetidsapplikationer.

Ifølge CSI specifikationer, hvis CSI-controlleren rapporterer, at den kun kan ændre størrelsen på diske "offline" (VolumeExpansion.OFFLINE), så skulle processen med at øge disken gå sådan her:

Hvis plugin'et kun har VolumeExpansion.OFFLINE udvidelseskapacitet og volumen er i øjeblikket udgivet eller tilgængelig på en node ControllerExpandVolume SKAL KUN kaldes efter enten:

  • Pluginnet har controller PUBLISH_UNPUBLISH_VOLUME kapacitet og ControllerUnpublishVolume er blevet påkaldt med succes.

ELLERS

  • Pluginnet har IKKE controller PUBLISH_UNPUBLISH_VOLUME kapacitet, plugin'et har node STAGE_UNSTAGE_VOLUME kapacitet, og NodeUnstageVolume er afsluttet med succes.

ELLERS

  • Pluginnet har IKKE controller PUBLISH_UNPUBLISH_VOLUME kapacitet eller node STAGE_UNSTAGE_VOLUME kapacitet, og NodeUnpublishVolume er afsluttet med succes.

Dette betyder i bund og grund, at du skal afmontere disken fra den virtuelle maskine, før du udvider den.

Dog desværre implementering CSI-specifikationen via sidevogne opfylder ikke disse krav:

  • I en sidevognscontainer csi-attacher, som burde være ansvarlig for tilstedeværelsen af ​​det nødvendige mellemrum mellem monteringer, er denne funktionalitet simpelthen ikke implementeret i offline-størrelsen. En diskussion herom blev indledt her.
  • Hvad er en sidevognscontainer egentlig i denne sammenhæng? CSI-pluginet i sig selv interagerer ikke med Kubernetes API, men reagerer kun på gRPC-kald, der sendes til det af sidevognscontainere. Seneste er under udvikling af Kubernetes-fællesskabet.

I vores tilfælde (CSI-plugin) ser operationen med at øge disken sådan ud:

  1. Vi modtager et gRPC-opkald ControllerExpandVolume;
  2. Vi forsøger at øge disken i API'et, men vi modtager en fejl om umuligheden af ​​at udføre handlingen, fordi disken er monteret;
  3. Vi gemmer diskidentifikatoren i map, som indeholder de diske, for hvilke stigningsoperationen skal udføres. Nedenfor vil vi for kortheds skyld kalde dette kort som volumeResizeRequired;
  4. Fjern manuelt den pod, der bruger disken. Kubernetes genstarter den. Så disken ikke når at montere (ControllerPublishVolume) før vi fuldfører stigningsoperationen, når vi forsøger at montere, kontrollerer vi, at den givne disk stadig er i volumeResizeRequired og returnere en fejl;
  5. CSI-driveren forsøger at gen-udføre størrelsesændringsoperationen. Hvis handlingen lykkedes, skal du fjerne disken fra volumeResizeRequired;
  6. Fordi Disk-id mangler fra volumeResizeRequired, ControllerPublishVolume passerer med succes, disken er monteret, poden starter.

Alt ser simpelt nok ud, men som altid er der faldgruber. Forstørrer diske ekstern resizer, hvilket i tilfælde af fejl under operationen bruger en kø med en eksponentiel stigning i timeouttid op til 1000 sekunder:

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)},
  )
}

Dette kan med jævne mellemrum resultere i, at diskudvidelsesoperationen forlænges i 15+ minutter, og dermed er den tilsvarende pod utilgængelig.

Den eneste mulighed, der ganske nemt og smertefrit tillod os at reducere potentiel nedetid, var brugen af ​​vores version af ekstern resizer med en maksimal timeout-grænse på 5 sekunder:

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

Vi anså det ikke for nødvendigt hurtigt at indlede en diskussion og lappe den eksterne resizer, fordi offline-ændring af diske er et tilbageslag, der snart vil forsvinde fra alle cloud-udbydere.

Hvordan begynder man at bruge det?

Driveren understøttes på Kubernetes version 1.15 og nyere. For at chaufføren kan arbejde, skal følgende krav være opfyldt:

  • flag --allow-privileged indstillet til værdi true til API-server og kubelet;
  • Inkluderet --feature-gates=VolumeSnapshotDataSource=true,KubeletPluginsWatcher=true,CSINodeInfo=true,CSIDriverRegistry=true til API-server og kubelet;
  • Mount udbredelse (mount udbredelse) skal være aktiveret på klyngen. Når du bruger Docker, skal dæmonen konfigureres til at tillade delte mounts.

Alle de nødvendige trin til selve installationen beskrevet i README. Installation involverer at skabe objekter i Kubernetes fra manifester.

For at chaufføren kan arbejde skal du bruge følgende:

  • Angiv mappe-id'et i manifestet (folder-id) Yandex.Cloud (se dokumentation);
  • For at interagere med Yandex.Cloud API'en bruger CSI-driveren en tjenestekonto. I manifestet skal Secret videregives autoriserede nøgler fra servicekontoen. I dokumentationen beskrevet, hvordan man opretter en servicekonto og får nøgler.

Alt i alt - prøv det, og vi vil være glade for at modtage feedback og nye spørgsmålhvis du støder på problemer!

Yderligere støtte

Som et resultat vil vi gerne bemærke, at vi implementerede denne CSI-driver ikke ud fra et stort ønske om at have det sjovt med at skrive applikationer i Go, men på grund af et presserende behov i virksomheden. Det forekommer os ikke praktisk at opretholde vores egen implementering, så hvis Yandex viser interesse og beslutter at fortsætte med at støtte driveren, vil vi med glæde overføre lageret til dem.

Yandex har desuden sandsynligvis sin egen implementering af CSI-driveren i sin administrerede Kubernetes-klynge, som kan frigives i Open Source. Vi ser også denne udviklingsmulighed som gunstig - samfundet vil være i stand til at bruge en gennemprøvet driver fra en tjenesteudbyder og ikke fra en tredjepartsvirksomhed.

PS

Læs også på vores blog:

Kilde: www.habr.com

Tilføj en kommentar