Třícestné sloučení do werf: nasazení do Kubernetes s Helmem „na steroidech“

Stalo se to, na co jsme (a nejen my) dlouho čekali: werf, náš Open Source nástroj pro vytváření aplikací a jejich dodávání do Kubernetes, nyní podporuje použití změn pomocí 3-way merge patchs! Kromě toho je možné převzít stávající prostředky K8 do verzí Helm, aniž by bylo nutné tyto prostředky znovu sestavovat.

Třícestné sloučení do werf: nasazení do Kubernetes s Helmem „na steroidech“

Pokud je to velmi krátké, pak dáme WERF_THREE_WAY_MERGE=enabled — dostaneme nasazení „jako v kubectl apply“, kompatibilní se stávajícími instalacemi Helm 2 a ještě o něco více.

Ale začněme teorií: co to vlastně jsou 3-way-merge patche, jak lidé přišli na přístup k jejich generování a proč jsou důležité v procesech CI/CD s infrastrukturou založenou na Kubernetes? A poté se podívejme, co je 3-way-merge ve werf, jaké režimy se používají ve výchozím nastavení a jak to spravovat.

Co je to 3-way-merge patch?

Začněme tedy úkolem zavádění prostředků popsaných v manifestech YAML do Kubernetes.

Pro práci se zdroji nabízí Kubernetes API následující základní operace: vytvoření, záplata, nahrazení a odstranění. Předpokládá se, že s jejich pomocí je nutné zkonstruovat pohodlné průběžné zavádění zdrojů do clusteru. Jak?

Imperativní příkazy kubectl

První přístup ke správě objektů v Kubernetes je použití imperativních příkazů kubectl k vytvoření, úpravě a odstranění těchto objektů. Jednoduše řečeno:

  • tým kubectl run můžete spustit Deployment nebo Job:
    kubectl run --generator=deployment/apps.v1 DEPLOYMENT_NAME --image=IMAGE
  • tým kubectl scale — změnit počet replik:
    kubectl scale --replicas=3 deployment/mysql
  • atd.

Tento přístup se může na první pohled zdát pohodlný. Existují však problémy:

  1. Je to těžké automatizovat.
  2. Jak odrážet konfiguraci v Gitu? Jak zkontrolovat změny, ke kterým dochází v clusteru?
  3. Jak zajistit reprodukovatelnost konfigurace při restartu?
  4. ...

Je jasné, že tento přístup se nehodí k ukládání aplikací a infrastruktury jako kódu (IaC; nebo dokonce GitOps jako modernější možnost, získávající na popularitě v ekosystému Kubernetes). Proto se tyto příkazy v kubectl nedočkaly dalšího rozvoje.

Vytváření, získávání, nahrazování a odstraňování operací

S primární tvorba je to jednoduché: pošlete manifest do operace create kube api a prostředek byl vytvořen. YAML reprezentace manifestu může být uložena v Gitu a vytvořena pomocí příkazu kubectl create -f manifest.yaml.

С odstranění také jednoduché: nahradit totéž manifest.yaml z Gitu do týmu kubectl delete -f manifest.yaml.

Operace replace umožňuje zcela nahradit konfiguraci zdroje novou, bez opětovného vytváření zdroje. To znamená, že před provedením změny zdroje je logické se pomocí operace zeptat na aktuální verzi get, změňte jej a aktualizujte pomocí operace replace. je zabudován kube apiserver optimistické zamykání a pokud po operaci get objekt se změnil, pak operace replace neprojde.

Chcete-li uložit konfiguraci v Gitu a aktualizovat ji pomocí funkce nahradit, musíte provést operaci get, sloučte konfiguraci z Gitu s tím, co jsme obdrželi, a spusťte replace. Ve výchozím nastavení vám kubectl umožňuje používat pouze příkaz kubectl replace -f manifest.yamlKde manifest.yaml — již plně připravený (v našem případě sloučený) manifest, který je třeba nainstalovat. Ukazuje se, že uživatel potřebuje implementovat slučovací manifesty, a to není triviální záležitost...

