Goede vergelijking van Kubernetes toepassen, vervangen en patchen

Kubernetes heeft verschillende opties voor het updaten van bronnen: toepassen, bewerken, patchen en vervangen. Er bestaat verwarring over wat ze allemaal doen en wanneer ze moeten worden gebruikt. Laten we het uitzoeken.

Goede vergelijking van Kubernetes toepassen, vervangen en patchen

als zoek op Google de zinsnede "kubernetes toepassen versus vervangen" bevindt zich antwoord op StackOverflow, wat niet juist is. Bij het zoeken "kubernetes apply vs patch" de eerste link is de documentatie voor kubectl patch, waarbij vergelijking niet is opgenomen apply и patch. In dit artikel worden de verschillende opties besproken, evenals het juiste gebruik ervan.

Tijdens de levenscyclus van een Kubernetes-resource (service, implementatie, inkomend verkeer, etc.) moet u soms enkele eigenschappen van deze resource wijzigen, toevoegen of verwijderen. Voeg bijvoorbeeld een notitie toe, verhoog of verlaag het aantal replica's.

Kubernetes-CLI

Als je al met Kubernetes-clusters werkt via de CLI, ben je er al bekend mee apply и edit. Team apply leest de resourcespecificatie uit het bestand en maakt een "upsert" naar het Kubernetes-cluster, d.w.z. maakt de resource aan als deze niet bestaat en werkt deze bij als deze wel bestaat. Team edit leest een bron via de API en schrijft vervolgens de bronspecificatie naar een lokaal bestand, dat vervolgens in een teksteditor wordt geopend. Nadat u het bestand hebt bewerkt en opgeslagen, kubectl stuurt de aangebrachte wijzigingen terug via de API, die deze wijzigingen zorgvuldig op de bron zal toepassen.

Niet iedereen kent de commando's patch и replace. Team patch Hiermee kunt u een deel van een resourcespecificatie wijzigen, waarbij alleen het gewijzigde deel op de opdrachtregel wordt weergegeven. Team replace werkt hetzelfde als edit, maar alles moet handmatig worden gedaan: u moet bijvoorbeeld de huidige versie van de bronspecificatie downloaden met behulp van kubectl get -o yaml, bewerk het en gebruik het vervolgens replace om een ​​hulpbron bij te werken volgens een gewijzigde specificatie. Team replace werkt niet als er wijzigingen zijn opgetreden tussen het lezen en vervangen van de bron.

Kubernetes-API

U kent de methoden waarschijnlijk wel CoreV1().Pods().Update(), replaceNamespacedService of patch_namespaced_deployment, als je met clusters werkt via clientbibliotheek voor Kubernetes API gebruik van een bepaalde programmeertaal. De bibliotheek verwerkt deze methoden via HTTP-verzoeken met behulp van de methoden PUT и PATCH... Waarin update и replace gebruik PUTEn patch, hoe triviaal het ook mag zijn, gebruikt PATCH.

Opgemerkt dat kubectl werkt ook met clusters via API. Met andere woorden, kubectlis een wrapper bovenop de clientbibliotheek voor de Go-taal, die grotendeels de mogelijkheid biedt om subopdrachten in een compactere en leesbare vorm aan te bieden naast de standaard API-mogelijkheden. Zoals je misschien al hebt gemerkt, de methode apply werd hierboven in de vorige paragraaf niet genoemd. Momenteel (mei 2020, ca. vertaler) allemaal logica kubectl apply, d.w.z. het creëren van niet-bestaande bronnen en het bijwerken van bestaande, werkt volledig aan de codekant kubectl. Er worden inspanningen geleverd over logische overdracht apply naar de API-kant, maar deze bevindt zich nog in de bètafase. Ik zal hieronder meer in detail schrijven.

Standaard patchen

Beste gebruikt patch, als u de bron wilt bijwerken. Dit is hoe beide clientbibliotheken bovenop de Kubernetes API werken kubectl (niet verrassend, aangezien het een wrapper is voor de clientbibliotheek, ca. vertaler).

Strategisch werken

