Richtiger Vergleich von Kubernetes Apply, Replacement und Patch

Kubernetes bietet mehrere Optionen zum Aktualisieren von Ressourcen: Anwenden, Bearbeiten, Patchen und Ersetzen. Es herrscht Unklarheit darüber, was die einzelnen Funktionen tun und wann sie eingesetzt werden sollen. Lass es uns herausfinden.

Richtiger Vergleich von Kubernetes Apply, Replacement und Patch

wenn googeln Der Ausdruck „Kubernetes anwenden vs. ersetzen“ befindet sich Antwort auf StackOverflow, was nicht korrekt ist. Beim Suchen „kubernetes apply vs patch“ Der erste Link ist die Dokumentation für kubectl patch, was keinen Vergleich beinhaltet apply и patch. In diesem Artikel werden die verschiedenen Optionen sowie deren ordnungsgemäße Verwendung erläutert.

Während des Lebenszyklus einer Kubernetes-Ressource (Dienst, Bereitstellung, Ingress usw.) müssen Sie manchmal einige Eigenschaften dieser Ressource ändern, hinzufügen oder entfernen. Fügen Sie beispielsweise eine Notiz hinzu oder erhöhen oder verringern Sie die Anzahl der Replikate.

Kubernetes-CLI

Wenn Sie bereits über die CLI mit Kubernetes-Clustern arbeiten, sind Sie damit bereits vertraut apply и edit. Mannschaft apply liest die Ressourcenspezifikation aus der Datei und führt einen „Upsert“ zum Kubernetes-Cluster durch, d. h. erstellt die Ressource, wenn sie nicht vorhanden ist, und aktualisiert sie, wenn sie vorhanden ist. Team edit liest eine Ressource über die API und schreibt dann die Ressourcenspezifikation in eine lokale Datei, die dann in einem Texteditor geöffnet wird. Nachdem Sie die Datei bearbeitet und gespeichert haben, kubectl sendet die vorgenommenen Änderungen über die API zurück, die diese Änderungen sorgfältig auf die Ressource anwendet.

Nicht jeder kennt die Befehle patch и replace. Mannschaft patch ermöglicht es Ihnen, einen Teil einer Ressourcenspezifikation zu ändern und nur den geänderten Teil in der Befehlszeile bereitzustellen. Team replace funktioniert genauso wie edit, aber alles muss manuell erledigt werden: Sie müssen die aktuelle Version der Ressourcenspezifikation herunterladen, beispielsweise mit kubectl get -o yaml, bearbeiten Sie es und verwenden Sie es dann replace um eine Ressource gemäß einer geänderten Spezifikation zu aktualisieren. Team replace funktioniert nicht, wenn zwischen dem Lesen und Ersetzen der Ressource Änderungen aufgetreten sind.

Kubernetes-API

Sie sind wahrscheinlich mit den Methoden vertraut CoreV1().Pods().Update(), replaceNamespacedService oder patch_namespaced_deployment, wenn Sie mit Clustern arbeiten über Client-Bibliothek für die Kubernetes-API mit einer Programmiersprache. Die Bibliothek verarbeitet diese Methoden über HTTP-Anfragen mithilfe der Methoden PUT и PATCH. In diesem Fall update и replace verwenden PUTUnd patch, egal wie trivial es auch sein mag, verwendet PATCH.

Es sollte angemerkt werden, dass kubectl Funktioniert auch mit Clustern über API. Mit anderen Worten, kubectlist ein Wrapper auf der Client-Bibliothek für die Go-Sprache, der neben den Standard-API-Funktionen weitgehend die Möglichkeit bietet, Unterbefehle in einer kompakteren und lesbareren Form bereitzustellen. Zum Beispiel, wie Sie vielleicht schon bemerkt haben, die Methode apply wurde oben im vorherigen Absatz nicht erwähnt. Derzeit (Mai 2020, ca. Übersetzer) alles Logik kubectl apply, d.h. Das Erstellen nicht vorhandener Ressourcen und das Aktualisieren vorhandener Ressourcen erfolgt vollständig auf der Codeseite kubectl. Es werden Anstrengungen unternommen zur Logikübertragung apply auf der API-Seite, aber es ist noch in der Beta-Phase. Ich werde weiter unten ausführlicher schreiben.

Standardmäßig patchen

Am besten verwendet patch, wenn Sie die Ressource aktualisieren möchten. Auf diese Weise funktionieren beide Client-Bibliotheken auf der Kubernetes-API und kubectl (nicht überraschend, da es sich um einen Wrapper für die Client-Bibliothek handelt, ca. Übersetzer).

