3-veis sammenslåing til werf: distribusjon til Kubernetes med Helm "på steroider"

Det vi (og ikke bare vi) har ventet på lenge skjedde: werf, vårt åpen kildekode-verktøy for å bygge applikasjoner og levere dem til Kubernetes, støtter nå bruk av endringer ved å bruke 3-veis fletteoppdateringer! I tillegg til dette er det mulig å ta i bruk eksisterende K8s-ressurser i Helm-utgivelser uten å gjenoppbygge disse ressursene.

3-veis sammenslåing til werf: distribusjon til Kubernetes med Helm "på steroider"

Hvis det er veldig kort, så setter vi WERF_THREE_WAY_MERGE=enabled - vi får distribusjon "som i kubectl apply", kompatibel med eksisterende Helm 2-installasjoner og enda litt mer.

Men la oss starte med teorien: hva er egentlig 3-veis sammenslåingsoppdateringer, hvordan kom folk på tilnærmingen til å generere dem, og hvorfor er de viktige i CI/CD-prosesser med Kubernetes-basert infrastruktur? Og etter det, la oss se hva 3-veis-sammenslåing er i werf, hvilke moduser som brukes som standard og hvordan du administrerer det.

Hva er en 3-veis sammenslåing patch?

Så la oss starte med oppgaven med å rulle ut ressursene beskrevet i YAML-manifestene til Kubernetes.

For å jobbe med ressurser tilbyr Kubernetes API følgende grunnleggende operasjoner: opprette, korrigere, erstatte og slette. Det antas at det med deres hjelp er nødvendig å konstruere en praktisk kontinuerlig utrulling av ressurser til klyngen. Hvordan?

kubectl imperative kommandoer

Den første tilnærmingen til å administrere objekter i Kubernetes er å bruke kubectl imperative kommandoer for å opprette, endre og slette disse objektene. For å si det enkelt:

  • team kubectl run du kan kjøre distribusjon eller jobb:
    kubectl run --generator=deployment/apps.v1 DEPLOYMENT_NAME --image=IMAGE
  • team kubectl scale — endre antall kopier:
    kubectl scale --replicas=3 deployment/mysql
  • etc.

Denne tilnærmingen kan virke praktisk ved første øyekast. Det er imidlertid problemer:

  1. Det er vanskelig automatisere.
  2. Som reflekterer konfigurasjonen i Git? Hvordan vurdere endringer som skjer med klyngen?
  3. Hvordan gi reproduserbarhet konfigurasjoner ved omstart?
  4. ...

Det er klart at denne tilnærmingen ikke passer godt med lagring av applikasjoner og infrastruktur som kode (IaC; eller til og med gitops som et mer moderne alternativ, som vinner popularitet i Kubernetes-økosystemet). Derfor fikk ikke disse kommandoene videre utvikling i kubectl.

Opprett, hent, erstatt og slett operasjoner

Med primær opprettelse det er enkelt: send manifestet til operasjonen create kube api og ressursen er opprettet. YAML-representasjonen av manifestet kan lagres i Git og opprettes ved hjelp av kommandoen kubectl create -f manifest.yaml.

С fjerne også enkelt: erstatte det samme manifest.yaml fra Git til team kubectl delete -f manifest.yaml.

Operasjon replace lar deg erstatte ressurskonfigurasjonen fullstendig med en ny, uten å gjenskape ressursen. Dette betyr at før du gjør en endring i en ressurs, er det logisk å spørre etter gjeldende versjon med operasjonen get, endre den og oppdater den med operasjonen replace. kube apiserver er innebygd optimistisk låsing og, hvis etter operasjonen get objektet er endret, deretter operasjonen replace det vil ikke fungere.

For å lagre konfigurasjonen i Git og oppdatere den ved å bruke replace, må du utføre operasjonen get, slå sammen konfigurasjonen fra Git med det vi mottok, og utfør replace. Som standard lar kubectl deg bare bruke kommandoen kubectl replace -f manifest.yamlDer manifest.yaml — et allerede fullt forberedt (i vårt tilfelle, sammenslått) manifest som må installeres. Det viser seg at brukeren trenger å implementere flettemanifester, og dette er ikke en triviell sak...

Det er også verdt å merke seg at selv om manifest.yaml og er lagret i Git, kan vi ikke på forhånd vite om det er nødvendig å lage et objekt eller oppdatere det – dette må gjøres av brukerprogramvare.

