Vår erfaring med å utvikle en CSI-driver i Kubernetes for Yandex.Cloud

Vår erfaring med å utvikle en CSI-driver i Kubernetes for Yandex.Cloud

Vi er glade for å kunngjøre at Flant utvider sitt bidrag til Open Source-verktøy for Kubernetes ved å gi ut alfaversjon av CSI-driveren (Container Storage Interface) for Yandex.Cloud.

Men før vi går videre til implementeringsdetaljene, la oss svare på spørsmålet hvorfor dette i det hele tatt er nødvendig når Yandex allerede har en tjeneste Administrert tjeneste for Kubernetes.

Innledning

Hvorfor er det sånn?

Innenfor vårt selskap har vi helt fra begynnelsen av å bruke Kubernetes i produksjon (dvs. i flere år nå), utviklet vårt eget verktøy (dekkhus), som vi forresten også planlegger å snart gjøre tilgjengelig som et åpen kildekode-prosjekt . Med dens hjelp konfigurerer og konfigurerer vi alle våre klynger ensartet, og for tiden er det allerede mer enn 100 av dem, på et bredt utvalg av maskinvarekonfigurasjoner og i alle tilgjengelige skytjenester.

Klynger som bruker dekkshus har alle komponentene som er nødvendige for drift: balansere, overvåking med praktiske diagrammer, beregninger og varsler, brukerautentisering gjennom eksterne leverandører for tilgang til alle dashbord, og så videre. Det er ingen vits i å installere en slik "opppumpet" klynge i en administrert løsning, siden dette ofte enten er umulig eller vil føre til at halvparten av komponentene må deaktiveres.

NB: Dette er vår erfaring, og den er ganske spesifikk. Vi foreslår på ingen måte at alle skal distribuere Kubernetes-klynger på egen hånd i stedet for å bruke ferdige løsninger. Forresten, vi har ingen reell erfaring med å betjene Kubernetes fra Yandex, og vi vil ikke gi noen vurdering av denne tjenesten i denne artikkelen.

Hva er det og for hvem?

Så vi har allerede snakket om den moderne tilnærmingen til lagring i Kubernetes: hvordan fungerer CSI? и hvordan samfunnet kom til denne tilnærmingen.

For tiden har mange store skytjenesteleverandører utviklet drivere for å bruke skydiskene deres som vedvarende volum i Kubernetes. Hvis leverandøren ikke har en slik driver, men alle nødvendige funksjoner leveres via API, så er det ingenting som hindrer deg i å implementere driveren selv. Dette er hva som skjedde med Yandex.Cloud.

Vi tok utgangspunkt i utviklingen CSI-driver for DigitalOcean cloud og et par ideer fra drivere for GCP, siden interaksjon med APIen til disse skyene (Google og Yandex) har en rekke likheter. Spesielt API og GCP, og kl Yandex returnere et objekt Operation for å spore statusen til langvarige operasjoner (for eksempel å lage en ny disk). For å samhandle med Yandex.Cloud API, bruk Yandex.Cloud Go SDK.

Resultatet av arbeidet som er utført publisert på GitHub og kan være nyttig for de som av en eller annen grunn bruker sin egen Kubernetes-installasjon på virtuelle Yandex.Cloud-maskiner (men ikke en ferdig administrert klynge) og ønsker å bruke (bestille) disker gjennom CSI.

implementering

Viktige funksjoner

For øyeblikket støtter driveren følgende funksjoner:

  • Ordne disker i alle soner i klyngen i henhold til topologien til nodene i klyngen;
  • Fjerning av tidligere bestilte plater;
  • Frakoblet størrelse for disker (Yandex.Cloud ikke støtter øke diskene som er montert på den virtuelle maskinen). For informasjon om hvordan driveren måtte modifiseres for å gjøre endring av størrelse så smertefri som mulig, se nedenfor.

I fremtiden planlegger vi å implementere støtte for å lage og slette disk-øyeblikksbilder.

Den største vanskeligheten og hvordan du kan overvinne den

Mangelen på muligheten til å øke disker i sanntid i Yandex.Cloud API er en begrensning som kompliserer størrelsesoperasjonen for PV (Persistent Volume): i dette tilfellet er det nødvendig at applikasjonsputen som bruker disken stoppes, og dette kan forårsake nedetidsapplikasjoner.

Ifølge CSI-spesifikasjoner, hvis CSI-kontrolleren rapporterer at den kan endre størrelsen på disker bare "frakoblet" (VolumeExpansion.OFFLINE), så skal prosessen med å øke disken gå slik:

Hvis plugin-en bare har VolumeExpansion.OFFLINE utvidelseskapasitet og volum er for øyeblikket publisert eller tilgjengelig på en node da ControllerExpandVolume MÅ ringes KUN etter enten:

  • Programtillegget har kontroller PUBLISH_UNPUBLISH_VOLUME kapasitet og ControllerUnpublishVolume har blitt påkalt.

ELLERS

  • Programtillegget har IKKE kontroller PUBLISH_UNPUBLISH_VOLUME kapasitet, plugin har node STAGE_UNSTAGE_VOLUME evne, og NodeUnstageVolume er fullført.