Za zmínku také stojí, že ačkoli manifest.yaml a je uložen v Gitu, nemůžeme předem vědět, zda je nutné objekt vytvořit nebo jej aktualizovat – to musí provést uživatelský software.

Celkem: můžeme vybudovat nepřetržité zavádění pouze pomocí vytvořit, nahradit a odstranit, což zajistí, že konfigurace infrastruktury bude uložena v Gitu spolu s kódem a pohodlným CI/CD?

V zásadě můžeme... Za tohle budete muset implementovat operaci sloučení manifesty a nějaký druh závaznosti, že:

  • kontroluje přítomnost objektu v clusteru,
  • provádí počáteční vytvoření zdroje,
  • aktualizuje nebo smaže.

Při aktualizaci mějte na paměti, že zdroj se mohl změnit od minula get a automaticky řešit případ optimistického zamykání - provádějte opakované pokusy o aktualizaci.

Proč však znovu vynalézat kolo, když kube-apiserver nabízí jiný způsob aktualizace zdrojů: operaci patch, která uživatele zbaví některých popsaných problémů?

Náplast

Nyní se dostáváme k patchům.

Opravy jsou primárním způsobem, jak aplikovat změny na existující objekty v Kubernetes. Úkon patch funguje to takto:

  • uživatel kube-apiserver musí odeslat opravu ve formátu JSON a specifikovat objekt,
  • a apiserver se sám vypořádá s aktuálním stavem objektu a dovede jej do požadované podoby.

Optimistické zamykání není v tomto případě nutné. Tato operace je spíše deklarativní než nahrazení, i když se to na první pohled může zdát naopak.

РўР ° РєРёРј РsР ° ЂјЂ:

  • pomocí operace create vytvoříme objekt podle manifestu z Gitu,
  • přes delete — smazat, pokud objekt již není potřeba,
  • přes patch — změníme objekt a uvedeme jej do podoby popsané v Git.

K tomu však musíte vytvořit správný patch!

Jak fungují záplaty v Helm 2: 2-way-merge

Když poprvé nainstalujete vydání, Helm provede operaci create pro zdroje grafů.

Při aktualizaci vydání Helm pro každý zdroj:

  • zvažuje opravu mezi verzí zdroje z předchozího grafu a aktuální verzí grafu,
  • aplikuje tento patch.

Budeme tomu říkat patch 2-way merge patch, protože na jeho tvorbě se podílejí 2 manifesty:

  • manifest zdroje z předchozího vydání,
  • manifest zdroje z aktuálního zdroje.

Při odstraňování provozu delete v kube je apiserver volán pro prostředky, které byly deklarovány v předchozí verzi, ale nebyly deklarovány v aktuální verzi.

Přístup 2-way merge patch má problém: vede k není synchronizován se skutečným stavem prostředku v clusteru a manifestem v Gitu.

Ilustrace problému s příkladem

  • V Gitu je v grafu uložen manifest, ve kterém je pole image Na nasazení záleží ubuntu:18.04.
  • Uživatel přes kubectl edit změnil hodnotu tohoto pole na ubuntu:19.04.
  • Při opětovném nasazení grafu Helm nevygeneruje záplatu, protože pole image v předchozí verzi vydání a v aktuální tabulce jsou stejné.
  • Po opětovném nasazení image zbytky ubuntu:19.04, i když graf říká ubuntu:18.04.

Dostali jsme desynchronizaci a ztratili jsme deklarativnost.

Co je synchronizovaný zdroj?

Obecně řečeno, plný Je nemožné získat shodu mezi manifestem prostředku v běžícím clusteru a manifestem z Gitu. Protože ve skutečném manifestu mohou být anotace/štítky služeb, další kontejnery a další data, která jsou dynamicky přidávána a odebírána ze zdroje některými řadiči. Tato data nemůžeme a nechceme uchovávat v Gitu. Chceme však, aby pole, která jsme explicitně specifikovali v Gitu, nabyla po zavedení příslušné hodnoty.

Ukazuje se to tak obecně pravidlo synchronizovaného zdroje: při zavádění zdroje můžete změnit nebo odstranit pouze ta pole, která jsou explicitně specifikována v manifestu z Git (nebo byla zadána v předchozí verzi a nyní jsou odstraněna).

