Existuje niekoľko možností, ako aktualizovať zdroje v Kubernetes: apply, edit, patch a replace. Medzi tým, čo každý z nich robí a kedy ich použiť, je dosť zmätku. Poďme si to objasniť.

Ak frázu "kubernetes apply vs replace", nájde , ktorá nie je správna. "kubernetes apply vs patch" prvý odkaz — dokumentácia na kubectl patch, ktorá neobsahuje porovnanie apply a patch. V tomto článku sa pozrieme na rôzne možnosti, ako aj na správne použitie každého z nich.
Počas životného cyklu zdroja v Kubernetes (služby, deployment, ingress a pod.) je občas potrebné zmeniť, pridať alebo odstrániť niektoré vlastnosti tohto zdroja. Napríklad, pridať poznámku, zvýšiť alebo znížiť počet replik.
Kubernetes CLI
Ak už pracujete s klastrami Kubernetes cez CLI, potom ste už oboznámení s apply a edit. Príkaz apply ktorý číta špecifikáciu zdroja z súboru a vykonáva "upsert" do klastru Kubernetes, t.j. vytvára zdroj, ak neexistuje, a aktualizuje ho, ak už existuje. Príkaz edit číta zdroj cez API, potom zapisuje špecifikáciu zdroja do lokálneho súboru, ktorý sa následne otvorí v textovom editore. Po tom, čo súbor upravíte a uložíte, kubectl odosiela vykonané zmeny späť cez API, ktoré starostlivo aplikuje tieto zmeny na zdroj.
Nie všetci poznajú príkazy patch a replace. Príkaz patch ktorý umožňuje zmeniť časť špecifikácie zdroja, pričom v príkazovom riadku poskytujete iba zmenenú časť. Príkaz replace funguje rovnako ako edit, ale všetko sa musí urobiť ručne: je potrebné stiahnuť aktuálnu verziu špecifikácie zdroja, napríklad pomocou kubectl get -o yaml, upraviť ju a potom použiť replace na aktualizáciu zdroja podľa zmenenej špecifikácie. Príkaz replace nepôjde, ak medzi čítaním a nahradením zdroja došlo k nejakým zmenám.
Kubernetes API
Určite ste oboznámení s metódami CoreV1().Pods().Update(), replaceNamespacedService alebo patch_namespaced_deployment, ak pracujete s klastrami cez použitím niektorého programovacieho jazyka. Knižnica spracováva tieto metódy pomocou požiadaviek cez protokol HTTP, používajúc metódy PUT a PATCH. Pri tom update a replace používajú PUT, a patch, akokoľvek to môže znieť banálne, používa PATCH.
Stojí za zmienku, že kubectl tiež pracuje s klastrami cez API. Inými slovami, kubectl– je obal pre klientskú knižnicu pre jazyk Go, ktorá vo veľkej miere poskytuje možnosť prezentovať podpríkazy v kompaktnejšej a čitateľnejšej podobe ako doplnok k štandardným schopnostiam API. Napríklad, ako ste si už mohli všimnúť, metóda apply nebola spomenutá vyššie v predchádzajúcom odseku. V súčasnosti (máj 2020, pozn. prekladateľa) celá logika kubectl apply, t.j. vytváranie neexistujúcich zdrojov a aktualizácia existujúcich, funguje úplne na strane kódu kubectl. Podnikajú sa kroky apply na stranu API, ale to je stále vo fáze beta testovania. Podrobne vysvetlím nižšie.
Patch predvolene
Najlepšie sa aplikuje patch, ak chcete aktualizovať zdroj. Takto fungujú ako klientské knižnice nad API Kubernetes, tak aj kubectl (nie je prekvapením, veď je to obal klientskej knižnice, pozn. prekladateľa).
Pracovať strategicky
Všetky príkazy kubectl apply, edit a patch využívajú metódu PATCH v HTTP požiadavkách na aktualizáciu existujúceho zdroja. Ak sa podrobnejšie zaoberáme realizáciou príkazov, vo všetkých sa používa prístup na aktualizáciu zdrojov, hoci príkaz patch môže používať aj iné prístupy (viac o tom nižšie). Prístup strategic-merge patching sa snaží "robiť všetko správne" pri zlúčení poskytnutej špecifikácie s existujúcou špecifikáciou. Presnejšie povedané, snaží sa zlúčiť ako objekty, tak aj polia, čo znamená, že zmeny sú zvyčajne aditívne. Napríklad spustenie príkazu patch s novou premennou prostredia v špecifikácii kontajnera pod vedie k tomu, že táto premenná prostredia sa pridáva k existujúcim premenným prostredia, a nie ich prepíše. Na odstránenie pomocou tohto prístupu je potrebné núdzovo nastaviť hodnotu parametra na null v poskytnutej špecifikácii. Ktoré z príkazov kubectl pre aktualizáciu sú najlepšie na použitie?
Ak vytvárate a spravujete svoje zdroje pomocou kubectl apply, pri aktualizácii je vždy lepšie používať kubectl apply, aby kubectl mohol spravovať konfiguráciu a správne sledovať požadované zmeny od aplikovania po aplikovanie. Výhodou vždy používať apply je, že sleduje predtým aplikovanú špecifikáciu, čo mu umožňuje vedieť, keď sú vlastnosti špecifikácie a prvky poľa jasne odstránené. To umožňuje používať apply na odstránenie vlastností a prvkov poľa, pričom bežný strategický spôsob zlúčenia nebude fungovať. Príkazy edit a patch neaktualizujú poznámky, ktoré kubectl apply používa na sledovanie svojich zmien, preto akékoľvek zmeny, ktoré sa sledujú a robia prostredníctvom API Kubernetes, ale uskutočňované príkazmi edit a patch, sú neviditeľné pre nasledujúce príkazy apply, t.j. apply neodstraňuje ich, aj keď sa nezobrazujú vo vstupnej špecifikácii pre apply (V dokumentácii je uvedené, že edit a patch robia aktualizácie poznámok, používaných apply, ale v praxi - nie).
Ak nepoužívate príkaz apply, možno ho použiť ako edit, tak aj patch, pričom zvolíte ten príkaz, ktorý najlepšie vyhovuje vykonávané zmene. Pri pridávaní a zmene vlastností špecifikácie sú obe prístupy zhruba rovnaké. Pri odstraňovaní vlastností špecifikácie alebo prvkov poľa edit sa správa ako jednorazový beh apply, vrátane sledovania, aká bola špecifikácia pred a po úprave, takže môžete explicitne odstrániť vlastnosti a prvky poľa z zdroja. Je potrebné explicitne nastaviť hodnotu vlastnosti na null v špecifikácii pre patch, aby ste jej odstránili zo zdroja. Odstránenie prvku poľa pomocou strategického zlúčenia je zložitejšie, pretože si vyžaduje použitie direktív zlúčenia. Pozrite si ďalšie prístupy k aktualizáciám nižšie, aby ste si vybrali prijateľnejšie alternatívy.
Aby sa v klientskej knižnici implementovali metódy aktualizácie, ktoré sa správajú podobne ako vyššie uvedené príkazy kubectl, mali by ste v požiadavkách nastaviť content-type v application/strategic-merge-patch+json. Ak chcete odstrániť vlastnosti v špecifikácii, musíte ich hodnoty explicitne nastaviť na null podobne ako kubectl patch. Ak potrebujete odstraňovať prvky poľa, mali by ste zahrnúť direktívy zlúčenia do špecifikácie aktualizácie alebo použiť iný prístup k aktualizáciám.
Iné prístupy k aktualizáciám
V Kubernetes sú podporované dva ďalšie prístupy k aktualizáciám: a . Prístup JSON merge patch prijíma čiastočnú špecifikáciu Kubernetes ako vstup a podporuje zlúčenie objektov podobne ako prístup strategic-merge patching. Rozdiel medzi nimi spočíva v tom, že podporuje iba nahradenie polí, vrátane poľa kontajnerov v špecifikácii pod. To znamená, že pri používaní JSON merge patch musíte poskytnúť úplné špecifikácie pre všetky kontajnery v prípade zmeny akéhokoľvek vlastnosti akéhokoľvek kontajnera. Týmto spôsobom je tento prístup užitočný na odstránenie prvkov z poľa v špecifikácii. V príkazovom riadku môžete vybrať JSON merge patch pomocou kubectl patch --type=merge. Pri práci s API Kubernetes by sa mal používať spôsob požiadavky PATCH a nastavení content-type v application/merge-patch+json.
Prístup JSON patch namiesto poskytovania čiastočnej špecifikácie zdroja používa poskytovanie zmien, ktoré chcete vykonať na zdroji, vo forme poľa, kde každý prvok poľa predstavuje popis zmeny, ktorá sa vykonáva na zdroji. Tento prístup je flexibilnejší a silnejší spôsob vyjadrenia vykonaných zmien, ale na úkor toho, že zoznam vykonaných zmien ide v samostatnom, nie Kubernetes formáte, namiesto zaslania čiastočnej špecifikácie zdroja. V kubectl môžete vybrať JSON patch pomocou kubectl patch --type=json. Pri použití API Kubernetes tento prístup funguje s použitím spôsobu požiadavky PATCH a nastavení content-type v application/json-patch+json.
Potrebujete istotu — používame replace
V niektorých prípadoch je potrebná istota, že do zdroja nebudú vykonané zmeny medzi časom čítania zdroja a jeho aktualizáciou. Inými slovami, je potrebné sa uistiť, že všetky zmeny budú atomárne. V tomto prípade by sa na aktualizáciu zdrojov mal používať replace. Napríklad, ak existuje ConfigMap s čítačom, ktorý sa aktualizuje viacerými zdrojmi, je potrebné sa uistiť, že dva zdroje nebudú aktualizovať čítač súčasne, čo by viedlo k strate aktualizácie. Na demonštráciu si predstavte sekvenciu udalostí, pri ktorej prístup patch:
- A a B získavajú aktuálny stav zdroja z API
- Každý z nich lokálne aktualizuje špecifikáciu, zvyšuje čítač o jednotku a zároveň pridáva 'A' alebo 'B' do poznámky 'updated-by'
- A o niečo rýchlejšie aktualizuje zdroj
- B aktualizuje zdroj
V dôsledku toho bolo aktualizovanie A stratené. Posledná operácia patch vyhráva, čítač sa zvyšuje o jednu, namiesto dvoch, a hodnota poznámky "updated-by" končí na "B" a neobsahuje "A". Porovnajme vyššie uvedené s tým, čo sa deje, keď sa aktualizácie vykonávajú pomocou prístupu replace:
- A a B získavajú aktuálny stav zdroja z API
- Každý z nich lokálne aktualizuje špecifikáciu, zvyšuje čítač o jednotku a zároveň pridáva 'A' alebo 'B' do poznámky 'updated-by'
- A o niečo rýchlejšie aktualizuje zdroj
- B sa pokúša aktualizovať zdroj, ale aktualizácia je zamietnutá API, pretože verzia zdroja v špecifikácii
replacesa nezhoduje s aktuálnou verziou zdroja v Kubernetes, pretože verzia zdroja bola zvýšená pri vykonávaní operácie replace na strane A.
V uvedenom prípade bude musieť B znova načítať zdroj, vykonať zmeny na novom stave a pokúsiť sa to urobiť znova. replaceV dôsledku toho sa čítač zvýši o dva a poznámka "updated-by" bude obsahovať "AB" na konci.
Vyššie uvedený príklad predpokladá, že pri vykonávaní replace prebieha úplná výmena celého zdroja. Špecifikácia použitá pre replacemusí byť kompletná, nie čiastočná alebo rozdelená ako v apply, vrátane pridania resourceVersion do metadát špecifikácie. Ak ste nezahrnuli resourceVersion alebo poskytnutá verzia nie je aktuálna, výmena bude zamietnutá. Takže najlepší prístup je replace načítať zdroj, aktualizovať ho a ihneď nahradiť. Použitím kubectlto môže vyzerať takto:
$ kubectl get deployment my-deployment -o json
| jq '.spec.template.spec.containers[0].env[1].value = "new value"'
| kubectl replace -f -Pri tom stojí za zmienku, že nasledujúce dve príkazy vykonané po sebe budú úspešné, pretože deployment.yaml neobsahuje vlastnosť .metadata.resourceVersion
$ kubectl create -f deployment.yaml
$ kubectl replace -f deployment.yamlZdalo by sa, že to je v rozpore s tým, čo bolo povedané vyššie, t.j. "pridanie resourceVersion do metadát špecifikácie". Je tvrdiť to nesprávne? Nie, nie je, pretože ak kubectl zaregistruje, že ste nenapísali resourceVersion, načíta ju zo zdroja a pridá do vami uvedenej špecifikácie a až potom vykoná replacežiadosti. Pretože toto je potenciálne nebezpečné, ak sa spoliehate na atomickosť, táto mágia funguje úplne na strane kubectl, netreba sa na ňu spoliehať pri používaní klientskych knižníc pracujúcich s API. V takomto prípade musíte načítať aktuálnu špecifikáciu zdroja, aktualizovať ju a potom vykonať PUT žiadosť.
Nie je možné vykonať patch – vykonáme replace
Niekedy je potrebné vykonať niektoré zmeny, ktoré nemôžu byť spracované API. V týchto prípadoch je možné nútene nahradiť zdroj jeho odstránením a opätovným vytvorením. To sa robí pomocou kubectl replace --force. Spustenie príkazu okamžite odstráni zdroje a potom ich znovu vytvorí podľa zadaných špecifikácií. V API nie je spracovateľ „nútenej náhrady“, a aby sa to dalo vykonať prostredníctvom API, je potrebné vykonať dve operácie. Najprv je potrebné odstrániť zdroj a nastaviť preň gracePeriodSeconds na nulu (0) a propagationPolicy na „Background“, a potom znova vytvoriť tento zdroj s požadovanou špecifikáciou.
Pozor: tento prístup je potenciálne nebezpečný a môže viesť k neurčitému stavu
Apply na strane servera
Ako už bolo spomenuté, vývojári Kubernetes pracujú na implementácii logiky apply z kubectl v API Kubernetes. Logika apply je dostupná v Kubernetes 1.18 prostredníctvom kubectl apply --server-side alebo prostredníctvom API pomocou metódy PATCH s content-type application/apply-patch+YAML.
Poznámka: JSON je tiež platný YAML, takže je možné poslať špecifikáciu vo formáte JSON, aj keď
content-typebudeapplication/apply-patch+yaml.
Okrem toho, že logika kubectl sa stáva dostupnou pre všetkých prostredníctvom API, apply na strane servera sleduje zodpovedné za polia v špecifikácii, čím umožňuje bezpečný viacnásobný prístup na jej bezkonfliktné úpravy. Inými slovami, ak apply na strane servera získa širšie rozšírenie, objaví sa univerzálne bezpečné rozhranie na správu zdrojov pre rôznych klientov, ako napríklad kubectl, Pulumi alebo Terraform, GitOps a tiež vlastné skripty používajúce klientské knižnice.
Zhrnutie
Dúfam, že tento krátky prehľad rôznych spôsobov aktualizácie zdrojov v klastri bol pre vás užitočný. Je dobré vedieť, že nie je iba „apply“ proti „replace“, pretože je možné aktualizovať zdroj pomocou apply, edit, patch alebo replace. Každý prístup má svoj vlastný účel. Pre atómové zmeny je preferovanejší replace, v opačnom prípade by ste mali použiť strategický merge patch cez apply. V poslednom prípade dúfam, že ste pochopili, že nemôžete dôverovať Google alebo StackOverflow pri hľadaní „kubernetes apply vs replace“. Aspoň pokiaľ táto článok nenahradí súčasnú odpoveď.

Zdroj: habr.com