Alle teams kubectl apply, edit и patch gebruik de methode PATCH in HTTP-verzoeken om een ​​bestaande bron bij te werken. Als je je meer in detail verdiept in de implementatie van commando's, dan gebruiken ze allemaal de aanpak strategische merge-patching om bronnen bij te werken, hoewel de opdracht patch kan andere benaderingen gebruiken (meer hierover hieronder). De strategische merge-patching-aanpak probeert het "goed te doen" door de geleverde specificatie samen te voegen met de bestaande specificatie. Meer specifiek probeert het zowel objecten als arrays te combineren, wat betekent dat de veranderingen vaak additief zijn. Bijvoorbeeld door de opdracht uit te voeren patch met een nieuwe omgevingsvariabele in de podcontainerspecificatie zorgt ervoor dat die omgevingsvariabele wordt toegevoegd aan de bestaande omgevingsvariabelen in plaats van deze te overschrijven. Als u deze aanpak wilt verwijderen, moet u de parameterwaarde in de opgegeven specificatie op nul zetten. Welke van de teams kubectl Is het het beste om te gebruiken voor het updaten?

Als u uw bronnen maakt en beheert met behulp van kubectl apply, bij het updaten is het beter om altijd te gebruiken kubectl applyNaar kubectl kan de configuratie beheren en de aangevraagde wijzigingen van applicatie tot applicatie op de juiste manier volgen. Voordeel altijd gebruiken apply is dat het een eerder toegepaste specificatie bijhoudt, waardoor het weet wanneer specificatie-eigenschappen en array-elementen expliciet worden verwijderd. Hierdoor kunt u gebruiken apply om eigenschappen en array-elementen te verwijderen, terwijl een normale strategische samenvoeging niet zal werken. Teams edit и patch notities niet bijwerken kubectl apply gebruikt om de wijzigingen bij te houden, dus alle wijzigingen die worden bijgehouden en aangebracht via de Kubernetes API, maar gemaakt via opdrachten edit и patch, onzichtbaar voor volgende opdrachten applyDat wil zeggen, apply verwijdert ze niet, ook al verschijnen ze niet in de invoerspecificatie voor apply (De documentatie zegt dat edit и patch updates aanbrengen in de gebruikte notities apply, maar in de praktijk - nee).

Als u het commando niet gebruikt apply, kan worden gebruikt als editEn patch, waarbij u de opdracht kiest die het beste past bij de wijziging die wordt aangebracht. Bij het toevoegen en wijzigen van stuklijsteigenschappen zijn beide benaderingen grofweg hetzelfde. Bij het verwijderen van specificatie-eigenschappen of array-elementen edit gedraagt ​​zich als een eenmalige lancering apply, inclusief het bijhouden van hoe de specificatie eruitzag vóór en nadat deze werd bewerkt, zodat u eigenschappen en array-elementen expliciet uit een bron kunt verwijderen. U moet de eigenschapswaarde expliciet instellen op null in de specificatie voor patchom het uit de bron te verwijderen. Het verwijderen van een array-element met behulp van strategische merge-patching is complexer omdat hiervoor het gebruik van merge-richtlijnen vereist is. Zie andere upgradebenaderingen hieronder voor meer haalbare alternatieven.

Om updatemethoden in de clientbibliotheek te implementeren die zich op dezelfde manier gedragen als de bovenstaande opdrachten kubectl, moet worden ingesteld in verzoeken content-type в application/strategic-merge-patch+json. Als u eigenschappen uit een specificatie wilt verwijderen, moet u hun waarden op een vergelijkbare manier expliciet op null instellen kubectl patch. Als u array-elementen moet verwijderen, moet u samenvoegrichtlijnen opnemen in de updatespecificatie of een andere benadering van updates gebruiken.

Andere benaderingen van updates

