Trosmjerno spajanje na werf: implementacija na Kubernetes s Helmom "na steroidima"

Desilo se ono što smo (i ne samo mi) dugo čekali: werf, naš uslužni program otvorenog koda za izradu aplikacija i njihovu isporuku Kubernetesu, sada podržava primjenu promjena pomoću trosmjernih zakrpa za spajanje! Uz to, moguće je usvojiti postojeće K3s resurse u izdanja Helma bez ponovne izgradnje ovih resursa.

Trosmjerno spajanje na werf: implementacija na Kubernetes s Helmom "na steroidima"

Ako je vrlo kratko, onda stavljamo WERF_THREE_WAY_MERGE=enabled — dobivamo raspoređivanje “kao u kubectl apply", kompatibilan s postojećim Helm 2 instalacijama i još malo više.

Ali počnimo s teorijom: što su točno zakrpe za trostruko spajanje, kako su ljudi došli do pristupa njihovom generiranju i zašto su važni u CI/CD procesima s infrastrukturom temeljenom na Kubernetesu? A nakon toga, da vidimo što je 3-way-merge u werf-u, koji se načini koriste prema zadanim postavkama i kako njime upravljati.

Što je trosmjerna zakrpa spajanja?

Dakle, počnimo sa zadatkom uvođenja resursa opisanih u YAML manifestima u Kubernetes.

Za rad s resursima, Kubernetes API nudi sljedeće osnovne operacije: stvaranje, zakrpa, zamjena i brisanje. Pretpostavlja se da je uz njihovu pomoć potrebno konstruirati pogodan kontinuirani prijenos resursa u klaster. Kako?

kubectl imperativne naredbe

Prvi pristup upravljanju objektima u Kubernetesu je korištenje imperativnih naredbi kubectl za stvaranje, modificiranje i brisanje tih objekata. Jednostavno rečeno:

  • Tim kubectl run možete pokrenuti implementaciju ili posao:
    kubectl run --generator=deployment/apps.v1 DEPLOYMENT_NAME --image=IMAGE
  • Tim kubectl scale — promijeniti broj replika:
    kubectl scale --replicas=3 deployment/mysql
  • itd.

Ovaj pristup se na prvi pogled može činiti prikladnim. Međutim, postoje problemi:

  1. Teško automatizirati.
  2. Kao odražavaju konfiguraciju u Gitu? Kako pregledati promjene koje se događaju u klasteru?
  3. Kako osigurati ponovljivost konfiguracije pri ponovnom pokretanju?
  4. ...

Jasno je da se ovaj pristup ne uklapa dobro s pohranjivanjem aplikacije i infrastrukture kao koda (IaC; ili čak GitOps kao modernija opcija koja stječe popularnost u ekosustavu Kubernetes). Stoga ove naredbe nisu dobile daljnji razvoj u kubectl.

Operacije stvaranja, dobivanja, zamjene i brisanja

S primarnim stvaranje jednostavno je: pošaljite manifest operaciji create kube api i resurs je stvoren. YAML prikaz manifesta može se pohraniti u Git i kreirati pomoću naredbe kubectl create -f manifest.yaml.

С uklanjanje također jednostavno: zamijeniti isto manifest.yaml od Gita do tima kubectl delete -f manifest.yaml.

Operacija replace omogućuje potpunu zamjenu konfiguracije resursa novom, bez ponovnog stvaranja resursa. To znači da je prije promjene resursa logično izvršiti upit o trenutnoj verziji s operacijom get, promijenite ga i ažurirajte operacijom replace. ugrađen je kube apiserver optimistično zaključavanje i, ako nakon operacije get promijenio se objekt, zatim operacija replace neće uspjeti.

Da biste pohranili konfiguraciju u Git i ažurirali je pomoću zamjene, morate izvršiti operaciju get, spojiti konfiguraciju iz Gita s onim što smo primili i izvršiti replace. Prema zadanim postavkama kubectl dopušta samo korištenje naredbe kubectl replace -f manifest.yamlGdje manifest.yaml — već potpuno pripremljen (u našem slučaju spojeni) manifest koji je potrebno instalirati. Ispada da korisnik treba implementirati manifeste spajanja, a to nije trivijalna stvar...

Također je vrijedno napomenuti da iako manifest.yaml i pohranjen je u Gitu, ne možemo unaprijed znati je li potrebno kreirati objekt ili ga ažurirati - to mora učiniti korisnički softver.

