Richtiger Vergleich von Kubernetes Apply, Replace und Patch

Für Kubernetes gibt es mehrere Möglichkeiten, Ressourcen zu aktualisieren: apply, edit, patch und replace. Es herrscht Verwirrung darüber, was jeder von ihnen macht und wann man sie anwenden sollte. Lassen Sie uns das klären.

Richtiger Vergleich von Kubernetes Apply, Replace und Patch

Wenn in Google suchen den Begriff "kubernetes apply vs replace", gefunden eine Antwort auf StackOverflow, die nicht korrekt ist. Bei der Suche nach "kubernetes apply vs patch" ist der erste Link die Dokumentation zu kubectl patch, die keinen Vergleich enthält apply und patch. In diesem Artikel werden die verschiedenen Optionen sowie die richtige Verwendung jedes einzelnen behandelt.

Im Lebenszyklus einer Kubernetes-Ressource (Dienst, Deployment, Ingress usw.) muss manchmal eine Eigenschaft dieser Ressource geändert, hinzugefügt oder entfernt werden. Zum Beispiel, um eine Notiz hinzuzufügen oder die Anzahl der Replikate zu erhöhen oder zu reduzieren.

Kubernetes CLI

Wenn Sie bereits mit Kubernetes-Clustern über die CLI arbeiten, sind Sie bereits mit apply und bearbeiten. Der Befehl apply vertraut, das die Spezifikation einer Ressource aus einer Datei liest und ein "Upsert" im Kubernetes-Cluster durchführt, d.h. die Ressource erstellt, wenn sie nicht vorhanden ist, und sie aktualisiert, wenn sie existiert. Der Befehl bearbeiten liest die Ressource über die API und erstellt anschließend eine Spezifikation der Ressource in einer lokalen Datei, die dann in einem Texteditor geöffnet wird. Nachdem Sie die Datei bearbeitet und gespeichert haben, kubectl werden die vorgenommenen Änderungen über die API zurückgesendet, die sich um die Anwendung dieser Änderungen an der Ressource kümmert.

Nicht jeder kennt die Befehle patch und ersetzen. Der Befehl patch ermöglicht es, einen Teil der Spezifikation der Ressource zu ändern, indem nur der geänderte Teil in der Kommandozeile angegeben wird. Der Befehl ersetzen funktioniert genauso wie bearbeiten, aber alles muss manuell erledigt werden: Zuerst müssen Sie die aktuelle Version der Spezifikation der Ressource herunterladen, zum Beispiel mit kubectl get -o yaml, sie dann bearbeiten und schließlich ersetzen verwenden, um die Ressource mit der geänderten Spezifikation zu aktualisieren. Der Befehl ersetzen wird nicht funktionieren, wenn zwischen dem Lesen und Ersetzen der Ressource Änderungen aufgetreten sind.

Kubernetes API

Sie sind wahrscheinlich mit den Methoden CoreV1().Pods().Update(), replaceNamespacedService oder patch_namespaced_deployment, vertraut, wenn Sie mit Clustern über die Clientbibliothek für die Kubernetes API in einer Programmiersprache arbeiten. Die Bibliothek verarbeitet diese Methoden über HTTP-Anfragen, indem sie die Methoden eine und PATCHverwendet. Aktualisieren und ersetzen , um eine hohe Datensicherheit zu gewährleisten. eine, und patch, so banal it may seem, uses PATCH.

It is worth noting that kubectl also works with clusters via API. In other words, kubectl– this is a wrapper over the client library for the Go language, providing a greatly enhanced capability to deliver subcommands in a more compact and readable format, along with the standard API functionality. For example, as you may have noticed, the method apply was not mentioned in the previous paragraph. Currently (May 2020, Anm. der Übersetzer) all logic kubectl apply, i.e., the creation of non-existent resources and updating existing ones, operates entirely on the code side kubectl. Efforts are being made to transfer the logic apply to the API side, but this is still in beta testing. I will elaborate further below.

Patch by default

It is best to apply patch, if you wish to update a resource. This is how both the client libraries over the Kubernetes API and kubectl function (not surprisingly, as it is a wrapper for the client library, Anm. der Übersetzer).

Work strategically

