Korrekt sammenligning af Kubernetes Apply, Replace og Patch

Der er flere måder at opdatere ressourcer i Kubernetes: apply, edit, patch og replace. Der er forvirring omkring, hvad hver af dem gør, og hvornår de skal anvendes. Lad os finde ud af det.

Korrekt sammenligning af Kubernetes Apply, Replace og Patch

Hvis man søger i Google sætningen "kubernetes apply vs replace", finder man et svar på StackOverflow, som ikke er korrekt. Når man søger efter "kubernetes apply vs patch", er det første link - dokumentationen for kubectl patch, som ikke inkluderer en sammenligning apply og patch. I denne artikel vil vi se på de forskellige muligheder og den korrekte anvendelse af hver enkelt.

I løbet af livscyklussen for en Kubernetes-ressource (tjeneste, deployment, ingress osv.) er det nogle gange nødvendigt at ændre, tilføje eller fjerne nogle egenskaber ved denne ressource. For eksempel at tilføje en note, øge eller formindske antallet af replikater.

Kubernetes CLI

Hvis du allerede arbejder med Kubernetes-klynger via CLI, er du allerede bekendt med apply og edit. Kommandoen apply læser specifikationen for ressourcen fra en fil og foretager "upsert" i Kubernetes-klyngen, dvs. den opretter ressourcen, hvis den ikke findes, og opdaterer den, hvis den eksisterer. Kommandoen edit læser ressourcen via API, hvorefter den skriver specifikationen for ressourcen til en lokal fil, som derefter åbnes i en teksteditor. Når du har redigeret og gemt filen, kubectl sender de foretagne ændringer tilbage via API, som omhyggeligt anvender disse ændringer på ressourcen.

Ikke alle kender kommandoerne patch og replace. Kommandoen patch giver mulighed for at ændre en del af specifikationen for ressourcen ved kun at give den ændrede del i kommandolinjen. Kommandoen replace fungerer på samme måde som edit, men alt skal gøres manuelt: du skal downloade den nuværende version af specifikationen for ressourcen, f.eks. ved hjælp af kubectl get -o yaml, redigere den, og derefter bruge replace til at opdatere ressourcen med den ændrede specifikation. Kommandoen replace vil ikke fungere, hvis der er sket ændringer mellem læsningen og udskiftningen af ressourcen.

Kubernetes API

Du kender muligvis metoderne CoreV1().Pods().Update(), replaceNamespacedService eller patch_namespaced_deployment, hvis du arbejder med klynger via klientbiblioteket til Kubernetes API ved hjælp af et programmeringssprog. Biblioteket håndterer disse metoder med HTTP-anmodninger, ved hjælp af metoderne PUT og PATCH. I denne forbindelse opdatering og replace bruger PUT, og patch, så trist det end måtte lyde, bruger PATCH.

Det skal bemærkes, at kubectl også fungerer med klynger gennem API. Med andre ord, kubectl– er et lag oven på klientbiblioteket for Go-sprog, som i høj grad muliggør at give underkommandoer på en mere kompakt og læsbar måde oven i de standard API-muligheder. For eksempel, som du allerede har bemærket, blev metoden apply ikke nævnt ovenfor i det forrige afsnit. I øjeblikket (maj 2020, oversætterens bemærkning) al logik kubectl apply, dvs. oprettelse af ikke-eksisterende ressourcer og opdatering af eksisterende, fungerer fuldstændigt på kode-siden kubectl. Der gøres bestræbelser på at overføre logik apply til API-siden, men det er stadig i beta-testning. Jeg vil uddybe dette nedenfor.

Patch som standard

Det er bedst at anvende patch, hvis du ønsker at opdatere ressourcen. Sådan fungerer både klientbibliotekerne oven på API Kubernetes og kubectl (ikke overraskende, da det er et lag oven på klientbiblioteket, oversætterens bemærkning).

At arbejde strategisk