totalt: kan vi bygge en kontinuerlig utrulling bruker bare opprette, erstatt og slett, og sikrer at infrastrukturkonfigurasjonen er lagret i Git sammen med koden og praktisk CI/CD?

I prinsippet kan vi... For dette du må implementere fletteoperasjonen manifester og en slags binding som:

  • sjekker tilstedeværelsen av et objekt i klyngen,
  • utfører første ressursoppretting,
  • oppdaterer eller sletter den.

Vær oppmerksom på det ved oppdatering ressursen kan ha endret seg siden sist get og håndterer automatisk tilfelle av optimistisk låsing - gjør gjentatte oppdateringsforsøk.

Men hvorfor finne opp hjulet på nytt når kube-apiserver tilbyr en annen måte å oppdatere ressurser på: operasjonen patch, som avlaster brukeren for noen av de beskrevne problemene?

patch

Nå kommer vi til lappene.

Patcher er den primære måten å bruke endringer på eksisterende objekter i Kubernetes. Operasjon patch det fungerer slik:

  • kube-apiserver-brukeren må sende en oppdatering i JSON-form og spesifisere objektet,
  • og apiserver selv vil håndtere den nåværende tilstanden til objektet og bringe det til ønsket form.

Optimistisk låsing er ikke nødvendig i dette tilfellet. Denne operasjonen er mer deklarativ enn å erstatte, selv om det i begynnelsen kan virke omvendt.

På denne måten:

  • ved hjelp av en operasjon create vi lager et objekt i henhold til manifestet fra Git,
  • via delete – slett hvis objektet ikke lenger er nødvendig,
  • via patch — vi endrer objektet, bringer det til formen beskrevet i Git.

Men for å gjøre dette, må du lage riktig lapp!

Hvordan patcher fungerer i Helm 2: 2-veis-sammenslåing

Når du først installerer en utgivelse, utfører Helm operasjonen create for kartressurser.

Når du oppdaterer en Helm-utgivelse for hver ressurs:

  • vurderer oppdateringen mellom ressursversjonen fra forrige diagram og gjeldende diagramversjon,
  • bruker denne oppdateringen.

Vi vil kalle denne patchen 2-veis fletteoppdatering, fordi 2 manifester er involvert i opprettelsen:

  • ressursmanifest fra forrige utgivelse,
  • ressursmanifest fra gjeldende ressurs.

Når operasjonen fjernes delete i kube apiserver kalles for ressurser som ble deklarert i forrige utgivelse, men ikke erklært i den nåværende.

Den 2-veis flette patch-tilnærmingen har et problem: den fører til ute av synkronisering med den virkelige tilstanden til ressursen i klyngen og manifestet i Git.

Illustrasjon av problemet med et eksempel

  • I Git lagrer et diagram et manifest der feltet image Utplassering er viktig ubuntu:18.04.
  • Bruker via kubectl edit endret verdien på dette feltet til ubuntu:19.04.
  • Når du distribuerer rordiagrammet på nytt genererer ikke en oppdatering, fordi feltet image i forrige versjon av utgivelsen og i gjeldende diagram er de samme.
  • Etter omplassering image rester ubuntu:19.04, selv om diagrammet sier ubuntu:18.04.

Vi fikk desynkronisering og mistet deklarativiteten.

Hva er en synkronisert ressurs?

Generelt sett full Det er umulig å oppnå samsvar mellom ressursmanifestet i en løpende klynge og manifestet fra Git. For i et ekte manifest kan det være tjenesteanmerkninger/-etiketter, tilleggsbeholdere og andre data som legges til og fjernes fra ressursen dynamisk av enkelte kontrollere. Vi kan og ønsker ikke å beholde disse dataene i Git. Vi vil imidlertid at feltene som vi eksplisitt spesifiserte i Git skal ta på seg de riktige verdiene ved utrulling.

Det viser seg så generelt synkronisert ressursregel: når du ruller ut en ressurs, kan du endre eller slette bare de feltene som er eksplisitt spesifisert i manifestet fra Git (eller ble spesifisert i en tidligere versjon og er nå slettet).

3-veis fletteoppdatering

