3-vejs fletning til werf: udrulning til Kubernetes med Helm "på steroider"

Det, vi (og ikke kun os) har ventet på længe, ​​skete: werf, vores Open Source-værktøj til at bygge applikationer og levere dem til Kubernetes, understøtter nu anvendelse af ændringer ved hjælp af 3-vejs fletterettelser! Ud over dette er det muligt at adoptere eksisterende K8s-ressourcer i Helm-udgivelser uden at genopbygge disse ressourcer.

3-vejs fletning til werf: udrulning til Kubernetes med Helm "på steroider"

Hvis det er meget kort, så sætter vi WERF_THREE_WAY_MERGE=enabled - vi får udrulning "som i kubectl apply", kompatibel med eksisterende Helm 2-installationer og endda lidt mere.

Men lad os starte med teorien: hvad er 3-vejs flette-patches præcist, hvordan fandt folk på tilgangen til at generere dem, og hvorfor er de vigtige i CI/CD-processer med Kubernetes-baseret infrastruktur? Og derefter, lad os se, hvad 3-vejs-fletning er i werf, hvilke tilstande der bruges som standard, og hvordan man administrerer det.

Hvad er en 3-vejs-flet patch?

Så lad os starte med opgaven med at udrulle ressourcerne beskrevet i YAML-manifester til Kubernetes.

For at arbejde med ressourcer tilbyder Kubernetes API følgende grundlæggende handlinger: oprette, patch, erstat og slet. Det antages, at det med deres hjælp er nødvendigt at konstruere en bekvem kontinuerlig udrulning af ressourcer til klyngen. Hvordan?

kubectl imperative kommandoer

Den første tilgang til at administrere objekter i Kubernetes er at bruge kubectl imperative kommandoer til at oprette, ændre og slette disse objekter. Kort fortalt:

  • hold kubectl run du kan køre Deployment eller Job:
    kubectl run --generator=deployment/apps.v1 DEPLOYMENT_NAME --image=IMAGE
  • hold kubectl scale — ændre antallet af replikaer:
    kubectl scale --replicas=3 deployment/mysql
  • etc.

Denne tilgang kan virke bekvem ved første øjekast. Der er dog problemer:

  1. Det er svært automatisere.
  2. Som afspejle konfiguration i Git? Hvordan gennemgår man ændringer, der sker i klyngen?
  3. Hvordan giver man reproducerbarhed konfigurationer ved genstart?
  4. ...

Det er klart, at denne tilgang ikke passer godt til lagring af applikation og infrastruktur som kode (IaC; eller endda GitOps som en mere moderne mulighed, der vinder popularitet i Kubernetes-økosystemet). Derfor modtog disse kommandoer ikke yderligere udvikling i kubectl.

Opret, hent, erstat og slet handlinger

Med primær skabelse det er enkelt: send manifestet til operationen create kube api, og ressourcen er blevet oprettet. YAML-repræsentationen af ​​manifestet kan gemmes i Git og oprettes ved hjælp af kommandoen kubectl create -f manifest.yaml.

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

Operation replace giver dig mulighed for fuldstændigt at erstatte ressourcekonfigurationen med en ny uden at genskabe ressourcen. Det betyder, at før du foretager en ændring af en ressource, er det logisk at forespørge på den aktuelle version med operationen get, skift det og opdater det med handlingen replace. kube apiserver er indbygget optimistisk låsning og hvis efter operationen get objektet er ændret, derefter operationen replace det vil ikke virke.

For at gemme konfigurationen i Git og opdatere den ved hjælp af replace, skal du udføre handlingen get, flet konfigurationen fra Git med det, vi modtog, og kør replace. Som standard tillader kubectl dig kun at bruge kommandoen kubectl replace -f manifest.yamlHvor manifest.yaml — et allerede fuldt forberedt (i vores tilfælde fusioneret) manifest, der skal installeres. Det viser sig, at brugeren skal implementere flettemanifester, og det er ikke en triviel sag...

Det er også værd at bemærke, at selvom manifest.yaml og er gemt i Git, kan vi ikke på forhånd vide, om det er nødvendigt at oprette et objekt eller opdatere det - dette skal gøres af brugersoftware.

