Kubernetes are mai multe opțiuni pentru actualizarea resurselor: aplicați, editați, corectați și înlocuiți. Există confuzie cu privire la ceea ce face fiecare și când să le folosească. Să ne dăm seama.
Dacă kubectl patch
, care nu include comparația apply
и patch
. Acest articol va analiza diferitele opțiuni, precum și utilizarea corectă a fiecăreia.
În timpul ciclului de viață al unei resurse Kubernetes (serviciu, implementare, intrare etc.), uneori trebuie să modificați, să adăugați sau să eliminați unele proprietăți ale acestei resurse. De exemplu, adăugați o notă, măriți sau micșorați numărul de replici.
CLI Kubernetes
Dacă lucrați deja cu clustere Kubernetes prin intermediul CLI, sunteți deja familiarizat apply
и edit
. Echipă apply
citește specificația resursei din fișier și face un „upsert” către clusterul Kubernetes, de exemplu. creează resursa dacă nu există și o actualizează dacă există. Echipă edit
citește o resursă prin API, apoi scrie specificația resursei într-un fișier local, care este apoi deschis într-un editor de text. După ce editați și salvați fișierul, kubectl
va trimite înapoi modificările făcute prin API, care va aplica cu atenție aceste modificări resursei.
Nu toată lumea cunoaște comenzile patch
и replace
. Echipă patch
vă permite să modificați o parte a specificației unei resurse, oferind doar partea modificată pe linia de comandă. Echipă replace
functioneaza la fel ca edit
, dar totul trebuie făcut manual: trebuie să descărcați versiunea curentă a specificației resursei, de exemplu, folosind kubectl get -o yaml
, editați-l, apoi utilizați replace
pentru a actualiza o resursă conform unei specificații modificate. Echipă replace
nu va funcționa dacă au apărut modificări între citirea și înlocuirea resursei.
API Kubernetes
Probabil că sunteți familiarizat cu metodele CoreV1().Pods().Update()
, replaceNamespacedService
sau patch_namespaced_deployment
, dacă lucrați cu clustere prin PUT
и PATCH
... Unde update
и replace
utilizare PUT
Și patch
, oricât de banal ar fi, folosește PATCH
.
Ar trebui remarcat faptul că kubectl
funcționează și cu clustere prin API. Cu alte cuvinte, kubectl
este un înveliș în partea de sus a bibliotecii client pentru limbajul Go, care oferă în mare măsură capacitatea de a furniza subcomenzi într-o formă mai compactă și mai lizibilă, în plus față de capabilitățile standard API. De exemplu, după cum poate ați observat deja, metoda apply
nu a fost menționat mai sus în paragraful anterior. În prezent (mai 2020, aproximativ traducător) toată logica kubectl apply
, adică crearea de resurse inexistente și actualizarea celor existente, funcționează în întregime pe partea de cod kubectl
. Se fac eforturi apply
în partea API, dar este încă în versiune beta. Voi scrie mai detaliat mai jos.
Patch implicit
Cel mai bine folosit patch
, dacă doriți să actualizați resursa. Acesta este modul în care ambele biblioteci client funcționează pe deasupra API-ului Kubernetes și kubectl
(nu este surprinzător, deoarece este un înveliș pentru biblioteca client, aproximativ traducător).
Lucrați strategic
Toate echipele kubectl
apply
, edit
и patch
utilizați metoda PATCH
în solicitările HTTP pentru a actualiza o resursă existentă. Dacă vă aprofundați în implementarea comenzilor mai detaliat, atunci toate folosesc abordarea patch
poate folosi alte abordări (mai multe despre asta mai jos). Abordarea de corecție prin îmbinare strategică încearcă să „să facă corect” prin îmbinarea specificației furnizate cu specificația existentă. Mai precis, încearcă să combine atât obiectele, cât și matricele, ceea ce înseamnă că modificările tind să fie aditive. De exemplu, rularea comenzii patch
cu o nouă variabilă de mediu în specificația containerului pod, face ca acea variabilă de mediu să fie adăugată la variabilele de mediu existente, în loc să le suprascrie. Pentru a elimina folosind această abordare, trebuie să forțați valoarea parametrului să fie nulă în specificația furnizată. Care dintre echipe kubectl
Este cel mai bine să îl utilizați pentru actualizare?
Dacă vă creați și gestionați resursele folosind kubectl apply
, atunci când actualizați este mai bine să utilizați întotdeauna kubectl apply
La kubectl
ar putea gestiona configurația și urmări corect modificările solicitate de la aplicație la aplicație. Utilizați întotdeauna avantaj apply
este că ține evidența unei specificații aplicate anterior, permițându-i să știe când proprietățile specificației și elementele matricei sunt eliminate în mod explicit. Acest lucru vă permite să utilizați apply
pentru a elimina proprietăți și elemente de matrice, în timp ce o îmbinare strategică normală nu va funcționa. Echipe edit
и patch
nu actualizați notele că kubectl apply
folosește pentru a-și urmări modificările, deci orice modificări care sunt urmărite și făcute prin API-ul Kubernetes, dar făcute prin comenzi edit
и patch
, invizibil pentru comenzile ulterioare apply
care este apply
nu le elimină chiar dacă nu apar în specificația de intrare pt apply
(Documentația spune că edit
и patch
efectuați actualizări la notele utilizate apply
, dar în practică - nu).
Dacă nu utilizați comanda apply
, poate fi folosit ca edit
Și patch
, alegând comanda care se potrivește cel mai bine modificării efectuate. Când adăugați și modificați proprietățile BOM, ambele abordări sunt aproximativ aceleași. Când ștergeți proprietăți de specificație sau elemente de matrice edit
se comportă ca o lansare unică apply
, inclusiv urmărirea cum a fost specificația înainte și după ce a fost editată, astfel încât să puteți elimina în mod explicit proprietățile și elementele matricei dintr-o resursă. Trebuie să setați în mod explicit valoarea proprietății la null în specificația pentru patch
pentru a-l elimina din resursă. Eliminarea unui element de matrice folosind corecțiile strategic-merge este mai complexă, deoarece necesită utilizarea directivelor de îmbinare. Vedeți mai jos alte abordări de actualizare pentru alternative mai viabile.
Pentru a implementa metode de actualizare în biblioteca client care se comportă similar comenzilor de mai sus kubectl
, ar trebui să fie stabilit în cereri content-type
в application/strategic-merge-patch+json
. Dacă doriți să eliminați proprietăți dintr-o specificație, trebuie să setați în mod explicit valorile lor la nul într-un mod similar kubectl patch
. Dacă trebuie să eliminați elemente de matrice, ar trebui să includeți directive de îmbinare în specificația de actualizare sau să utilizați o abordare diferită a actualizărilor.
Alte abordări ale actualizărilor
Kubernetes acceptă alte două abordări de actualizare: kubectl patch --type=merge
. Când lucrați cu API-ul Kubernetes, ar trebui să utilizați metoda de solicitare PATCH
si instalare content-type
в application/merge-patch+json
.
Abordarea patch-ului JSON, în loc să ofere o specificație parțială a unei resurse, folosește furnizarea modificărilor pe care doriți să le faceți resursei ca o matrice, în care fiecare element al matricei reprezintă o descriere a modificării aduse resursei. Această abordare este o modalitate mai flexibilă și mai puternică de a exprima modificările efectuate, dar cu prețul listării modificărilor efectuate într-un format separat, non-Kubernetes, mai degrabă decât trimiterea unei specificații parțiale a resurselor. ÎN kubectl
puteți selecta patch-ul JSON folosind kubectl patch --type=json
. Când utilizați API-ul Kubernetes, această abordare funcționează folosind metoda de solicitare PATCH
si instalare content-type
в application/json-patch+json
.
Avem nevoie de încredere - folosiți înlocuiți
În unele cazuri, trebuie să vă asigurați că nu se fac modificări unei resurse între momentul citirii resursei și momentul actualizării acesteia. Cu alte cuvinte, ar trebui să vă asigurați că toate modificările vor fi atomic. În acest caz, pentru a actualiza resursele pe care ar trebui să le utilizați replace
. De exemplu, dacă aveți un ConfigMap cu un contor care este actualizat de mai multe surse, ar trebui să vă asigurați că două surse nu actualizează contorul în același timp, ceea ce duce la pierderea actualizării. Pentru a demonstra, imaginați-vă o secvență de evenimente folosind abordarea patch
:
- A și B obțin starea curentă a resursei din API
- Fiecare actualizează local specificația prin creșterea contorului cu unul și, de asemenea, adăugând „A” sau, respectiv, „B” la nota „actualizată de”
- Și actualizează resursa puțin mai repede
- B actualizează resursa
Ca urmare, actualizarea A este pierdută. Ultima operatie patch
câștigă, contorul este incrementat cu unu în loc de doi, iar valoarea notei „actualizate de” se termină cu „B” și nu conține „A”. Să comparăm cele de mai sus cu ceea ce se întâmplă atunci când actualizările se fac folosind abordarea replace
:
- A și B obțin starea curentă a resursei din API
- Fiecare actualizează local specificația prin creșterea contorului cu unul și, de asemenea, adăugând „A” sau, respectiv, „B” la nota „actualizată de”
- Și actualizează resursa puțin mai repede
- B încearcă să actualizeze resursa, dar actualizarea este respinsă de API deoarece versiunea resursei este în specificație
replace
nu se potrivește cu versiunea curentă a resursei din Kubernetes, deoarece versiunea resursei a fost mărită de operația de înlocuire a lui A.
În cazul de mai sus, B va trebui să preia din nou resursa, să facă modificări în noua stare și să încerce din nou replace
. Acest lucru va face ca contorul să fie incrementat cu două și nota „actualizată de” să includă „AB” la sfârșit.
Exemplul de mai sus implică faptul că atunci când se execută replace
Întreaga resursă este complet înlocuită. Specificația folosită pentru replace
, nu trebuie să fie parțial sau în părți ca în apply
, dar complet, inclusiv adaosul resourceVersion
în metadatele specificației. Dacă nu ați activat resourceVersion
sau versiunea pe care o furnizați nu este actuală, înlocuirea va fi respinsă. Deci cea mai bună abordare de utilizat este replace
– citiți resursa, actualizați-o și înlocuiți-o imediat. Folosind kubectl
, ar putea arăta astfel:
$ kubectl get deployment my-deployment -o json
| jq '.spec.template.spec.containers[0].env[1].value = "new value"'
| kubectl replace -f -
Este de remarcat faptul că următoarele două comenzi, executate secvenţial, se vor executa cu succes, deoarece deployment.yaml
nu contine proprietate .metadata.resourceVersion
$ kubectl create -f deployment.yaml
$ kubectl replace -f deployment.yaml
Acest lucru ar părea să contrazică ceea ce s-a spus mai sus, adică. „adăugând resourceVersion
în metadatele specificației." Este greșit să spui asta? Nu, nu este, pentru că dacă kubectl
observă că nu ai specificat resourceVersion
, o va citi din resursă și o va adăuga la specificația specificată de dvs. și abia apoi o va executa replace
. Deoarece acest lucru este potențial periculos dacă te bazezi pe atomicitate, magia funcționează în întregime în lateral kubectl
, nu ar trebui să vă bazați pe el atunci când utilizați biblioteci client care funcționează cu API. În acest caz, va trebui să citiți specificația curentă a resursei, să o actualizați și apoi să executați PUT
cerere.
Nu puteți face un patch - noi facem o înlocuire
Uneori trebuie să faceți unele modificări care nu pot fi gestionate de API. În aceste cazuri, puteți forța înlocuirea resursei prin ștergerea și recrearea acesteia. Acest lucru se face folosind kubectl replace --force
. Rularea comenzii elimină imediat resursele și apoi le recreează din specificația furnizată. Nu există un handler de „înlocuire forțată” în API și, pentru a face acest lucru prin API, trebuie să efectuați două operațiuni. Mai întâi trebuie să ștergeți resursa setând-o gracePeriodSeconds
la zero (0) și propagationPolicy
în „Background” și apoi re-creați această resursă cu specificația dorită.
Avertisment: Această abordare este potențial periculoasă și poate duce la o stare nedefinită.
Aplicați pe partea de server
După cum am menționat mai sus, dezvoltatorii Kubernetes lucrează la implementarea logicii apply
de kubectl
în API-ul Kubernetes. Logici apply
disponibil în Kubernetes 1.18 prin kubectl apply --server-side
sau prin API folosind metoda PATCH
с content-type
application/apply-patch+YAML
.
Notă: JSON este și YAML valid, așa că puteți trimite specificația ca JSON chiar dacă
content-type
voințăapplication/apply-patch+yaml
.
Pe langa aceasta logica kubectl
devine disponibil pentru toată lumea prin API, apply
pe partea de server, ține evidența cine este responsabil pentru câmpurile din specificație, permițând astfel acces multiplu securizat pentru editarea fără conflicte. Cu alte cuvinte, dacă apply
pe partea de server va deveni mai răspândită, va apărea o interfață universală de gestionare a resurselor securizate pentru diferiți clienți, de exemplu, kubectl, Pulumi sau Terraform, GitOps, precum și scripturi auto-scrise folosind biblioteci client.
Rezultatele
Sper că această scurtă prezentare generală a diferitelor modalități de actualizare a resurselor în clustere v-a fost de ajutor. Este bine să știți că nu este doar aplicați versus înlocuiți, este posibil să actualizați o resursă utilizând aplicați, editați, corectați sau înlocuiți. La urma urmei, în principiu, fiecare abordare are propriul său domeniu de aplicare. Pentru modificări atomice, este de preferat înlocuirea, în caz contrar, ar trebui să utilizați patch-ul de îmbinare strategică prin aplicare. Cel puțin, mă aștept să înțelegeți că nu puteți avea încredere în Google sau StackOerflow atunci când căutați „kubernetes apply vs replace”. Cel puțin până când acest articol înlocuiește răspunsul actual.
Sursa: www.habr.com