sentrale ideen 3-veis fletteoppdatering: vi genererer en oppdatering mellom den sist brukte versjonen av manifestet fra Git og målversjonen av manifestet fra Git, tar hensyn til gjeldende versjon av manifestet fra den kjørende klyngen. Den resulterende oppdateringen må overholde den synkroniserte ressursregelen:

  • nye felt lagt til målversjonen legges til ved hjelp av en oppdatering;
  • tidligere eksisterende felt i den sist brukte versjonen og ikke eksisterende i målversjonen tilbakestilles ved hjelp av en oppdatering;
  • felt i gjeldende versjon av objektet som er forskjellig fra målversjonen av manifestet, oppdateres ved hjelp av oppdateringen.

Det er på dette prinsippet den genererer patcher kubectl apply:

  • den siste brukte versjonen av manifestet lagres i merknaden til selve objektet,
  • target - hentet fra den angitte YAML-filen,
  • den nåværende er fra en løpende klynge.

Nå som vi har sortert ut teorien, er det på tide å fortelle deg hva vi gjorde i werf.

Bruker endringer på werf

Tidligere brukte werf, i likhet med Helm 2, 2-veis flettelapper.

reparasjon patch

For å bytte til en ny type patcher – 3-veis-sammenslåing – introduserte vi det første trinnet den s.k. reparere lapper.

Ved utrulling brukes en standard 2-veis sammenslåingspatch, men werf genererer i tillegg en patch som vil synkronisere den virkelige tilstanden til ressursen med det som er skrevet i Git (en slik patch lages ved å bruke den samme synkroniserte ressursregelen beskrevet ovenfor) .

Hvis en desynkronisering oppstår, mottar brukeren på slutten av distribusjonen en ADVARSEL med en tilsvarende melding og en oppdatering som må brukes for å bringe ressursen til en synkronisert form. Denne oppdateringen er også spilt inn i en spesiell merknad werf.io/repair-patch. Det forutsettes at brukerens hender selv vil bruke denne oppdateringen: werf vil ikke bruke den i det hele tatt.

Generering av reparasjonspatcher er et midlertidig tiltak som lar deg faktisk teste opprettelsen av patcher basert på 3-veis-sammenslåingsprinsippet, men ikke automatisk bruke disse patchene. For øyeblikket er denne driftsmodusen aktivert som standard.

3-veis sammenslåingsoppdatering kun for nye utgivelser

Fra 1. desember 2019 begynner beta- og alfaversjoner av werf som standard bruk fullverdige 3-veis sammenslåingsoppdateringer for å bruke endringer kun på nye Helm-utgivelser rullet ut gjennom werf. Eksisterende utgivelser vil fortsette å bruke 2-veis-sammenslåing + reparasjonspatcher-tilnærmingen.

Denne driftsmodusen kan aktiveres eksplisitt ved innstilling WERF_THREE_WAY_MERGE_MODE=onlyNewReleases nå.

Note: funksjonen dukket opp i werf over flere utgivelser: i alfakanalen ble den klar med versjon v1.0.5-alfa.19, og i betakanalen - med v1.0.4-beta.20.

3-veis sammenslåingsoppdatering for alle utgivelser

Fra og med 15. desember 2019 begynner beta- og alfaversjoner av werf å bruke fullstendige 3-veis sammenslåingsoppdateringer som standard for å bruke endringer på alle utgivelser.

Denne driftsmodusen kan aktiveres eksplisitt ved innstilling WERF_THREE_WAY_MERGE_MODE=enabled nå.

Hva skal jeg gjøre med ressurs autoskalering?

Det er 2 typer autoskalering i Kubernetes: HPA (horisontal) og VPA (vertikal).

Horisontal velger automatisk antall replikaer, vertikal - antall ressurser. Både antall replikaer og ressurskrav er spesifisert i ressursmanifestet (se Ressursmanifest). spec.replicas eller spec.containers[].resources.limits.cpu, spec.containers[].resources.limits.memory и andre).

Problem: hvis en bruker konfigurerer en ressurs i et diagram slik at den spesifiserer visse verdier for ressurser eller replikaer og autoskalere er aktivert for denne ressursen, vil werf med hver distribusjon tilbakestille disse verdiene til det som er skrevet i diagrammanifestet .

Det er to løsninger på problemet. Til å begynne med er det best å unngå å eksplisitt spesifisere autoskalerte verdier i diagrammanifestet. Hvis dette alternativet ikke er egnet av en eller annen grunn (for eksempel fordi det er praktisk å angi innledende ressursgrenser og antall replikaer i diagrammet), tilbyr werf følgende merknader:

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