Totalt: kan vi bygge en løbende udrulning kun ved at bruge oprette, erstatte og slette, hvilket sikrer, at infrastrukturkonfigurationen er gemt i Git sammen med koden og praktisk CI/CD?

I princippet kan vi... Til dette du bliver nødt til at implementere fletteoperationen manifester og en form for binding, der:

  • kontrollerer tilstedeværelsen af ​​et objekt i klyngen,
  • udfører indledende ressourceoprettelse,
  • opdaterer eller sletter den.

Vær opmærksom på det ved opdatering ressource kan have ændret sig siden sidst get og håndtere automatisk tilfælde af optimistisk låsning - foretag gentagne opdateringsforsøg.

Men hvorfor genopfinde hjulet, når kube-apiserver tilbyder en anden måde at opdatere ressourcer på: operationen patch, som fritager brugeren for nogle af de beskrevne problemer?

patch

Nu kommer vi til lapperne.

Patches er den primære måde at anvende ændringer på eksisterende objekter i Kubernetes. Operation patch det virker sådan her:

  • kube-apiserver-brugeren skal sende en patch i JSON-form og angive objektet,
  • og apiserver selv vil håndtere den aktuelle tilstand af objektet og bringe det til den nødvendige form.

Optimistisk låsning er ikke påkrævet i dette tilfælde. Denne operation er mere deklarativ end at erstatte, selvom det i første omgang kan virke omvendt.

Således:

  • ved hjælp af en operation create vi skaber et objekt i henhold til manifestet fra Git,
  • via delete — slet, hvis objektet ikke længere er nødvendigt,
  • via patch — vi ændrer objektet og bringer det til den form, der er beskrevet i Git.

Men for at gøre dette skal du oprette korrekt patch!

Sådan fungerer patches i Helm 2: 2-vejs-fletning

Når du først installerer en udgivelse, udfører Helm handlingen create for diagramressourcer.

Når du opdaterer en Helm-udgivelse for hver ressource:

  • overvejer patchen mellem ressourceversionen fra det forrige diagram og den aktuelle diagramversion,
  • anvender denne patch.

Vi vil kalde denne patch 2-vejs flette patch, fordi 2 manifester er involveret i dets oprettelse:

  • ressourcemanifest fra den forrige udgivelse,
  • ressourcemanifest fra den aktuelle ressource.

Når operationen fjernes delete i kube apiserver kaldes for ressourcer, der blev erklæret i den forrige udgivelse, men ikke erklæret i den nuværende.

2-vejs merge patch-tilgangen har et problem: det fører til ude af sync med den reelle tilstand af ressourcen i klyngen og manifestet i Git.

Illustration af problemet med et eksempel

  • I Git gemmer et diagram et manifest, hvor feltet image Implementering har betydning ubuntu:18.04.
  • Bruger via kubectl edit ændret værdien af ​​dette felt til ubuntu:19.04.
  • Når du geninstallerer Helm-diagrammet genererer ikke en patch, fordi feltet image i den tidligere version af udgivelsen og i det aktuelle diagram er de samme.
  • Efter genudsendelse image resterne ubuntu:19.04, selvom diagrammet siger ubuntu:18.04.

Vi fik desynkronisering og mistede deklarativitet.

Hvad er en synkroniseret ressource?

Generelt set fuld Det er umuligt at opnå et match mellem ressourcemanifestet i en kørende klynge og manifestet fra Git. For i et rigtigt manifest kan der være tjenesteannoteringer/-etiketter, yderligere containere og andre data, der tilføjes og fjernes fra ressourcen dynamisk af nogle controllere. Vi kan og ønsker ikke at beholde disse data i Git. Vi ønsker dog, at de felter, som vi udtrykkeligt specificerede i Git, antager de relevante værdier ved udrulning.

Det viser sig så generelt synkroniseret ressourceregel: Når du ruller en ressource ud, kan du kun ændre eller slette de felter, der er eksplicit angivet i manifestet fra Git (eller blev specificeret i en tidligere version og nu er slettet).

3-vejs flette patch