All commands kubectl apply, bearbeiten und patch use the method PATCH in HTTP requests to update an existing resource. If we delve deeper into the implementation of the commands, all utilize the approach strategic-merge patching für die Aktualisierung von Ressourcen, obwohl das Team patch auch andere Ansätze verwenden kann (mehr dazu weiter unten). Der Ansatz des strategischen Merging-Patchings versucht, "alles richtig zu machen" beim Zusammenführen der bereitgestellten Spezifikation mit der bestehenden Spezifikation. Genauer gesagt, versucht er, sowohl Objekte als auch Arrays zusammenzuführen, was bedeutet, dass Änderungen in der Regel additiv sind. Zum Beispiel führt das Ausführen des Befehls patch mit einer neuen Umgebungsvariable in der Pod-Spezifikation dazu, dass diese Umgebungsvariable zu den bestehenden Umgebungsvariablen hinzugefügt wird, anstatt sie zu überschreiben. Um mit diesem Ansatz zu entfernen, sollte der Parameterwert in der bereitgestellten Spezifikation auf null gesetzt werden. Welche der Befehle kubectl ist am besten für die Aktualisierung geeignet?

Wenn Sie Ihre Ressourcen mithilfe von kubectl apply, ist es immer besser, bei der Aktualisierung kubectl applyzu verwenden, damit kubectl die Konfiguration verwalten und die angeforderten Änderungen von Anwendung zu Anwendung korrekt verfolgen kann. Der Vorteil, immer apply besteht darin, dass es die zuvor angewendete Spezifikation verfolgt, sodass es weiß, wann Spezifikationseigenschaften und Array-Elemente explizit entfernt werden. Dies ermöglicht die Nutzung apply zum Entfernen von Eigenschaften und Array-Elementen, während ein übliches strategisches Merging nicht funktionieren wird. Die Befehle bearbeiten und patch aktualisieren die Kommentare, die kubectl apply verwendet, um ihre Änderungen nachzuverfolgen, sodass alle Änderungen, die über die Kubernetes API nachverfolgt und vorgenommen werden, aber durch die Befehle, bearbeiten und patch, für nachfolgende Befehle unsichtbar sind. apply, das heißt apply entfernt sie nicht, selbst wenn sie nicht in der Eingangsspezifikation erscheinen für apply (In der Dokumentation steht, dass bearbeiten und patch die Kommentare aktualisieren, die apply, aber in der Praxis – tun sie dies nicht).

Wenn Sie den Befehl nicht verwenden apply, können sowohl bearbeiten, als auch patchverwendet werden, wobei der Befehl ausgewählt wird, der besser zu der umzusetzen Änderung passt. Beim Hinzufügen und Ändern von Spezifikationseigenschaften verhalten sich beide Ansätze ungefähr gleich. Beim Entfernen von Spezifikationseigenschaften oder Array-Elementen bearbeiten verhält sich wie ein einmaliger Aufruf. apply, einschließlich der Verfolgung, welche Spezifikation vor und nach der Bearbeitung gültig war, sodass Eigenschaften und Array-Elemente ausdrücklich aus der Ressource entfernt werden können. Der Wert einer Eigenschaft muss ausdrücklich auf null in der Spezifikation gesetzt werden, um patch, sie aus der Ressource zu entfernen. Das Entfernen eines Array-Elements mit strategischem Merging-Patching ist komplizierter, da Merge-Direktiven benötigt werden. Bitte beachten Sie die folgenden Alternativen für Updates, um akzeptablere Optionen auszuwählen.

Um in der Client-Bibliothek Update-Methoden zu implementieren, die sich ähnlich wie die oben genannten Befehle verhalten kubectl, sollten Sie in den Anfragen content-type in application/strategic-merge-patch+json. Wenn Sie Eigenschaften in der Spezifikation entfernen möchten, müssen Sie deren Werte ausdrücklich auf null setzen, ähnlich wie kubectl patch. Wenn Sie Array-Elemente entfernen möchten, sollten Sie Merge-Direktiven in die Update-Spezifikation einfügen oder einen anderen Aktualisierungsansatz verwenden.

Andere Aktualisierungsansätze

In Kubernetes werden zwei weitere Ansätze für Updates unterstützt: JSON-Merge-Patch und JSON-Patch. Der JSON-Merge-Patch-Ansatz akzeptiert eine partielle Kubernetes-Spezifikation als Eingabe und unterstützt das Merging von Objekten ähnlich wie der Ansatz des Strategic-Merge-Patchings. Der Unterschied zwischen ihnen besteht darin, dass nur die Ersetzung von Arrays unterstützt wird, einschließlich des Arrays von Containern in der Pod-Spezifikation. Das bedeutet, dass Sie beim Einsatz von JSON Merge Patch vollständige Spezifikationen für alle Container bereitstellen müssen, wenn Sie eine Eigenschaft eines Containers ändern. Somit ist dieser Ansatz nützlich, um Elemente aus einem Array in der Spezifikation zu entfernen. In der Kommandozeile können Sie JSON Merge Patch auswählen, indem Sie kubectl patch --type=merge. Bei der Arbeit mit der Kubernetes-API sollte die Anfrage-Methode verwendet werden PATCH und Festlegung content-type in application/merge-patch+json.