Hvis en slik merknad er tilstede, vil werf ikke tilbakestille de tilsvarende verdiene på hver distribusjon, men vil bare sette dem når ressursen først er opprettet.

For flere detaljer, se prosjektdokumentasjonen for HPA и VPA.

Forby bruk av 3-veis sammenslåingsoppdatering

Brukeren kan for øyeblikket forby bruken av nye patcher i werf ved å bruke en miljøvariabel WERF_THREE_WAY_MERGE_MODE=disabled. Imidlertid starter Fra 1. mars 2020 vil dette forbudet ikke lenger gjelde. og det vil kun være mulig å bruke 3-veis fletteoppdateringer.

Adopsjon av ressurser i werf

Å mestre metoden for å bruke endringer med 3-veis sammenslåingspatcher tillot oss umiddelbart å implementere en funksjon som å ta i bruk ressurser som eksisterer i klyngen i Helm-utgivelsen.

Helm 2 har et problem: du kan ikke legge til en ressurs til diagrammanifester som allerede eksisterer i klyngen uten å gjenskape denne ressursen fra bunnen av (se. #6031, #3275). Vi lærte werf å akseptere eksisterende ressurser for utgivelse. For å gjøre dette må du installere en merknad på gjeldende versjon av ressursen fra den kjørende klyngen (for eksempel ved å bruke kubectl edit):

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

Nå må ressursen beskrives i diagrammet, og neste gang werf distribuerer en utgivelse med riktig navn, vil den eksisterende ressursen bli akseptert i denne utgivelsen og forbli under dens kontroll. I prosessen med å akseptere en ressurs for utgivelse, vil werf dessuten bringe den nåværende tilstanden til ressursen fra den kjørende klyngen til tilstanden beskrevet i diagrammet, ved å bruke de samme 3-veis sammenslåingsoppdateringene og den synkroniserte ressursregelen.

Note: innstilling WERF_THREE_WAY_MERGE_MODE påvirker ikke adopsjon av ressurser - ved adopsjon brukes alltid en 3-veis flettelapp.

Detaljer - inn dokumentasjon.

Konklusjoner og fremtidsplaner

Jeg håper at det etter denne artikkelen har blitt klarere hva 3-veis flette-patcher er og hvorfor de kom til dem. Fra et praktisk synspunkt av utviklingen av werf-prosjektet var implementeringen av dem enda et skritt mot å forbedre den Helm-lignende utplasseringen. Nå kan du glemme problemene med konfigurasjonssynkronisering, som ofte oppsto ved bruk av Helm 2. Samtidig ble en ny nyttig funksjon for å ta i bruk allerede nedlastede Kubernetes-ressurser lagt til Helm-utgivelsen.

Det er fortsatt noen problemer og utfordringer med Helm-lignende distribusjoner, for eksempel bruken av Go-maler, som vi vil fortsette å ta tak i.

Informasjon om ressursoppdateringsmetoder og adopsjon kan også finnes på denne dokumentasjonssiden.

Ror 3

Verdt å merke seg spesielt løslatt forleden dag en ny hovedversjon av Helm - v3 - som også bruker 3-veis flettelapper og blir kvitt Tiller. Den nye versjonen av Helm krever migrasjon eksisterende installasjoner for å konvertere dem til det nye lagringsformatet.

Werf på sin side har for øyeblikket kvittet seg med Tiller, gått over til 3-veis sammenslåing og lagt til mye mer, mens den forblir kompatibel med eksisterende Helm 2-installasjoner (ingen migreringsskript trenger å utføres). Derfor, før werf bytter til Helm 3, mister ikke werf-brukere hovedfordelene til Helm 3 fremfor Helm 2 (werf har dem også).

Byttingen av werf til Helm 3-kodebasen er imidlertid uunngåelig og vil skje i nær fremtid. Antagelig vil dette være werf 1.1 eller werf 1.2 (for øyeblikket er hovedversjonen av werf 1.0; for mer informasjon om werf-versjonsenheten, se her). I løpet av denne tiden vil Helm 3 ha tid til å stabilisere seg.

PS

Les også på bloggen vår:

Kilde: www.habr.com

Legg til en kommentar