centrale idé 3-vejs flette patch: vi genererer en patch mellem den sidst anvendte version af manifestet fra Git og målversionen af ​​manifestet fra Git, under hensyntagen til den aktuelle version af manifestet fra den kørende klynge. Den resulterende patch skal overholde den synkroniserede ressourceregel:

  • nye felter tilføjet til målversionen tilføjes ved hjælp af en patch;
  • tidligere eksisterende felter i den sidst anvendte version og ikke eksisterende i målversionen nulstilles ved hjælp af en patch;
  • felter i den aktuelle version af objektet, der adskiller sig fra målversionen af ​​manifestet, opdateres ved hjælp af patchen.

Det er på dette princip, at det genererer patches kubectl apply:

  • den sidst anvendte version af manifestet gemmes i annoteringen af ​​selve objektet,
  • target - taget fra den angivne YAML-fil,
  • den nuværende er fra en kørende klynge.

Nu hvor vi har ordnet teorien, er det tid til at fortælle dig, hvad vi lavede i werf.

Anvender ændringer til werf

Tidligere brugte werf, ligesom Helm 2, 2-vejs flette-patches.

Reparation patch

For at skifte til en ny type patches - 3-vejs-fletning - introducerede vi det første skridt den såkaldte reparere patches.

Ved udrulning bruges en standard 2-vejs-flet patch, men werf genererer desuden en patch, der ville synkronisere den reelle tilstand af ressourcen med det, der er skrevet i Git (en sådan patch oprettes ved hjælp af den samme synkroniserede ressourceregel beskrevet ovenfor) .

Hvis der sker en desynkronisering, modtager brugeren i slutningen af ​​implementeringen en ADVARSEL med en tilsvarende meddelelse og en patch, der skal anvendes for at bringe ressourcen til en synkroniseret form. Denne patch er også optaget i en speciel annotation werf.io/repair-patch. Det forudsættes, at brugerens hænder selv vil anvende denne patch: werf vil slet ikke anvende den.

Generering af reparationspatches er en midlertidig foranstaltning, der giver dig mulighed for rent faktisk at teste oprettelsen af ​​patches baseret på 3-vejs-flet-princippet, men ikke automatisk anvende disse patches. I øjeblikket er denne driftstilstand aktiveret som standard.

3-vejs-flet patch kun til nye udgivelser

Fra den 1. december 2019 begynder beta- og alfaversioner af werf по умолчанию brug fuldgyldige 3-vejs flette-patches til kun at anvende ændringer på nye Helm-udgivelser, der er rullet ud gennem werf. Eksisterende udgivelser vil fortsætte med at bruge 2-vejs-fletning + reparationspatches-tilgangen.

Denne driftstilstand kan aktiveres eksplicit ved at indstille WERF_THREE_WAY_MERGE_MODE=onlyNewReleases nu.

Bemærk: funktionen dukkede op i werf over flere udgivelser: i alfakanalen blev den klar med version v1.0.5-alfa.19, og i betakanalen - med v1.0.4-beta.20.

3-vejs-flet patch til alle udgivelser

Fra den 15. december 2019 begynder beta- og alfaversioner af werf som standard at bruge fulde 3-vejs-fletningspatches for at anvende ændringer på alle udgivelser.

Denne driftstilstand kan aktiveres eksplicit ved at indstille WERF_THREE_WAY_MERGE_MODE=enabled nu.

Hvad skal man gøre med ressourceautoskalering?

Der er 2 typer autoskalering i Kubernetes: HPA (vandret) og VPA (lodret).

Vandret vælger automatisk antallet af replikaer, lodret - antallet af ressourcer. Både antallet af replikaer og ressourcekrav er angivet i ressourcemanifestet (se ressourcemanifest). spec.replicas eller spec.containers[].resources.limits.cpu, spec.containers[].resources.limits.memory и andre).

Problem: hvis en bruger konfigurerer en ressource i et diagram, så den specificerer bestemte værdier for ressourcer, eller replikaer og autoskalere er aktiveret for denne ressource, så vil werf med hver implementering nulstille disse værdier til det, der er skrevet i diagrammanifestet .

Der er to løsninger på problemet. Til at begynde med er det bedst at undgå eksplicit at angive autoskalerede værdier i diagrammanifestet. Hvis denne mulighed af en eller anden grund ikke er egnet (for eksempel fordi det er praktisk at indstille indledende ressourcegrænser og antallet af replikaer i diagrammet), så tilbyder werf følgende kommentarer:

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

