Naše zkušenosti s vývojem CSI ovladače v Kubernetes pro Yandex.Cloud

Naše zkušenosti s vývojem CSI ovladače v Kubernetes pro Yandex.Cloud

S potěšením oznamujeme, že společnost „Flant“ posiluje svůj příspěvek k nástrojům Open Source pro Kubernetes vydáním alfaverze řidiče CSI (Container Storage Interface) pro Yandex.Cloud.

Ale předtím, než se dostaneme k podrobnostem implementace, odpovězme na otázku, proč to vlastně potřebujeme, když má Yandex již službu Managed Service for Kubernetes.

Úvod

Proč to?

Uvnitř naší společnosti, ještě od samého začátku používání Kubernetes v produkci (tj. už několik let), se vyvíjí vlastní nástroj (deckhouse), který, mimochodem, plánujeme brzy zpřístupnit jako projekt Open Source. S jeho pomocí jednotně konfigurujeme a nastavujeme všechny naše clustery, a v současné době jich máme více než 100, přičemž na nejrůznějších konfiguracích hardware a ve všech dostupných cloudových službách.

Clustery, ve kterých se používá deckhouse, obsahují všechny potřebné komponenty pro provoz: vyvažovače zatížení, monitoring s pohodlnými grafy, metrikami a upozorněními, autentizaci uživatelů prostřednictvím externích poskytovatelů pro přístup ke všem dashboardům a tak dále. Takový „vylepšený“ cluster nemá smysl nasazovat v managed řešení, protože to často není možné, nebo to povede k nutnosti vypnout polovinu komponentů.

NB: Toto je naše zkušenost a je poměrně specifická. V žádném případě netvrdíme, že se všichni mají sami zabývat nasazením clusterů Kubernetes namísto toho, aby využívali hotová řešení. Mimochodem, reálnou zkušenost s používáním Kubernetes od Yandexu nemáme a v této článku nebudeme hodnotit tuto službu.

Co to je a pro koho?

Takže jsme již hovořili o moderním přístupu k úložištím v Kubernetes: jak funguje CSI a jak se komunita dostala k takovému přístupu.

V současné době mnoho velkých poskytovatelů cloudových služeb vyvinulo ovladače pro použití svých „cloudových“ disků jako Persistent Volume v Kubernetes. Pokud však daný poskytovatel nemá takový ovladač, ale všechny potřebné funkce jsou poskytovány přes API, nic nebrání tomu, abychom ovladač realizovali vlastními silami. A tak se to stalo i s Yandex.Cloud.

Základem pro vývoj jsme vzali CSI-driver pro cloud DigitalOcean a pár myšlenek z driveru pro GCP, protože interakce s API těchto cloudů (Google a Yandex) má řadu podobností. Především, API mají jak GCP, tak Yandex vrací objekt Operace pro sledování stavu dlouhotrvajících operací (například vytváření nového disku). Pro interakci s API Yandex.Cloud se používá Yandex.Cloud Go SDK.

Výsledek vykonané práce je zveřejněn na GitHubu a může být užitečný těm, kteří z nějakého důvodu používají vlastní instalaci Kubernetes na virtuálních strojích Yandex.Cloud (ale ne hotový managed cluster) a chtěli by používat (objednávat) disky prostřednictvím CSI.

Implementace

Hlavní funkce

V současné době ovladač podporuje následující funkce:

  • Objednávání disků ve všech zónách clusteru podle topologie existujících uzlů v clusteru;
  • Odstraňování dříve objednaných disků;
  • Offline resize pro disky (Yandex.Cloud nepodporuje zvětšování disků, které jsou připojeny k virtuálnímu stroji). O tom, jak bylo nutné upravit ovladač pro co nejbezproblémovější provedení resize, viz níže.

Do budoucna se plánuje realizace podpory vytváření a odstraňování snímků disků.

Hlavní obtíž a její překonání

Nedostatek možnosti zvyšování disků v reálném čase v API Yandex.Cloud — omezení, které ztěžuje operaci resize pro PV (Persistent Volume): vždyť v takovém případě je nutné, aby pod aplikace, která používá disk, byl zastaven, a to může způsobit nefunkčnost aplikace.

Podle specifikace CSI, pokud CSI řadič hlásí, že umí provádět resize disků pouze „offline“ (VolumeExpansion.OFFLINE), pak proces zvyšování disku musí probíhat takto:

Pokud plugin má pouze VolumeExpansion.OFFLINE capability pro zvětšení a objem je aktuálně publikován nebo dostupný na uzlu, pak ControllerExpandVolume MUSÍ být volán POUZE po:

  • Plugin má řadič PUBLISH_UNPUBLISH_VOLUME capability a ControllerUnpublishVolume byl úspěšně vyvolán.

NEBO

  • Pokud plugin NEMÁ řadič PUBLISH_UNPUBLISH_VOLUME capability, plugin má uzlové STAGE_UNSTAGE_VOLUME capability a NodeUnstageVolume byl úspěšně dokončen.

NEBO

  • Pokud plugin NEMÁ řadič PUBLISH_UNPUBLISH_VOLUME kapacitu, ani uzel STAGE_UNSTAGE_VOLUME capability a NodeUnpublishVolume byl úspěšně dokončen.

V podstatě to znamená, že je nutné odpojit disk od virtuálního stroje, než ho zvětšíte.

