Vår erfarenhet av att utveckla en CSI-drivrutin i Kubernetes för Yandex.Cloud

Vår erfarenhet av att utveckla en CSI-drivrutin i Kubernetes för Yandex.Cloud

Vi är glada att kunna meddela att Flant utökar sitt bidrag till Open Source-verktyg för Kubernetes genom att släppa alfaversionen av CSI-drivrutinen (Container Storage Interface) för Yandex.Cloud.

Men innan vi går vidare till implementeringsdetaljerna, låt oss svara på frågan om varför detta överhuvudtaget behövs när Yandex redan har en tjänst Hanterad tjänst för Kubernetes.

Inledning

Varför är detta?

Inom vårt företag har vi redan från början av att använda Kubernetes i produktionen (dvs. sedan flera år tillbaka) utvecklat vårt eget verktyg (däckhus), som vi för övrigt också planerar att snart göra tillgängligt som ett Open Source-projekt . Med dess hjälp konfigurerar och konfigurerar vi alla våra kluster enhetligt, och för närvarande finns det redan mer än 100 av dem, på en mängd olika hårdvarukonfigurationer och i alla tillgängliga molntjänster.

Kluster som använder däckshus har alla komponenter som behövs för drift: balanserare, övervakning med praktiska diagram, mätvärden och varningar, användarautentisering genom externa leverantörer för åtkomst till alla instrumentpaneler och så vidare. Det är ingen mening att installera ett sådant "upppumpat" kluster i en hanterad lösning, eftersom detta ofta antingen är omöjligt eller kommer att leda till att hälften av komponenterna måste inaktiveras.

NB: Detta är vår erfarenhet och den är ganska specifik. Vi föreslår inte på något sätt att alla ska distribuera Kubernetes-kluster på egen hand istället för att använda färdiga lösningar. Förresten, vi har ingen riktig erfarenhet av att driva Kubernetes från Yandex och vi kommer inte att ge någon bedömning av denna tjänst i den här artikeln.

Vad är det och för vem?

Så vi har redan pratat om det moderna tillvägagångssättet för lagring i Kubernetes: hur fungerar CSI? и hur samhället kom till detta tillvägagångssätt.

För närvarande har många stora molntjänsteleverantörer utvecklat drivrutiner för att använda sina molndiskar som persistent volym i Kubernetes. Om leverantören inte har en sådan drivrutin, men alla nödvändiga funktioner tillhandahålls via API:t, så hindrar ingenting dig från att implementera drivrutinen själv. Detta är vad som hände med Yandex.Cloud.

Vi tog som grund för utveckling CSI-drivrutin för digitalocean cloud och ett par idéer från drivrutiner för GCP, eftersom interaktion med API:et för dessa moln (Google och Yandex) har ett antal likheter. I synnerhet API och GCP, och Yandex returnera ett objekt Operation för att spåra status för långvariga operationer (till exempel skapa en ny disk). För att interagera med Yandex.Cloud API, använd Yandex.Cloud Go SDK.

Resultatet av det utförda arbetet publicerad på GitHub och kan vara användbar för dem som av någon anledning använder sin egen Kubernetes-installation på virtuella Yandex.Cloud-maskiner (men inte ett färdigt hanterat kluster) och vill använda (beställa) diskar genom CSI.

genomförande

Viktiga funktioner

För närvarande stöder drivrutinen följande funktioner:

  • Ordna skivor i alla zoner i klustret enligt topologin för noderna i klustret;
  • Ta bort tidigare beställda skivor;
  • Ändra storlek offline för diskar (Yandex.Cloud stöder inte öka antalet diskar som är monterade på den virtuella maskinen). För information om hur drivrutinen måste modifieras för att göra storleksändring så smärtfri som möjligt, se nedan.

I framtiden planerar vi att implementera stöd för att skapa och ta bort skivögonblicksbilder.

Den största svårigheten och hur man kan övervinna den

Avsaknaden av möjligheten att öka diskarna i realtid i Yandex.Cloud API är en begränsning som komplicerar storleksändringen för PV (Persistent Volume): i det här fallet är det nödvändigt att applikationspodden som använder disken stoppas, och detta kan orsaka driftstopp.

Enligt CSI-specifikationer, om CSI-styrenheten rapporterar att den bara kan ändra storlek på diskar "offline" (VolumeExpansion.OFFLINE), bör processen att öka disken gå så här:

Om plugin endast har VolumeExpansion.OFFLINE expansionskapacitet och volym är för närvarande publicerad eller tillgänglig på en nod då ControllerExpandVolume MÅSTE bli anropad ENDAST efter antingen:

  • Insticksprogrammet har kontroller PUBLISH_UNPUBLISH_VOLUME förmåga och ControllerUnpublishVolume har anropats framgångsrikt.

ANNARS

  • Insticksprogrammet har INTE kontroller PUBLISH_UNPUBLISH_VOLUME kapacitet, plugin har nod STAGE_UNSTAGE_VOLUME förmåga och NodeUnstageVolume har slutförts framgångsrikt.