Kubernetes ondersteunt twee andere updatebenaderingen: JSON-samenvoegpatch и JSON-patch. De JSON merge patch-aanpak gebruikt een gedeeltelijke Kubernetes-specificatie als invoer en ondersteunt het samenvoegen van objecten, vergelijkbaar met de strategische merge-patching-aanpak. Het verschil tussen de twee is dat het alleen array-vervanging ondersteunt, inclusief de containerarray in de pod-specificatie. Dit betekent dat u bij het gebruik van een JSON-mergepatch de volledige specificaties voor alle containers moet opgeven voor het geval een eigenschap van een container verandert. Deze aanpak is dus handig voor het verwijderen van elementen uit een array in een stuklijst. Op de opdrachtregel kunt u JSON merge patch selecteren met behulp van kubectl patch --type=merge. Wanneer u met de Kubernetes API werkt, moet u de verzoekmethode gebruiken PATCH en installatie content-type в application/merge-patch+json.

De JSON-patchbenadering maakt, in plaats van een gedeeltelijke specificatie van een bron te verstrekken, gebruik van het verstrekken van de wijzigingen die u aan de bron wilt aanbrengen als een array, waarbij elk element van de array een beschrijving vertegenwoordigt van de wijziging die in de bron wordt aangebracht. Deze aanpak is een flexibelere en krachtigere manier om de aangebrachte wijzigingen tot uitdrukking te brengen, maar gaat ten koste van het vermelden van de aangebrachte wijzigingen in een afzonderlijk, niet-Kubernetes-formaat, in plaats van het verzenden van een gedeeltelijke resourcespecificatie. IN kubectl u kunt JSON-patch selecteren met behulp van kubectl patch --type=json. Bij gebruik van de Kubernetes API werkt deze aanpak met behulp van de verzoekmethode PATCH en installatie content-type в application/json-patch+json.

We hebben vertrouwen nodig - gebruik vervangen

In sommige gevallen moet u er zeker van zijn dat er geen wijzigingen worden aangebracht in een resource tussen het moment waarop de resource wordt gelezen en het moment waarop deze wordt bijgewerkt. Met andere woorden, u moet ervoor zorgen dat alle wijzigingen doorgevoerd worden atomair. In dit geval moet u de bronnen bijwerken die u moet gebruiken replace. Als u bijvoorbeeld een ConfigMap heeft met een teller die door meerdere bronnen wordt bijgewerkt, moet u er zeker van zijn dat twee bronnen de teller niet tegelijkertijd bijwerken, waardoor de update verloren gaat. Om dit te demonstreren, stel je een reeks gebeurtenissen voor met behulp van de aanpak patch:

  • A en B krijgen de huidige status van de bron van de API
  • Iedereen werkt de specificatie lokaal bij door de teller met één te verhogen en ook respectievelijk "A" of "B" toe te voegen aan de notitie "bijgewerkt door".
  • En het werkt de bron iets sneller bij
  • B werkt de bron bij

Als gevolg hiervan gaat update A verloren. Laatste operatie patch wint, de teller wordt verhoogd met één in plaats van twee, en de waarde van de "bijgewerkt door"-noot eindigt met "B" en bevat geen "A". Laten we het bovenstaande vergelijken met wat er gebeurt als er updates worden uitgevoerd met behulp van deze aanpak replace:

  • A en B krijgen de huidige status van de bron van de API
  • Iedereen werkt de specificatie lokaal bij door de teller met één te verhogen en ook respectievelijk "A" of "B" toe te voegen aan de notitie "bijgewerkt door".
  • En het werkt de bron iets sneller bij
  • B probeert de bron bij te werken, maar de update wordt door de API afgewezen omdat de bronversie in de specificatie staat replace komt niet overeen met de huidige versie van de bron in Kubernetes, omdat de versie van de bron is vergroot door de vervangingsbewerking van A.

In het bovenstaande geval zal B de bron opnieuw moeten ophalen, wijzigingen moeten aanbrengen in de nieuwe status en het opnieuw moeten proberen replace. Dit zorgt ervoor dat de teller met twee wordt verhoogd en dat de "bijgewerkt door"-noot aan het einde "AB" bevat.

Het bovenstaande voorbeeld impliceert dat bij het uitvoeren replace De gehele hulpbron wordt volledig vervangen. Specificatie gebruikt voor replace, mag niet gedeeltelijk zijn, of in delen zoals in apply, maar compleet, inclusief de toevoeging resourceVersion in de specificatiemetagegevens. Als je dit niet hebt ingeschakeld resourceVersion of de door u verstrekte versie is niet actueel, de vervanging wordt afgewezen. De beste aanpak is dus replace – lees de bron, update deze en vervang deze onmiddellijk. Gebruik makend van kubectl, het zou er zo uit kunnen zien:

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