Bohužel však, implementace specifikace CSI prostřednictvím sidecarů neodpovídají těmto požadavkům:

  • V sidecar kontejneru csi-attacher, který by měl zajišťovat přítomnost potřebného intervalu mezi montážemi, není při offline-resize jednoduše tento funkční prvek realizován. Diskusi o tom iniciovali zde.
  • Co vlastně znamená sidecar kontejner v tomto kontextu? Samotný CSI plugin se nezabývá interakcí s Kubernetes API, ale pouze reaguje na gRPC volání, která mu posílají sidecar kontejnery. Tyto jsou vyvíjeny komunity Kubernetes.

V našem případě (CSI plugin) operace zvětšení disku vypadá takto:

  1. Získáváme gRPC volání ControllerExpandVolume;
  2. Snažíme se zvětšit disk v API, ale obdržíme chybu o nemožnosti provést operaci, protože disk je připojen;
  3. Ukládáme identifikátor disku do mapy, která obsahuje disky, pro které je třeba provést operaci zvětšení. Dále pro stručnost budeme tuto mapu nazývat volumeResizeRequired;
  4. Ručním způsobem odstraňujeme pod, který používá disk. Kubernetes ho přitom restartuje. Aby disk nebyl připojen (ControllerPublishVolume) před dokončením operace zvětšení při pokusu o připojení, kontrolujeme, že tento disk je stále v volumeResizeRequired a vracíme chybu;
  5. CSI ovladač se znovu pokouší provést operaci resize. Pokud je operace úspěšná, odstraníme disk z volumeResizeRequired;
  6. Jelikož identifikátor disku není přítomen v volumeResizeRequired, ControllerPublishVolume prochází úspěšně, disk se připojuje, pod se spouští.

Vše vypadá docela jednoduše, ale jako vždy jsou tu skryté úskalí. Zvětšení disků zajišťuje external-resizer, který v případě chyby při provádění operace používá frontu s exponenciálně se zvyšujícími časovými limity až 1000 sekund:

func DefaultControllerRateLimiter() RateLimiter {
  return NewMaxOfRateLimiter(
  NewItemExponentialFailureRateLimiter(5*time.Millisecond, 1000*time.Second),
  	// 10 qps, 100 velikost bucketu. Toto je pouze pro rychlost opakování a je to jen celkový faktor (ne na položku)
  &BucketRateLimiter{Limiter: rate.NewLimiter(rate.Limit(10), 100)},
  )
}

To může občas způsobit, že operace zvětšení disku se protahuje na více než 15 minut a tím dochází k nedostupnosti odpovídajícího podu.

Jedinou možností, která nám dostatečně snadno a bezbolestně umožnila snížit potenciální dobu prostojů, bylo použití naší verze external-resizer s maximálním limitem časového limitu na 5 sekund:

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

Nehodlali jsme urgentně iniciovat diskusi a patchovat external-resizer, protože offline resizing disků je atavismus, který brzy vymizí u všech poskytovatelů cloudu.

Jak začít používat?

Ovladač je podporován v Kubernetes verzi 1.15 a výše. Pro funkci ovladače musí být splněny následující požadavky:

  • Přepínač --allow-privileged nastaven na hodnotu true pro API server a kubelet;
  • Zapnuto --feature-gates=VolumeSnapshotDataSource=true,KubeletPluginsWatcher=true,CSINodeInfo=true,CSIDriverRegistry=true pro API server a kubelet;
  • Šíření montování (mount propagation) musí být povoleno v clusteru. Při použití Dockeru musí být démon nakonfigurován tak, aby bylo povoleno sdílené montování (shared mounts).

Všechny potřebné kroky pro samotnou instalaci jsou popsány v README. Instalace zahrnuje vytváření objektů v Kubernetes z manifestů.

Pro provoz ovladače budete potřebovat následující:

  • Uvedení identifikátoru adresáře v manifestu (folder-id) Yandex.Cloud (viz dokumentaci);
  • Pro interakci s API Yandex.Cloud v CSI ovladači se používá servisní účet. V manifestu Secret je třeba předat autorizované klíče od servisního účtu. V dokumentaci je popsáno, jak vytvořit servisní účet a získat klíče.

Obecně — zkuste, a budeme rádi za zpětnou vazbu a nové problémy, pokud narazíte na nějaké problémy!

Další podpora

Na závěr bychom rádi zdůraznili, že tento CSI ovladač jsme implementovali ne z velké touhy zabývat se vývojem aplikací v Go, ale z naléhavé potřeby uvnitř společnosti. Nepřijde nám rozumné udržovat vlastní implementaci, proto pokud Yandex projeví zájem a rozhodne se pokračovat v podpoře ovladače, rádi předáme repozitář do jejich správy.

Kromě toho má Yandex pravděpodobně ve spravovaném clusteru Kubernetes vlastní implementaci CSI ovladače, který lze vydat jako Open Source. Taková možnost se nám také jeví jako příznivá — komunita by mohla využívat osvědčený ovladač od poskytovatele služeb, nikoli od třetí strany.

P.S.

Přečtěte si také náš blog:

Zdroj: habr.com

Koupit spolehlivý hosting pro webové stránky s ochranou proti DDoS, VPS VDS servery 🔥 Koupit spolehlivý hosting pro webové stránky s ochranou proti DDoS, VPS VDS servery | ProHoster