Der JSON-Patch-Ansatz verwendet anstelle der Bereitstellung einer teilweisen Ressourcenspezifikation die Bereitstellung von Änderungen, die Sie an der Ressource vornehmen möchten, in Form eines Arrays, wobei jedes Element des Arrays eine Beschreibung der Änderung darstellt, die an der Ressource vorgenommen wird. Dieser Ansatz ist flexibler und leistungsfähiger, um die vorgenommenen Änderungen auszudrücken, da die Liste der Änderungen in einem separaten, nicht Kubernetes-kompatiblen Format vorliegt, anstatt eine partielle Ressourcenspezifikation zu senden. kubectl Sie können JSON-Patch auswählen, indem Sie kubectl patch --type=jsonverwenden. Bei der Verwendung der Kubernetes-API funktioniert dieser Ansatz mit der Anfrage-Methode PATCH und Festlegung content-type in application/json-patch+json.

Brauchen Sie Sicherheit – verwenden Sie replace

In einigen Fällen ist es notwendig, sicherzustellen, dass zwischen dem Zeitpunkt des Lesens der Ressource und ihrem Update keine Änderungen an der Ressource vorgenommen werden. Mit anderen Worten, es muss sichergestellt werden, dass alle Änderungen atomarsind. In diesem Fall sollten Sie beim Aktualisieren von Ressourcen ersetzen. Wenn es zum Beispiel ein ConfigMap mit einem Zähler gibt, der von mehreren Quellen aktualisiert wird, sollte sichergestellt werden, dass nicht zwei Quellen den Zähler gleichzeitig aktualisieren, da dies zu einem Verlust von Aktualisierungen führen kann. Stellen Sie sich zur Veranschaulichung eine Ereignisfolge vor, die diesen Ansatz verwendet. patch:

  • A und B rufen den aktuellen Zustand der Ressource über die API ab.
  • Jeder aktualisiert lokal die Spezifikation, indem er den Zähler um eins erhöht und "A" oder "B" entsprechend in die Notiz "updated-by" hinzufügt.
  • A aktualisiert die Ressource etwas schneller.
  • B aktualisiert die Ressource.

Das Ergebnis ist, dass das Update von A verloren geht. Die letzte Operation patch gewinnt, der Zähler wird um eins erhöht anstatt um zwei, und der Wert der Notiz "updated-by" endet mit "B" und enthält kein "A". Lassen Sie uns das mit dem vergleichen, was passiert, wenn Updates unter Verwendung des Ansatzes ersetzen:

  • A und B rufen den aktuellen Zustand der Ressource über die API ab.
  • Jeder aktualisiert lokal die Spezifikation, indem er den Zähler um eins erhöht und "A" oder "B" entsprechend in die Notiz "updated-by" hinzufügt.
  • A aktualisiert die Ressource etwas schneller.
  • B versucht, die Ressource zu aktualisieren, aber das Update wird von der API abgelehnt, weil die Version der Ressource in der Spezifikation ersetzen nicht mit der aktuellen Version der Ressource in Kubernetes übereinstimmt, da die Version der Ressource bei der Ausführung einer Ersetzungsoperation von A erhöht wurde.

In dem oben genannten Fall muss B die Ressource erneut abrufen, Änderungen am neuen Zustand vornehmen und es erneut versuchen. ersetzenDadurch wird der Zähler um zwei erhöht, und die Bemerkung "updated-by" enthält am Ende "AB".

Das obige Beispiel impliziert, dass beim Ausführen von ersetzen eine vollständige Ersetzung der gesamten Ressource erfolgt. Die verwendete Spezifikation muss ersetzenvollständig sein, nicht teilweise wie in apply, sondern umfassend. Dies schließt das Hinzufügen von resourceVersion zu den Metadaten der Spezifikation ein. Wenn Sie dies nicht einschließen resourceVersion oder die von Ihnen angegebene Version nicht aktuell ist, wird die Ersetzung abgelehnt. Daher ist der beste Ansatz, ersetzen die Ressource zu lesen, sie zu aktualisieren und sie umgehend zu ersetzen. Mit kubectlkönnte es so aussehen:

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