3-way merge patch

ústřední myšlenkou 3-way merge patch: vygeneruje opravu mezi poslední použitou verzí manifestu z Git a cílovou verzí manifestu z Gitu s přihlédnutím k aktuální verzi manifestu z běžícího clusteru. Výsledná oprava musí vyhovovat pravidlu synchronizovaného zdroje:

  • nová pole přidaná do cílové verze jsou přidána pomocí opravy;
  • dříve existující pole v poslední použité verzi a neexistující v cílové verzi jsou resetována pomocí opravy;
  • pole v aktuální verzi objektu, která se liší od cílové verze manifestu, jsou aktualizována pomocí opravy.

Právě na tomto principu generuje záplaty kubectl apply:

  • poslední použitá verze manifestu je uložena v anotaci samotného objektu,
  • cíl - převzato ze zadaného souboru YAML,
  • aktuální je z běžícího clusteru.

Nyní, když jsme vyřešili teorii, je čas vám říci, co jsme dělali ve werfu.

Aplikace změn na werf

Dříve werf, stejně jako Helm 2, používal 2-way-merge patche.

Oprava opravy

Abychom mohli přejít na nový typ záplat - 3-way-merge - prvním krokem jsme zavedli tzv. opravné záplaty.

Při nasazení se používá standardní 2-way-merge patch, ale werf navíc generuje patch, který by synchronizoval skutečný stav zdroje s tím, co je napsáno v Gitu (taková oprava je vytvořena pomocí stejného synchronizovaného pravidla pro zdroje popsaného výše) .

Pokud dojde k desynchronizaci, na konci nasazení uživatel obdrží VAROVÁNÍ s odpovídající zprávou a opravou, kterou je třeba použít, aby se zdroj dostal do synchronizované podoby. Tento patch je také zaznamenán ve speciální anotaci werf.io/repair-patch. Předpokládá se, že ruce uživatele sám použije tuto opravu: werf ji nepoužije vůbec.

Generování opravných oprav je dočasné opatření, které vám umožňuje skutečně otestovat vytváření oprav na principu 3-way-merge, ale tyto opravy automaticky neaplikovat. V tuto chvíli je tento provozní režim standardně povolen.

Oprava 3-way sloučení pouze pro nová vydání

Od 1. prosince 2019 začínají beta a alfa verze werf ve výchozím nastavení použijte plnohodnotné 3-way-merge patche k aplikování změn pouze na nová vydání Helm zavedená přes werf. Stávající verze budou i nadále používat přístup 2-way-merge + repair patches.

Tento provozní režim lze explicitně aktivovat nastavením WERF_THREE_WAY_MERGE_MODE=onlyNewReleases Nyní.

Poznámka: funkce se objevila ve werf během několika vydání: v alfa kanálu byla připravena s verzí v1.0.5-alpha.19a v beta kanálu - s v1.0.4-beta.20.

3-way-merge patch pro všechna vydání

Počínaje 15. prosincem 2019 začnou beta a alfa verze werf ve výchozím nastavení používat plné záplaty 3-way-merge, aby se změny aplikovaly na všechna vydání.

Tento provozní režim lze explicitně aktivovat nastavením WERF_THREE_WAY_MERGE_MODE=enabled Nyní.

Co dělat s automatickým škálováním zdrojů?

V Kubernetes existují 2 typy automatického škálování: HPA (horizontální) a VPA (vertikální).

Horizontální automaticky vybere počet replik, vertikální - počet zdrojů. Počet replik i požadavky na prostředky jsou uvedeny v manifestu prostředku (viz Manifest prostředků). spec.replicas nebo spec.containers[].resources.limits.cpu, spec.containers[].resources.limits.memory и ostatní).

Problém: Pokud uživatel nakonfiguruje zdroj v grafu tak, aby specifikoval určité hodnoty pro zdroje nebo repliky a pro tento zdroj jsou povoleny automatické škálování, pak při každém nasazení werf tyto hodnoty resetuje na to, co je napsáno v manifestu grafu. .