Arbeiten Sie strategisch

Alle Mannschaften kubectl apply, edit и patch Verwenden Sie die Methode PATCH in HTTP-Anfragen zum Aktualisieren einer vorhandenen Ressource. Wenn Sie sich näher mit der Implementierung von Befehlen befassen, verwenden alle den Ansatz Strategisches Merge-Patching um Ressourcen zu aktualisieren, obwohl der Befehl patch kann andere Ansätze verwenden (mehr dazu weiter unten). Beim strategischen Merge-Patching-Ansatz wird versucht, „es richtig zu machen“, indem die bereitgestellte Spezifikation mit der vorhandenen Spezifikation zusammengeführt wird. Genauer gesagt wird versucht, sowohl Objekte als auch Arrays zu kombinieren, was bedeutet, dass die Änderungen tendenziell additiv sind. Beispiel: Ausführen des Befehls patch mit einer neuen Umgebungsvariablen in der Pod-Container-Spezifikation führt dazu, dass diese Umgebungsvariable zu den vorhandenen Umgebungsvariablen hinzugefügt wird, anstatt sie zu überschreiben. Um diesen Ansatz zu verwenden, müssen Sie den Parameterwert in der bereitgestellten Spezifikation auf Null setzen. Welches der Teams kubectl Ist es am besten zum Aktualisieren zu verwenden?

Wenn Sie Ihre Ressourcen erstellen und verwalten mit kubectl apply, beim Aktualisieren ist es besser, immer zu verwenden kubectl applyAuf kubectl konnte die Konfiguration verwalten und angeforderte Änderungen von Anwendung zu Anwendung korrekt verfolgen. Vorteil immer nutzen apply Der Vorteil liegt darin, dass es eine zuvor angewendete Spezifikation verfolgt und so weiß, wann Spezifikationseigenschaften und Array-Elemente explizit entfernt werden. Dies ermöglicht Ihnen die Verwendung apply um Eigenschaften und Array-Elemente zu entfernen, während eine normale strategische Zusammenführung nicht funktioniert. Mannschaften edit и patch Notizen nicht aktualisieren kubectl apply verwendet, um seine Änderungen zu verfolgen, also alle Änderungen, die über die Kubernetes-API verfolgt und vorgenommen, aber über Befehle vorgenommen werden edit и patch, unsichtbar für nachfolgende Befehle applyDas heißt, apply entfernt sie nicht, auch wenn sie nicht in der Eingabespezifikation für erscheinen apply (Die Dokumentation sagt das edit и patch Aktualisierungen der verwendeten Notizen vornehmen apply, aber in der Praxis - nein).

Wenn Sie den Befehl nicht verwenden apply, kann verwendet werden als editUnd patch, indem Sie den Befehl auswählen, der am besten zu der vorgenommenen Änderung passt. Beim Hinzufügen und Ändern von Stücklisteneigenschaften sind beide Ansätze ungefähr gleich. Beim Löschen von Spezifikationseigenschaften oder Array-Elementen edit verhält sich wie ein einmaliger Start apply, einschließlich der Verfolgung des Zustands der Spezifikation vor und nach der Bearbeitung, sodass Sie Eigenschaften und Array-Elemente explizit aus einer Ressource entfernen können. Sie müssen den Eigenschaftswert in der Spezifikation für explizit auf null setzen patchum es aus der Ressource zu entfernen. Das Entfernen eines Array-Elements mithilfe des strategischen Merge-Patchings ist komplexer, da hierfür Merge-Anweisungen erforderlich sind. Weitere praktikablere Alternativen finden Sie weiter unten in den anderen Upgrade-Ansätzen.

Um Aktualisierungsmethoden in der Clientbibliothek zu implementieren, die sich ähnlich wie die oben genannten Befehle verhalten kubectl, sollte in Anfragen festgelegt werden content-type в application/strategic-merge-patch+json. Wenn Sie Eigenschaften in einer Spezifikation entfernen möchten, müssen Sie deren Werte auf ähnliche Weise explizit auf Null setzen kubectl patch. Wenn Sie Array-Elemente entfernen müssen, sollten Sie Merge-Direktiven in die Update-Spezifikation aufnehmen oder einen anderen Ansatz für Updates verwenden.

Andere Ansätze für Updates