Alle kommandoer kubectl apply, edit og patch benytter metoden PATCH i HTTP-anmodninger for at opdatere en eksisterende ressource. Hvis man ser nærmere på implementeringen af kommandoerne, så bruger alle en tilgang strategic-merge patching til opdatering af ressourcer, selvom kommandoen patch kan bruge andre tilgange (mere om dette nedenfor). Tilgangen strategic-merge patching forsøger at "gøre alt korrekt" ved at slå den angivne specifikation sammen med den eksisterende specifikation. Mere specifikt forsøger den at kombinere både objekter og arrays, hvilket betyder, at ændringer typisk er additive. For eksempel, at køre kommandoen patch med en ny miljøvariabel i pod-kontainerspecifikationen, tilføjer denne miljøvariabels til de eksisterende miljøvariabler i stedet for at overskrive dem. For at fjerne dette ved denne tilgang, skal værdien af parameteren tvinges til at være null i den angivne specifikation. Hvilke af kommandoerne kubectl til opdatering er bedst at bruge?

Hvis du opretter og administrerer dine ressourcer ved hjælp af kubectl apply, er det bedst altid at bruge kubectl apply, så kubectl kan administrere konfigurationen og korrekt spore de anmodede ændringer fra anvendelse til anvendelse. Fordelen ved altid at bruge apply er, at den holder styr på den tidligere anvendte specifikation, hvilket giver den mulighed for at vide, hvornår specifikationens egenskaber og elementer i arrayet eksplicit fjernes. Dette muliggør brugen af apply til fjernelse af egenskaber og elementer i et array, mens almindelig strategisk sammensmeltning ikke vil fungere. Kommandoerne edit og patch opdaterer ikke kommentarerne, som kubectl apply bruger til at spore sine ændringer, så eventuelle ændringer, der spores og laves via Kubernetes API, men foretaget via kommandoer edit og patch, er usynlige for følgende kommandoer apply, altså apply fjerner dem ikke, selvom de ikke fremgår af den indkommende specifikation for apply (Dokumentationen angiver, at edit og patch foretager opdateringer af kommentarerne, der bruges apply, men i praksis - nej).

Hvis du ikke bruger kommandoen apply, kan du bruge både edit, og patch, og vælge den kommando, der passer bedst til den ændring, der foretages. Når du tilføjer og ændrer egenskaber i specifikationen, er begge tilgange omtrent ens. Ved sletning af egenskaber i specifikationen eller elementer i arrayet edit opfører sig som et engangsstart apply, herunder at spore, hvad specifikationen var før og efter redigeringen, så du kan eksplicit fjerne egenskaber og elementer i arrayet fra ressourcen. Det er nødvendigt eksplicit at sætte værdien af egenskaben til null i specifikationen for patch, for at fjerne det fra ressourcen. Sletning af et element i arrayet ved hjælp af strategisk sammensmeltnings-patch er mere komplekst, da det kræver brug af sammenfletningsdirektiver. Se andre tilgange til opdatering nedenfor for at vælge mere acceptable alternativer.

For at implementere i klientbiblioteket metoder til opdatering, der fungerer på samme måde som de ovenfor nævnte kommandoer kubectl, skal du angive content-type i application/strategic-merge-patch+json. Hvis du vil fjerne egenskaber i specifikationen, skal du eksplicit sætte deres værdier til null svarende til kubectl patch. Hvis du skal fjerne elementer fra arrayet, skal du inkludere sammenfletningsdirektiver i opdateringsspecifikationen eller bruge en anden tilgang til opdateringer.

Andre tilgange til opdateringer