Ukupno: možemo li izgraditi kontinuirano uvođenje samo koristeći stvaranje, zamjenu i brisanje, osiguravajući da je konfiguracija infrastrukture pohranjena u Gitu zajedno s kodom i praktičnim CI/CD-om?

U principu možemo... Za ovo morat ćete implementirati operaciju spajanja manifesti i neka vrsta obvezivanja koja:

  • provjerava prisutnost objekta u klasteru,
  • izvodi početno stvaranje resursa,
  • ažurira ili briše.

Prilikom ažuriranja imajte na umu da resurs se možda promijenio od zadnjeg get i automatski obrađuje slučaj optimističnog zaključavanja - ponovite pokušaje ažuriranja.

Međutim, zašto ponovno izmišljati kotač kada kube-apiserver nudi još jedan način ažuriranja resursa: operaciju patch, što korisnika oslobađa nekih od opisanih problema?

Patch

Sada dolazimo do zakrpa.

Zakrpe su primarni način primjene promjena na postojeće objekte u Kubernetesu. Operacija patch radi ovako:

  • korisnik kube-apiservera treba poslati zakrpu u JSON obliku i navesti objekt,
  • a apiserver će se sam pozabaviti trenutnim stanjem objekta i dovesti ga u traženi oblik.

Optimističko zaključavanje u ovom slučaju nije potrebno. Ova operacija je više deklarativna nego zamjena, iako se na početku može činiti obrnuto.

Na ovaj način:

  • pomoću operacije create kreiramo objekt prema manifestu iz Gita,
  • uz pomoć delete — izbrisati ako objekt više nije potreban,
  • uz pomoć patch — mijenjamo objekt, dovodeći ga u oblik opisan u Gitu.

Međutim, da biste to učinili, morate stvoriti ispravan patch!

Kako zakrpe rade u Helmu 2: 2-way-merge

Kada prvi put instalirate izdanje, Helm izvodi operaciju create za resurse grafikona.

Prilikom ažuriranja Helm izdanja za svaki resurs:

  • razmatra zakrpu između verzije resursa iz prethodnog grafikona i trenutne verzije grafikona,
  • primjenjuje ovu zakrpu.

Nazvat ćemo ovu zakrpu 2-smjerna zakrpa spajanja, jer su u njegovom stvaranju uključena 2 manifesta:

  • manifest resursa iz prethodnog izdanja,
  • manifest resursa iz trenutnog resursa.

Prilikom uklanjanja operacije delete u kube apiserver se poziva za resurse koji su deklarirani u prethodnom izdanju, ali nisu deklarirani u trenutnom.

Dvosmjerni pristup zakrpi spajanja ima problem: vodi do nije usklađen sa stvarnim stanjem resursa u klasteru i manifestom u Gitu.

Ilustracija problema s primjerom

  • U Gitu grafikon pohranjuje manifest u kojem polje image Implementacija je važna ubuntu:18.04.
  • Korisnik putem kubectl edit promijenio vrijednost ovog polja u ubuntu:19.04.
  • Prilikom ponovnog postavljanja Helm karte ne stvara zakrpu, jer polje image u prethodnoj verziji izdanja iu trenutnom grafikonu su isti.
  • Nakon ponovnog raspoređivanja image ostaci ubuntu:19.04, iako grafikon kaže ubuntu:18.04.

Dobili smo desinhronizaciju i izgubili deklarativnost.

Što je sinkronizirani resurs?

Općenito govoreći puni Nemoguće je pronaći podudaranje između manifesta resursa u pokrenutom klasteru i manifesta iz Gita. Budući da u stvarnom manifestu mogu postojati bilješke/oznake usluge, dodatni spremnici i drugi podaci koje neki kontrolori dinamički dodaju i uklanjaju iz resursa. Ne možemo i ne želimo zadržati te podatke u Gitu. Međutim, želimo da polja koja smo eksplicitno naveli u Gitu poprime odgovarajuće vrijednosti nakon uvođenja.

Ispada tako općenito sinkronizirano pravilo resursa: prilikom izvođenja resursa možete promijeniti ili izbrisati samo ona polja koja su izričito navedena u manifestu iz Gita (ili su navedena u prethodnoj verziji i sada su izbrisana).

3-smjerna zakrpa spajanja