Kubernetes unterstützt zwei weitere Update-Ansätze: JSON-Merge-Patch и JSON-Patch. Der JSON-Merge-Patch-Ansatz verwendet eine teilweise Kubernetes-Spezifikation als Eingabe und unterstützt das Zusammenführen von Objekten ähnlich dem strategischen Merge-Patching-Ansatz. Der Unterschied zwischen den beiden besteht darin, dass nur der Array-Ersatz unterstützt wird, einschließlich des Container-Arrays in der Pod-Spezifikation. Das bedeutet, dass Sie bei Verwendung eines JSON-Merge-Patches vollständige Spezifikationen für alle Container bereitstellen müssen, falls sich eine Eigenschaft eines Containers ändert. Daher ist dieser Ansatz nützlich, um Elemente aus einem Array in einer Stückliste zu entfernen. In der Befehlszeile können Sie den JSON-Merge-Patch mit auswählen kubectl patch --type=merge. Wenn Sie mit der Kubernetes-API arbeiten, sollten Sie die Request-Methode verwenden PATCH und Installation content-type в application/merge-patch+json.

Der JSON-Patch-Ansatz stellt statt einer teilweisen Spezifikation einer Ressource die Änderungen, die Sie an der Ressource vornehmen möchten, als Array bereit, wobei jedes Element des Arrays eine Beschreibung der an der Ressource vorgenommenen Änderung darstellt. Dieser Ansatz ist eine flexiblere und leistungsfähigere Möglichkeit, die vorgenommenen Änderungen auszudrücken, allerdings auf Kosten der Auflistung der vorgenommenen Änderungen in einem separaten Nicht-Kubernetes-Format, anstatt eine teilweise Ressourcenspezifikation zu senden. IN kubectl Sie können den JSON-Patch mit auswählen kubectl patch --type=json. Bei Verwendung der Kubernetes-API funktioniert dieser Ansatz über die Request-Methode PATCH und Installation content-type в application/json-patch+json.

Wir brauchen Vertrauen – verwenden Sie Ersetzen

In manchen Fällen müssen Sie sicherstellen, dass zwischen dem Lesen der Ressource und der Aktualisierung keine Änderungen an einer Ressource vorgenommen werden. Mit anderen Worten: Sie sollten sicherstellen, dass alle Änderungen wirksam werden atomar. In diesem Fall sollten Sie zum Aktualisieren Ressourcen verwenden replace. Wenn Sie beispielsweise über eine ConfigMap mit einem Zähler verfügen, der von mehreren Quellen aktualisiert wird, sollten Sie sicherstellen, dass nicht zwei Quellen den Zähler gleichzeitig aktualisieren, wodurch die Aktualisierung verloren geht. Stellen Sie sich zur Veranschaulichung eine Abfolge von Ereignissen vor, die diesen Ansatz verwenden patch:

  • A und B erhalten den aktuellen Status der Ressource von der API
  • Jeder aktualisiert die Spezifikation lokal, indem er den Zähler um eins erhöht und außerdem „A“ bzw. „B“ zur Notiz „aktualisiert von“ hinzufügt
  • Und es aktualisiert die Ressource etwas schneller
  • B aktualisiert die Ressource

Dadurch geht Update A verloren. Letzte Operation patch gewinnt, wird der Zähler um eins statt um zwei erhöht, und der Wert der Notiz „aktualisiert von“ endet mit „B“ und enthält kein „A“. Vergleichen wir das oben Gesagte mit dem, was passiert, wenn Aktualisierungen mit diesem Ansatz durchgeführt werden replace:

  • A und B erhalten den aktuellen Status der Ressource von der API
  • Jeder aktualisiert die Spezifikation lokal, indem er den Zähler um eins erhöht und außerdem „A“ bzw. „B“ zur Notiz „aktualisiert von“ hinzufügt
  • Und es aktualisiert die Ressource etwas schneller
  • B versucht, die Ressource zu aktualisieren, aber die Aktualisierung wird von der API abgelehnt, da die Ressourcenversion in der Spezifikation enthalten ist replace stimmt nicht mit der aktuellen Version der Ressource in Kubernetes überein, da die Version der Ressource durch den Ersetzungsvorgang von A erhöht wurde.

Im obigen Fall muss B die Ressource erneut abrufen, Änderungen am neuen Status vornehmen und es erneut versuchen replace. Dadurch wird der Zähler um zwei erhöht und der Hinweis „Aktualisiert von“ enthält am Ende „AB“.

Das obige Beispiel impliziert dies bei der Ausführung replace Die gesamte Ressource wird vollständig ersetzt. Spezifikation verwendet für replace, darf nicht teilweise oder in Teilen wie in sein apply, aber vollständig, einschließlich der Ergänzung resourceVersion in die Spezifikationsmetadaten. Wenn Sie es nicht aktiviert haben resourceVersion oder die von Ihnen bereitgestellte Version nicht aktuell ist, wird der Ersatz abgelehnt. Der beste Ansatz ist also replace – Lesen Sie die Ressource, aktualisieren Sie sie und ersetzen Sie sie sofort. Benutzen kubectl, es könnte so aussehen:

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