Kubernetes understøtter to andre tilgange til opdateringer: JSON sammensmeltning patch og JSON patch. JSON merge patch-metoden accepterer en delvis specifikation af Kubernetes som input og understøtter sammenføring af objekter på en måde, der ligner strategic-merge patching. Forskellen mellem dem er, at den kun understøtter erstatning af arrays, inklusive arrayet af containere i pod-specifikationen. Det betyder, at når du bruger JSON merge patch, skal du angive komplette specifikationer for alle containere, hvis nogen egenskab af en container ændres. Derfor er denne tilgang nyttig til at fjerne elementer fra et array i specifikationen. I kommandolinjen kan du vælge JSON merge patch ved at bruge kubectl patch --type=merge. Når du arbejder med Kubernetes API, skal du bruge metoden PATCH og indstillingen content-type i application/merge-patch+json.

JSON patch-tilgangen bruger i stedet for at give en delvis specifikation af ressourcen en liste over ændringer, som du ønsker at foretage i ressourcen, i form af et array, hvor hvert element i arrayet repræsenterer en beskrivelse af ændringen, der skal foretages i ressourcen. Denne tilgang er en mere fleksibel og kraftfuld måde at udtrykke de ændringer, der foretages, men på bekostning af, at listen over ændringer kommer i et separat, ikke-Kubernetes format, i stedet for at sende en delvis specifikation af ressourcen. I kubectl kan du vælge JSON patch ved at bruge kubectl patch --type=json. Når du bruger Kubernetes API, fungerer denne tilgang ved at bruge metoden PATCH og indstillingen content-type i application/json-patch+json.

Har brug for sikkerhed — bruger replace

I nogle tilfælde har man brug for at være sikker på, at ressourcen ikke vil ændres mellem læsningen af ressourcen og opdateringen af den. Med andre ord, man skal sikre sig, at alle ændringer vil være atomære. I dette tilfælde er det bedst at bruge replace. For eksempel, hvis der er en ConfigMap med en tæller, der opdateres af flere kilder, skal man være sikker på, at to kilder ikke opdaterer tælleren samtidig, hvilket vil føre til tab af opdateringen. For at demonstrere, forestil dig en sekvens af hændelser, hvor patch:

  • A og B henter den nuværende tilstand af ressourcen fra API'et
  • Hver især opdaterer lokalt specifikationen ved at øge tælleren med én, og tilføjer henholdsvis "A" eller "B" til bemærkningen "updated-by"
  • A opdaterer ressourcen lidt hurtigere
  • B opdaterer ressourcen

Som opfølgning er opdatering A gået tabt. Den seneste operation patch vinder, tælleren øges med én i stedet for to, og værdien af kommentaren "updated-by" ender med "B" og indeholder ikke "A". Lad os sammenligne det ovenstående med, hvad der sker, når opdateringer udføres ved hjælp af metoden replace:

  • A og B henter den nuværende tilstand af ressourcen fra API'et
  • Hver især opdaterer lokalt specifikationen ved at øge tælleren med én, og tilføjer henholdsvis "A" eller "B" til bemærkningen "updated-by"
  • A opdaterer ressourcen lidt hurtigere
  • B forsøger at opdatere ressourcen, men opdateringen afvises af API'en, fordi versionen af ressourcen i specifikationen replace ikke svarer til den nuværende version af ressourcen i Kubernetes, da versionen af ressourcen blev forøget under udførelsen af operationen replace fra A's side.

I ovenstående tilfælde skal B trække ressourcen igen, foretage ændringer til den nye tilstand og forsøge igen at gøre replace. Som følge heraf vil tælleren blive forøget med to, og kommentaren "updated-by" vil indeholde "AB" til sidst.

Det ovenstående eksempel antyder, at under udførelsen replace udføres en fuld erstatning af hele ressourcen. Specifikationen, der anvendes til replace, skal ikke være delvis eller i dele som i apply, men fuld, inklusive tilføjelsen af resourceVersion i metadataene af specifikationen. Hvis du ikke inkluderer resourceVersion eller den version, du angav, ikke er aktuel, vil erstatningen blive afvist. Derfor er den bedste tilgang at bruge replace – at læse ressourcen, opdatere den og straks erstatte. Ved at bruge kubectl, kan det se sådan ud:

$ kubectl get deployment my-deployment -o json 
    | jq '.spec.template.spec.containers[0].env[1].value = "new value"' 
    | kubectl replace -f -

Det skal bemærkes, at de følgende to kommandoer, der udføres efter hinanden, vil blive udført med succes, da deployment.yaml ikke indeholder egenskaben .metadata.resourceVersion

$ kubectl create -f deployment.yaml
$ kubectl replace -f deployment.yaml

Det synes at være i modstrid med det, der blev sagt ovenstående, altså "tilføjelsen resourceVersion til metadataene af specifikationen". Er det forkert at påstå? Nej, det er det ikke, da hvis kubectl bemærker, at du ikke har angivet resourceVersion, læser den det fra ressourcen og tilføjer det til den specifikation, du angav, og først derefter udfører replace. Da denne potentielt er farlig, hvis man stoler på atomaritet, fungerer magien helt på kubectl, så det er ikke klogt at stole på den ved brug af klientbiblioteker, der arbejder med API'en. I dette tilfælde skal du læse den nuværende specifikation for ressourcen, opdatere den og derefter udføre PUT forespørgslen.

Det er ikke muligt at lave en patch – vi laver en erstatning

Nogle gange er det nødvendigt at foretage ændringer, som API'et ikke kan håndtere. I disse tilfælde kan ressourcen tvinges til at blive erstattet ved at slette og genoprette den. Dette gøres ved hjælp af kubectl replace --force. At køre kommandoen fjerner straks ressourcerne og genopretter dem med den angivne specifikation. API'et har ikke en "tvangserstatning"-håndterer, så for at gøre dette gennem API'et skal der udføres to operationer. Først skal ressourcen slettes, med gracePeriodSeconds sat til nul (0) og propagationPolicy sat til “Background”, og derefter genoprettes denne ressource med den ønskede specifikation.

Bemærk: Denne tilgang er potentielt farlig, da den kan føre til en usikker tilstand.

Apply på serversiden

Som nævnt tidligere arbejder Kubernetes-udviklerne på at implementere logik apply af kubectl i Kubernetes API'et. Logikken apply er tilgængelig i Kubernetes 1.18 gennem kubectl apply --server-side eller gennem API'et ved at bruge metoden PATCH med content-type application/apply-patch+YAML.

Bemærk: JSON er også gyldig YAML, så specifikationen kan sendes i JSON-format, selvom content-type det vil application/apply-patch+yaml.

Udover at logikken kubectl bliver tilgængelig for alle via API'et, apply på serversiden overvåger den ansvarlige for felterne i specifikationen, hvilket muliggør sikker samtidig adgang for konfliktfri redigering. Med andre ord, hvis apply på serversiden får bredere udbredelse, vil der opstå et universelt sikkert grænseflade til ressourcehåndtering for forskellige klienter, såsom kubectl, Pulumi eller Terraform, GitOps samt skræddersyede scripts, der bruger klientbiblioteker.

Resumé

Jeg håber, at denne korte oversigt over forskellige måder at opdatere ressourcer i klynger har været nyttig for dig. Det er godt at vide, at modstanderne ikke blot er apply kontra replace, da man kan opdatere ressourcen ved hjælp af apply, edit, patch eller replace. I princippet har hver tilgang sit anvendelsesområde. For atomare ændringer er replace at foretrække, ellers bør man bruge strategic-merge patch gennem apply. I værste fald håber jeg, at du har forstået, at man ikke kan stole på Google eller StackOverflow, når man søger efter "kubernetes apply vs replace". I det mindste indtil denne artikel erstatter det nuværende svar.

Korrekt sammenligning af Kubernetes Apply, Replace og Patch

Kilde: habr.com

Køb pålidelig webhosting med DDoS-beskyttelse, VPS VDS-servere 🔥 Køb pålidelig webhosting med DDoS-beskyttelse, VPS VDS-servere | ProHoster