Es ist bemerkenswert, dass die folgenden beiden Befehle, die nacheinander ausgeführt werden, erfolgreich sind, da deployment.yaml nicht die Eigenschaft .metadata.resourceVersion

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

offensichtlich im Widerspruch zu dem, was oben gesagt wurde, steht, nämlich "Hinzufügen resourceVersion in den Metadaten-Spezifikationen. Ist es falsch, das zu behaupten? Nein, das ist es nicht, denn wenn kubectl er bemerkt, dass Sie nicht angegeben haben, resourceVersion, wird er sie aus der Ressource lesen und zur von Ihnen angegebenen Spezifikation hinzufügen, und erst dann wird er den ersetzen. Da dies potenziell gefährlich ist, wenn man auf Atomizität vertraut, funktioniert diese Magie vollständig auf kubectl, sollten Sie sich nicht darauf verlassen, wenn Sie Client-Bibliotheken verwenden, die mit der API arbeiten. In diesem Fall müssen Sie die aktuelle Ressourcenspezifikation lesen, aktualisieren und dann den eine Antrag.

Patch kann nicht durchgeführt werden – wir ersetzen

Manchmal müssen einige Änderungen vorgenommen werden, die von der API nicht verarbeitet werden können. In diesen Fällen kann das Ressourcenkraft ersetzen, indem es sie löscht und neu erstellt. Dies geschieht mit kubectl replace --force. Das Ausführen des Kommandos löscht sofort die Ressourcen und erstellt sie dann mit der bereitgestellten Spezifikation neu. In der API gibt es keinen "ersatzzwang"-Handler, und um dies über die API zu tun, müssen zwei Operationen durchgeführt werden. Zuerst muss die Ressource gelöscht werden, indem gracePeriodSeconds auf null (0) gesetzt wird und propagationPolicy im Abschnitt „Hintergrund“ und dann diese Ressource mit der gewünschten Spezifikation neu erstellen.

Achtung: Dieser Ansatz ist potenziell riskant und kann zu einem undefinierten Zustand führen.

Apply auf Serverseite

Wie bereits erwähnt, arbeiten die Entwickler von Kubernetes an der Umsetzung der Logik apply von kubectl in der Kubernetes-API. Die Logik apply ist ab Kubernetes 1.18 über kubectl apply --server-side oder über die API unter Verwendung der Methode PATCH mit content-type application/apply-patch+YAML.

Hinweis: JSON ist ebenfalls ein gültiges YAML, sodass die Spezifikation auch im JSON-Format gesendet werden kann, selbst wenn content-type es application/apply-patch+yaml.

Darüber hinaus wird die Logik kubectl allen über die API zugänglich gemacht, apply wobei auf Serverseite die Verantwortlichen für die Felder in der Spezifikation überwacht werden, was einen sicheren Mehrfachzugriff für die konfliktfreie Bearbeitung ermöglicht. Mit anderen Worten, wenn apply auf Serverseite eine breitere Verwendung findet, wird eine universelle sichere Schnittstelle zur Verwaltung von Ressourcen für verschiedene Clients entstehen, wie zum Beispiel kubectl, Pulumi oder Terraform, GitOps sowie benutzerdefinierte Skripte, die Client-Bibliotheken verwenden.

Ergebnisse

Ich hoffe, dass dieser kurze Überblick über die verschiedenen Möglichkeiten zur Aktualisierung von Ressourcen in Clustern für Sie hilfreich war. Es ist wichtig zu wissen, dass es nicht nur Anwenden (apply) und Ersetzen (replace) gibt; Ressourcen können auch mit Anwenden (apply), Editieren (edit), Patchen (patch) oder Ersetzen (replace) aktualisiert werden. Jeder Ansatz hat seine eigene Anwendungsbereich. Für atomare Änderungen ist Ersetzen (replace) vorzuziehen, während in anderen Fällen strategisches Merging-Patching über Anwenden (apply) sinnvoller ist. Ich hoffe, Sie haben verstanden, dass man Google oder StackOverflow bei der Suche nach „kubernetes apply vs replace“ nicht blind vertrauen kann. Zumindest bis dieser Artikel die aktuellen Antworten ersetzt.

Richtiger Vergleich von Kubernetes Apply, Replace und Patch

Quelle: habr.com

Zuverlässiges Webhosting mit DDoS-Schutz, VPS- und VDS-Server kaufen 🔥 Zuverlässiges Webhosting mit DDoS-Schutz, VPS- und VDS-Server kaufen | ProHoster