Es ist erwähnenswert, dass die folgenden beiden Befehle, die nacheinander ausgeführt werden, erfolgreich ausgeführt werden, da deployment.yaml enthält keine Eigenschaft .metadata.resourceVersion

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

Dies scheint dem oben Gesagten zu widersprechen, d. h. „Hinzufügen resourceVersion in die Spezifikationsmetadaten.“ Ist es falsch, das zu sagen? Nein, ist es nicht, denn if kubectl bemerkt, dass Sie keine Angaben gemacht haben resourceVersion, liest es es aus der Ressource, fügt es der von Ihnen angegebenen Spezifikation hinzu und führt es erst dann aus replace. Da dies potenziell gefährlich ist, wenn man sich auf Atomizität verlässt, funktioniert die Magie völlig nebenbei kubectl, sollten Sie sich nicht darauf verlassen, wenn Sie Clientbibliotheken verwenden, die mit der API arbeiten. In diesem Fall müssen Sie die aktuelle Ressourcenspezifikation lesen, aktualisieren und dann ausführen PUT Anfrage.

Sie können keinen Patch machen – wir machen einen Ersatz

Manchmal müssen Sie einige Änderungen vornehmen, die von der API nicht verarbeitet werden können. In diesen Fällen können Sie den Austausch der Ressource erzwingen, indem Sie sie löschen und neu erstellen. Dies geschieht mit kubectl replace --force. Durch die Ausführung des Befehls werden die Ressourcen sofort entfernt und anschließend anhand der bereitgestellten Spezifikation neu erstellt. In der API gibt es keinen „Force-Replace“-Handler. Um dies über die API zu tun, müssen Sie zwei Vorgänge ausführen. Zuerst müssen Sie die Ressource löschen, indem Sie sie festlegen gracePeriodSeconds auf Null (0) und propagationPolicy in „Hintergrund“ und erstellen Sie dann diese Ressource mit der gewünschten Spezifikation neu.

Warnung: Dieser Ansatz ist potenziell gefährlich und kann zu einem undefinierten Zustand führen.

Auf der Serverseite anwenden

Wie oben erwähnt, arbeiten Kubernetes-Entwickler an der Implementierung der Logik apply von kubectl in der Kubernetes-API. Logiken apply Verfügbar in Kubernetes 1.18 über kubectl apply --server-side oder über die API mit der Methode PATCH с content-type application/apply-patch+YAML.

Hinweis: JSON ist auch gültiges YAML, sodass Sie die Spezifikation auch dann als JSON senden können content-type werden application/apply-patch+yaml.

Abgesehen von dieser Logik kubectl wird über die API für jedermann verfügbar, apply Verfolgt auf der Serverseite, wer für die Felder in der Spezifikation verantwortlich ist, und ermöglicht so einen sicheren Mehrfachzugriff für deren konfliktfreie Bearbeitung. Mit anderen Worten, wenn apply Auf der Serverseite wird es eine größere Verbreitung geben, eine universelle sichere Ressourcenverwaltungsschnittstelle für verschiedene Clients erscheinen, zum Beispiel Kubectl, Pulumi oder Terraform, GitOps, sowie selbst geschriebene Skripte unter Verwendung von Client-Bibliotheken.

Ergebnisse

Ich hoffe, dieser kurze Überblick über verschiedene Möglichkeiten zur Aktualisierung von Ressourcen in Clustern war hilfreich für Sie. Es ist gut zu wissen, dass es nicht nur um Anwenden oder Ersetzen geht; es ist auch möglich, eine Ressource durch Anwenden, Bearbeiten, Patchen oder Ersetzen zu aktualisieren. Denn grundsätzlich hat jeder Ansatz seinen eigenen Anwendungsbereich. Für atomare Änderungen ist „replace“ vorzuziehen; andernfalls sollten Sie den „Strategic-Merge-Patch“ über „Apply“ verwenden. Zumindest erwarte ich, dass Sie verstehen, dass Sie Google oder StackOerflow bei der Suche nach „Kubernetes anwenden vs. ersetzen“ nicht vertrauen können. Zumindest bis dieser Artikel die aktuelle Antwort ersetzt.

Richtiger Vergleich von Kubernetes Apply, Replacement und Patch

Source: habr.com

Kommentar hinzufügen