Existují dvě řešení problému. Pro začátek je nejlepší vyhnout se explicitnímu zadání automaticky škálovaných hodnot v manifestu grafu. Pokud tato možnost není z nějakého důvodu vhodná (například proto, že je vhodné nastavit počáteční limity zdrojů a počet replik v grafu), pak werf nabízí následující anotace:

  • werf.io/set-replicas-only-on-creation=true
  • werf.io/set-resources-only-on-creation=true

Pokud je taková anotace přítomna, werf neresetuje odpovídající hodnoty při každém nasazení, ale nastaví je pouze při prvotním vytvoření prostředku.

Další podrobnosti naleznete v projektové dokumentaci k HPA и VPA.

Zakažte použití 3-cestné slučovací opravy

Uživatel může aktuálně zakázat používání nových záplat ve werf pomocí proměnné prostředí WERF_THREE_WAY_MERGE_MODE=disabled. Nicméně počínaje Od 1. března 2020 tento zákaz již nebude platit. a bude možné používat pouze 3-way-merge patche.

Přijetí zdrojů ve werf

Zvládnutí metody aplikace změn pomocí 3-way-merge patchů nám umožnilo okamžitě implementovat takovou funkci, jako je převzetí zdrojů existujících v clusteru do verze Helm.

Helm 2 má problém: nemůžete přidat prostředek do manifestů grafu, který již v clusteru existuje, aniž byste tento prostředek znovu vytvořili od začátku (viz. #6031, #3275). Naučili jsme werf přijímat existující zdroje k vydání. Chcete-li to provést, musíte nainstalovat anotaci na aktuální verzi prostředku z běžícího clusteru (například pomocí kubectl edit):

"werf.io/allow-adoption-by-release": RELEASE_NAME

Nyní je třeba zdroj popsat v grafu a až werf příště nasadí vydání s příslušným názvem, existující prostředek bude přijat do tohoto vydání a zůstane pod jeho kontrolou. Kromě toho v procesu přijímání prostředku k vydání werf převede aktuální stav prostředku z běžícího clusteru do stavu popsaného v grafu pomocí stejných 3-cestných záplat a pravidla synchronizovaného prostředku.

Poznámka: nastavení WERF_THREE_WAY_MERGE_MODE neovlivňuje adopci zdrojů - v případě adopce se vždy použije 3-way-merge patch.

Podrobnosti - v dokumentace.

Závěry a plány do budoucna

Doufám, že po tomto článku je jasnější, co jsou 3-way-merge patche a proč k nim přišly. Z praktického hlediska vývoje projektu werf byla jejich implementace dalším krokem ke zlepšení nasazení ve stylu Helm. Nyní můžete zapomenout na problémy se synchronizací konfigurace, které často vznikaly při používání Helm 2. Zároveň byla do vydání Helm přidána nová užitečná funkce přebírání již stažených zdrojů Kubernetes.

Stále existují určité problémy a problémy s nasazením podobným Helm, jako je použití šablon Go, které budeme nadále řešit.

Informace o metodách aktualizace zdrojů a jejich přijetí lze také nalézt na adrese tuto stránku dokumentace.

Helma 3

Hodné zvláštní poznámky propuštěn právě nedávno nová hlavní verze Helmu - v3 - která také používá 3-way-merge patche a zbavuje se Tillera. Nová verze Helmu vyžaduje migrace stávající instalace a převést je do formátu úložiště nového vydání.

Werf se aktuálně zbavil používání Tilleru, přešel na 3-way-merge a přidal mnohem více, přičemž zůstává kompatibilní se stávajícími instalacemi Helm 2 (nemusí být spouštěny žádné migrační skripty). Dokud tedy werf nepřejde na Helm 3, uživatelé werf neztrácejí hlavní výhody Helmu 3 oproti Helmu 2 (werf je také má).

Přechod werf na kódovou základnu Helm 3 je však nevyhnutelný a dojde k němu v blízké budoucnosti. Pravděpodobně to bude werf 1.1 nebo werf 1.2 (v tuto chvíli je hlavní verzí werf 1.0; více informací o zařízení pro verzování werf viz zde). Během této doby bude mít Helm 3 čas se stabilizovat.

PS

Přečtěte si také na našem blogu:

Zdroj: www.habr.com

Přidat komentář