središnja ideja 3-smjerna zakrpa spajanja: generirajte zakrpu između posljednje primijenjene verzije manifesta iz Gita i ciljane verzije manifesta iz Gita, uzimajući u obzir trenutnu verziju manifesta iz pokrenutog klastera. Rezultirajuća zakrpa mora biti u skladu s pravilom sinkroniziranih resursa:

  • nova polja dodana ciljnoj verziji dodaju se pomoću zakrpe;
  • prethodno postojeća polja u posljednjoj primijenjenoj verziji i nepostojeća u ciljnoj verziji poništavaju se pomoću zakrpe;
  • polja u trenutnoj verziji objekta koja se razlikuju od ciljane verzije manifesta ažuriraju se pomoću zakrpe.

Na tom principu generira zakrpe kubectl apply:

  • zadnja primijenjena verzija manifesta pohranjuje se u anotaciji samog objekta,
  • target - preuzeto iz navedene YAML datoteke,
  • trenutni je iz pokrenutog klastera.

Sad kad smo sredili teoriju, vrijeme je da vam kažemo što smo radili u werfu.

Primjena promjena na werf

Prethodno je werf, kao i Helm 2, koristio dvosmjerne zakrpe za spajanje.

Popravite zakrpu

Kako bismo prešli na novu vrstu zakrpa - 3-way-merge - prvi korak smo uveli tzv. zakrpe za popravak.

Prilikom implementacije koristi se standardna zakrpa za dvosmjerno spajanje, ali werf dodatno generira zakrpu koja bi sinkronizirala stvarno stanje resursa s onim što je napisano u Git-u (takva se zakrpa stvara pomoću istog pravila sinkroniziranog resursa opisanog gore) .

Ako dođe do desinkronizacije, na kraju postavljanja korisnik dobiva UPOZORENJE s odgovarajućom porukom i zakrpom koju je potrebno primijeniti kako bi se resurs doveo u sinkronizirani oblik. Ova zakrpa također je zabilježena u posebnoj napomeni werf.io/repair-patch. Pretpostavlja se da ruke korisnika sam primijenit će ovu zakrpu: werf je uopće neće primijeniti.

Generiranje zakrpa za popravak privremena je mjera koja vam omogućuje stvarno testiranje stvaranja zakrpa na temelju načela trosmjernog spajanja, ali nemojte automatski primjenjivati ​​te zakrpe. Trenutačno je ovaj način rada uključen prema zadanim postavkama.

Trosmjerna zakrpa spajanja samo za nova izdanja

Od 1. prosinca 2019. počinju beta i alfa verzije werfa prema zadanom koristite potpune trosmjerne zakrpe za spajanje kako biste primijenili promjene samo na nova izdanja Helma koja se uvode kroz werf. Postojeća izdanja nastavit će koristiti pristup dvosmjernog spajanja + popravka zakrpa.

Ovaj način rada može se eksplicitno omogućiti postavljanjem WERF_THREE_WAY_MERGE_MODE=onlyNewReleases sada.

Primijetiti: značajka se pojavila u werf-u tijekom nekoliko izdanja: u alfa kanalu postala je spremna s verzijom v1.0.5-alpha.19, au beta kanalu - sa v1.0.4-beta.20.

Trosmjerna zakrpa spajanja za sva izdanja

Počevši od 15. prosinca 2019., beta i alfa verzije werfa počinju prema zadanim postavkama koristiti pune zakrpe trosmjernog spajanja za primjenu promjena na sva izdanja.

Ovaj način rada može se eksplicitno omogućiti postavljanjem WERF_THREE_WAY_MERGE_MODE=enabled sada.

Što učiniti s automatskim skaliranjem resursa?

U Kubernetesu postoje 2 vrste automatskog skaliranja: HPA (horizontalno) i VPA (vertikalno).

Horizontalno automatski odabire broj replika, okomito - broj resursa. I broj replika i zahtjevi za resursima navedeni su u manifestu resursa (pogledajte Manifest resursa). spec.replicas ili spec.containers[].resources.limits.cpu, spec.containers[].resources.limits.memory и drugi).

Problem: ako korisnik konfigurira resurs u grafikonu tako da specificira određene vrijednosti za resurse ili su replike i autoscaleri omogućeni za ovaj resurs, tada će sa svakom implementacijom werf vratiti te vrijednosti na ono što je napisano u manifestu grafikona .