Het is vermeldenswaard dat de volgende twee opdrachten, die opeenvolgend worden uitgevoerd, sindsdien met succes zullen worden uitgevoerd deployment.yaml bevat geen eigendom .metadata.resourceVersion

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

Dit lijkt in strijd te zijn met wat hierboven is gezegd, d.w.z. "toevoegen resourceVersion in de metagegevens van de specificatie." Is het verkeerd om dat te zeggen? Nee, dat is niet zo, want als kubectl mededelingen die u niet heeft opgegeven resourceVersion, zal het het uit de bron lezen en toevoegen aan de door u opgegeven specificatie, en het dan pas uitvoeren replace. Omdat dit potentieel gevaarlijk is als je op atomiciteit vertrouwt, werkt de magie volledig zijdelings kubectl, moet u er niet op vertrouwen als u clientbibliotheken gebruikt die met de API werken. In dit geval moet u de huidige resourcespecificatie lezen, bijwerken en vervolgens uitvoeren PUT verzoek.

Je kunt geen patch uitvoeren – wij doen een vervanging

Soms moet u enkele wijzigingen aanbrengen die niet door de API kunnen worden afgehandeld. In deze gevallen kunt u vervanging van de bron afdwingen door deze te verwijderen en opnieuw te maken. Dit gebeurt met behulp van kubectl replace --force. Als u de opdracht uitvoert, worden de bronnen onmiddellijk verwijderd en vervolgens opnieuw gemaakt op basis van de opgegeven specificatie. Er is geen 'force replacement'-handler in de API, en om dit via de API te doen, moet u twee bewerkingen uitvoeren. Eerst moet u de bron verwijderen door deze in te stellen gracePeriodSeconds naar nul (0) en propagationPolicy in “Achtergrond” en maak vervolgens deze bron opnieuw met de gewenste specificatie.

Waarschuwing: deze aanpak is potentieel gevaarlijk en kan leiden tot een ongedefinieerde toestand.

Toepassen aan de serverzijde

Zoals hierboven vermeld, werken Kubernetes-ontwikkelaars aan de implementatie van de logica apply van kubectl in de Kubernetes-API. Logica apply beschikbaar in Kubernetes 1.18 via kubectl apply --server-side of via de API met behulp van de methode PATCH с content-type application/apply-patch+YAML.

Opmerking: JSON is ook geldige YAML, dus u kunt de specificatie zelfs als JSON verzenden content-type zullen application/apply-patch+yaml.

Naast die logica kubectl wordt voor iedereen beschikbaar via API, apply aan de serverzijde wordt bijgehouden wie verantwoordelijk is voor de velden in de specificatie, waardoor veilige meervoudige toegang mogelijk is voor conflictvrije bewerking. Met andere woorden: als apply aan de serverkant zal het steeds wijdverspreider worden, er zal een universele, veilige interface voor resourcebeheer verschijnen voor verschillende clients, bijvoorbeeld kubectl, Pulumi of Terraform, GitOps, evenals zelfgeschreven scripts die gebruik maken van clientbibliotheken.

Resultaten van

Ik hoop dat dit korte overzicht van verschillende manieren om bronnen in clusters bij te werken nuttig voor u was. Het is goed om te weten dat het niet slechts een kwestie van toepassen versus vervangen is; het is mogelijk om een ​​bron bij te werken met behulp van toepassen, bewerken, patchen of vervangen. Iedere aanpak heeft immers in principe zijn eigen toepassingsgebied. Voor atomaire veranderingen verdient vervangen de voorkeur; anders moet u de strategische merge-patch gebruiken via apply. Ik verwacht op zijn minst dat u begrijpt dat u Google of StackOerflow niet kunt vertrouwen bij het zoeken naar "kubernetes apply vs Replace". In ieder geval totdat dit artikel het huidige antwoord vervangt.

Goede vergelijking van Kubernetes toepassen, vervangen en patchen

Bron: www.habr.com

Voeg een reactie