ANNARS

  • Insticksprogrammet har INTE kontroller PUBLISH_UNPUBLISH_VOLUME förmåga, inte heller nod STAGE_UNSTAGE_VOLUME förmåga och NodeUnpublishVolume har slutförts framgångsrikt.

Detta betyder i huvudsak att du måste ta bort disken från den virtuella maskinen innan du expanderar den.

Dock tyvärr genomförande CSI-specifikationen via sidvagnar uppfyller inte dessa krav:

  • I en sidvagnscontainer csi-attacher, som borde vara ansvarig för förekomsten av det nödvändiga gapet mellan monteringen, är denna funktion helt enkelt inte implementerad i offlinestorleksändringen. En diskussion om detta inleddes här.
  • Vad är egentligen en sidvagnscontainer i detta sammanhang? CSI-pluginet i sig interagerar inte med Kubernetes API, utan svarar bara på gRPC-anrop som skickas till det av sidovagnscontainrar. Senast håller på att utvecklas av Kubernetes-gemenskapen.

I vårt fall (CSI-plugin) ser operationen att öka disken ut så här:

  1. Vi får ett gRPC-samtal ControllerExpandVolume;
  2. Vi försöker utöka disken i API:t, men vi får ett felmeddelande om omöjligheten att utföra operationen eftersom disken är monterad;
  3. Vi lagrar diskidentifieraren i kartan, som innehåller de diskar för vilka ökningsoperationen måste utföras. Nedan, för korthets skull, kommer vi att kalla denna karta som volumeResizeRequired;
  4. Ta bort kapseln som använder skivan manuellt. Kubernetes kommer att starta om det. Så att disken inte hinner monteras (ControllerPublishVolume) innan vi slutför ökningsoperationen när vi försöker montera, kontrollerar vi att den givna disken fortfarande finns i volumeResizeRequired och returnera ett fel;
  5. CSI-drivrutinen försöker köra om storleksändringsoperationen. Om operationen lyckades, ta sedan bort disken från volumeResizeRequired;
  6. Därför att Disk-ID saknas från volumeResizeRequired, ControllerPublishVolume passerar framgångsrikt, skivan är monterad, podden startar.

Allt ser enkelt ut, men som alltid finns det fallgropar. Förstorar skivor extern resizer, vilket i händelse av ett fel under operationen använder en kö med en exponentiell ökning av timeouttiden upp till 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)},
  )
}

Detta kan med jämna mellanrum leda till att diskexpansionsoperationen förlängs i 15+ minuter och att motsvarande pod därför inte är tillgänglig.

Det enda alternativet som ganska enkelt och smärtfritt tillät oss att minska potentiell driftstopp var användningen av vår version av extern resizer med en maximal tidsgräns på 5 sekunder:

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

Vi ansåg det inte nödvändigt att omedelbart inleda en diskussion och korrigera den externa resizern, för att ändra storlek på diskar offline är en återgång som snart kommer att försvinna från alla molnleverantörer.

Hur börjar man använda det?

Drivrutinen stöds på Kubernetes version 1.15 och senare. För att föraren ska fungera måste följande krav uppfyllas:

  • flag --allow-privileged inställd på värde true för API-server och kubelet;
  • Ingår --feature-gates=VolumeSnapshotDataSource=true,KubeletPluginsWatcher=true,CSINodeInfo=true,CSIDriverRegistry=true för API-server och kubelet;
  • Monteringsförökning (bergets utbredning) måste vara aktiverat på klustret. När du använder Docker måste demonen konfigureras för att tillåta delade monteringar.

Alla nödvändiga steg för själva installationen beskrivs i README. Installation innebär att man skapar objekt i Kubernetes från manifest.

För att föraren ska fungera behöver du följande:

  • Ange katalogidentifieraren i manifestet (folder-id) Yandex.Cloud (se dokumentation);
  • För att interagera med Yandex.Cloud API använder CSI-drivrutinen ett tjänstkonto. I manifestet måste Secret skickas auktoriserade nycklar från tjänstekontot. I dokumentationen beskrivs, hur man skapar ett tjänstekonto och får nycklar.

Allt som allt - prova, och vi tar gärna emot feedback och nya frågorom du stöter på några problem!

Ytterligare stöd

Som ett resultat av detta vill vi notera att vi implementerade denna CSI-drivrutin inte av en stor önskan att ha roligt med att skriva ansökningar i Go, utan på grund av ett akut behov inom företaget. Det verkar inte praktiskt för oss att behålla vår egen implementering, så om Yandex visar intresse och bestämmer sig för att fortsätta stödja föraren, kommer vi gärna att överföra förvaret till dem.

Dessutom har Yandex förmodligen sin egen implementering av CSI-drivrutinen i sitt hanterade Kubernetes-kluster, som kan släppas i Open Source. Vi ser också detta utvecklingsalternativ som gynnsamt - samhället kommer att kunna använda en beprövad drivrutin från en tjänsteleverantör och inte från ett tredjepartsföretag.

PS

Läs även på vår blogg:

Källa: will.com

Lägg en kommentar