Postoje dva rješenja problema. Za početak, najbolje je izbjegavati eksplicitno određivanje automatski skaliranih vrijednosti u manifestu grafikona. Ako ova opcija iz nekog razloga nije prikladna (na primjer, jer je zgodno postaviti početna ograničenja resursa i broj replika u grafikonu), tada werf nudi sljedeće bilješke:

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

Ako je takva napomena prisutna, werf neće poništiti odgovarajuće vrijednosti pri svakoj implementaciji, već će ih postaviti samo kada se resurs inicijalno stvori.

Za više detalja pogledajte projektnu dokumentaciju za HPA и VPA.

Zabranite korištenje zakrpe trosmjernog spajanja

Korisnik trenutno može zabraniti korištenje novih zakrpa u werf-u pomoću varijable okruženja WERF_THREE_WAY_MERGE_MODE=disabled. Međutim, počevši Od 1. ožujka 2020. ova se zabrana više neće primjenjivati. i bit će moguće koristiti samo 3-way-merge zakrpe.

Usvajanje resursa u werf

Ovladavanje metodom primjene promjena s trosmjernim spajanjem zakrpa omogućilo nam je da odmah implementiramo značajku kao što je usvajanje resursa koji postoje u klasteru u Helm izdanje.

Helm 2 ima problem: ne možete dodati resurs manifestima grafikona koji već postoji u klasteru bez ponovnog stvaranja tog resursa ispočetka (pogledajte. #6031, #3275). Naučili smo werf da prihvati postojeće resurse za izdavanje. Da biste to učinili, trebate instalirati napomenu na trenutnu verziju resursa iz pokrenutog klastera (na primjer, pomoću kubectl edit):

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

Sada resurs treba opisati u grafikonu i sljedeći put kada werf postavi izdanje s odgovarajućim nazivom, postojeći resurs će biti prihvaćen u ovo izdanje i ostati pod njegovom kontrolom. Štoviše, u procesu prihvaćanja resursa za izdavanje, werf će dovesti trenutno stanje resursa iz pokrenutog klastera u stanje opisano u grafikonu, koristeći iste trosmjerne zakrpe za spajanje i sinkronizirano pravilo resursa.

Primijetiti: postavljanje WERF_THREE_WAY_MERGE_MODE ne utječe na usvajanje resursa - u slučaju usvajanja uvijek se koristi trosmjerna zakrpa spajanja.

Detalji - u dokumentacija.

Zaključci i budući planovi

Nadam se da je nakon ovog članka postalo jasnije što su 3-way-merge zakrpe i zašto su došli do njih. S praktične točke gledišta razvoja projekta werf, njihova implementacija bila je još jedan korak prema poboljšanju Helmove implementacije. Sada možete zaboraviti na probleme sa sinkronizacijom konfiguracije, koji su se često javljali pri korištenju Helma 2. U isto vrijeme, nova korisna značajka usvajanja već preuzetih Kubernetes resursa dodana je izdanju Helma.

Još uvijek postoje neki problemi i izazovi s implementacijama sličnim Helmu, kao što je upotreba Go predložaka, kojima ćemo se nastaviti baviti.

Informacije o metodama ažuriranja resursa i usvajanju također se mogu pronaći na ovu stranicu dokumentacije.

kormilo 3

Vrijedan posebnog spomena pušten na slobodu baš prije neki dan nova velika verzija Helma - v3 - koja također koristi trosmjerne zakrpe za spajanje i riješila se Tillera. Nova verzija Helma zahtijeva migracije postojeće instalacije kako biste ih pretvorili u novi format pohrane izdanja.

Werf se trenutno riješio korištenja Tillera, prebacio se na trosmjerno spajanje i dodao mnogo više, dok ostaje kompatibilan s postojećim Helm 2 instalacijama (ne moraju se izvršavati migracijske skripte). Dakle, sve dok werf ne prijeđe na Helm 3, korisnici werfa ne gube glavne prednosti Helma 3 u odnosu na Helm 2 (ima ih i werf).

Međutim, prebacivanje werfa na Helm 3 kodnu bazu je neizbježno i dogodit će se u bliskoj budućnosti. Vjerojatno će to biti werf 1.1 ili werf 1.2 (trenutačno je glavna verzija werfa 1.0; za više informacija o uređaju za izradu verzija werfa pogledajte здесь). Tijekom tog vremena, Helm 3 će imati vremena da se stabilizira.

PS

Pročitajte i na našem blogu:

Izvor: www.habr.com

Dodajte komentar