Hvis en sådan annotering er til stede, vil werf ikke nulstille de tilsvarende værdier på hver implementering, men vil kun indstille dem, når ressourcen oprindeligt oprettes.

For flere detaljer, se projektdokumentationen for HPA и VPA.

Forbyd brugen af ​​3-vejs-flet patch

Brugeren kan i øjeblikket forbyde brugen af ​​nye patches i werf ved hjælp af en miljøvariabel WERF_THREE_WAY_MERGE_MODE=disabled. Dog starter Fra 1. marts 2020 gælder dette forbud ikke længere. og det vil kun være muligt at bruge 3-vejs flette patches.

Vedtagelse af ressourcer i werf

At mestre metoden til at anvende ændringer med 3-vejs flette-patches gjorde det muligt for os straks at implementere en sådan funktion som at adoptere ressourcer, der findes i klyngen, i Helm-udgivelsen.

Helm 2 har et problem: du kan ikke tilføje en ressource til diagrammanifester, der allerede findes i klyngen uden at genskabe denne ressource fra bunden (se. #6031, #3275). Vi lærte werf at acceptere eksisterende ressourcer til frigivelse. For at gøre dette skal du installere en anmærkning på den aktuelle version af ressourcen fra den kørende klynge (f.eks. kubectl edit):

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

Nu skal ressourcen beskrives i diagrammet, og næste gang werf implementerer en udgivelse med det passende navn, vil den eksisterende ressource blive accepteret i denne udgivelse og forblive under dens kontrol. Desuden vil werf i processen med at acceptere en ressource til frigivelse bringe den aktuelle tilstand af ressourcen fra den kørende klynge til den tilstand, der er beskrevet i diagrammet, ved at bruge de samme 3-vejs flette-patches og den synkroniserede ressourceregel.

Bemærk: indstilling WERF_THREE_WAY_MERGE_MODE påvirker ikke overtagelsen af ​​ressourcer - i tilfælde af adoption bruges der altid en 3-vejs fletning.

Detaljer - in dokumentation.

Konklusioner og fremtidsplaner

Jeg håber, at det efter denne artikel er blevet tydeligere, hvad 3-vejs flette-patches er, og hvorfor de kom til dem. Fra et praktisk synspunkt med hensyn til udviklingen af ​​werf-projektet var deres implementering endnu et skridt i retning af at forbedre den Helm-lignende implementering. Nu kan du glemme problemerne med konfigurationssynkronisering, som ofte opstod, når du brugte Helm 2. Samtidig blev en ny nyttig funktion til at adoptere allerede downloadede Kubernetes-ressourcer tilføjet til Helm-udgivelsen.

Der er stadig nogle problemer og udfordringer med Helm-lignende implementeringer, såsom brugen af ​​Go-skabeloner, som vi vil fortsætte med at løse.

Oplysninger om ressourceopdateringsmetoder og adoption kan også findes på denne dokumentationsside.

Hjelm 3

Værd at være særlig opmærksom på frigivet netop forleden en ny større version af Helm - v3 - som også bruger 3-vejs-flet patches og slipper af med Tiller. Den nye version af Helm kræver migration eksisterende installationer for at konvertere dem til det nye udgivelseslagringsformat.

Werf på sin side er i øjeblikket sluppet for at bruge Tiller, skiftet til 3-vejs-fletning og tilføjet meget mere, mens den forbliver kompatibel med eksisterende Helm 2-installationer (ingen migreringsscripts skal udføres). Derfor, indtil werf skifter til Helm 3, mister werf-brugere ikke de vigtigste fordele ved Helm 3 frem for Helm 2 (werf har dem også).

Skiftet fra werf til Helm 3-kodebasen er dog uundgåeligt og vil ske i den nærmeste fremtid. Formentlig vil dette være werf 1.1 eller werf 1.2 (i øjeblikket er hovedversionen af ​​werf 1.0; for mere information om werf versioneringsenheden, se her). I løbet af denne tid vil Helm 3 have tid til at stabilisere sig.

PS

Læs også på vores blog:

Kilde: www.habr.com

Tilføj en kommentar