ELLERS

  • Programtillegget har IKKE kontroller PUBLISH_UNPUBLISH_VOLUME kapasitet, heller ikke node STAGE_UNSTAGE_VOLUME evne, og NodeUnpublishVolume har fullført.

Dette betyr i hovedsak at du må koble disken fra den virtuelle maskinen før du utvider den.

Men dessverre realisering av CSI-spesifikasjonen via sidevogner oppfyller ikke disse kravene:

  • I en sidevognscontainer csi-attacher, som bør være ansvarlig for tilstedeværelsen av det nødvendige gapet mellom monteringer, er denne funksjonaliteten ganske enkelt ikke implementert i den frakoblede størrelsen. Det ble innledet en diskusjon om dette her.
  • Hva er egentlig en sidevognscontainer i denne sammenhengen? CSI-pluginen i seg selv samhandler ikke med Kubernetes API, men reagerer bare på gRPC-anrop som sendes til den av sidevognsbeholdere. Siste er under utvikling av Kubernetes-fellesskapet.

I vårt tilfelle (CSI-plugin) ser operasjonen for å øke disken slik ut:

  1. Vi mottar en gRPC-samtale ControllerExpandVolume;
  2. Vi prøver å øke disken i API, men vi får en feilmelding om umuligheten av å utføre operasjonen fordi disken er montert;
  3. Vi lagrer diskidentifikatoren i kartet, som inneholder diskene som økningsoperasjonen må utføres for. Nedenfor vil vi for korthets skyld kalle dette kartet som volumeResizeRequired;
  4. Fjern poden som bruker disken manuelt. Kubernetes vil starte den på nytt. Slik at disken ikke har tid til å montere (ControllerPublishVolume) før vi fullfører økningsoperasjonen når vi prøver å montere, sjekker vi at den gitte disken fortsatt er inne volumeResizeRequired og returnere en feil;
  5. CSI-driveren prøver å utføre endringsoperasjonen på nytt. Hvis operasjonen var vellykket, fjerner du disken fra volumeResizeRequired;
  6. Fordi Disk-ID mangler fra volumeResizeRequired, ControllerPublishVolume passerer vellykket, disken er montert, poden starter.

Alt ser enkelt nok ut, men som alltid er det fallgruver. Forstørrer disker ekstern resizer, som i tilfelle feil under operasjonen bruker en kø med en eksponentiell økning i timeout-tid opp 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 jevne mellomrom føre til at diskutvidelsesoperasjonen forlenges i 15+ minutter og dermed at den tilsvarende poden ikke er tilgjengelig.

Det eneste alternativet som ganske enkelt og smertefritt tillot oss å redusere potensiell nedetid var bruken av vår versjon av ekstern resizer med en maksimal tidsavbruddsgrense på 5 sekunder:

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

Vi anså det ikke som nødvendig å snarest starte en diskusjon og lappe den eksterne resizeren, fordi offline-størrelsen på disker er en tilbakevending som snart vil forsvinne fra alle skyleverandører.

Hvordan begynne å bruke?

Driveren støttes på Kubernetes versjon 1.15 og høyere. For at sjåføren skal fungere, må følgende krav være oppfylt:

  • flagg --allow-privileged satt til verdi true for API-server og kubelet;
  • Inkludert --feature-gates=VolumeSnapshotDataSource=true,KubeletPluginsWatcher=true,CSINodeInfo=true,CSIDriverRegistry=true for API-server og kubelet;
  • Mount forplantning (mount forplantning) må være aktivert på klyngen. Når du bruker Docker, må daemonen konfigureres til å tillate delte monteringer.

Alle nødvendige trinn for selve installasjonen beskrevet i README. Installasjon innebærer å lage objekter i Kubernetes fra manifester.

For at sjåføren skal fungere trenger du følgende:

  • Spesifiser katalogidentifikatoren i manifestet (folder-id) Yandex.Cloud (se dokumentasjon);
  • For å samhandle med Yandex.Cloud API, bruker CSI-driveren en tjenestekonto. I manifestet må Secret sendes autoriserte nøkler fra tjenestekontoen. I dokumentasjonen beskrevet, hvordan du oppretter en tjenestekonto og får nøkler.

Alt i alt - prøve, og vi vil gjerne motta tilbakemeldinger og nye problemstillingerhvis du støter på problemer!

Ytterligere støtte

Som et resultat vil vi merke at vi implementerte denne CSI-driveren ikke av et stort ønske om å ha det gøy med å skrive applikasjoner i Go, men på grunn av et presserende behov i selskapet. Det virker ikke praktisk for oss å opprettholde vår egen implementering, så hvis Yandex viser interesse og bestemmer seg for å fortsette å støtte driveren, vil vi gjerne overføre depotet til dem.

I tillegg har Yandex sannsynligvis sin egen implementering av CSI-driveren i sin administrerte Kubernetes-klynge, som kan utgis i åpen kildekode. Vi ser også på dette utviklingsalternativet som gunstig – fellesskapet vil kunne bruke en velprøvd driver fra en tjenesteleverandør, og ikke fra et tredjepartsselskap.

PS

Les også på bloggen vår:

Kilde: www.habr.com

Legg til en kommentar