{"id":53120,"date":"2019-11-24T00:00:00","date_gmt":"2019-11-23T21:00:00","guid":{"rendered":"https:\/\/prohoster.info\/blog\/blog_prohoster\/3-way-merge-v-werf-deploj-v-kubernetes-s-helm-na-steroidah"},"modified":"2020-02-18T14:00:59","modified_gmt":"2020-02-18T11:00:59","slug":"3-way-merge-v-werf-deploj-v-kubernetes-s-helm-na-steroidah","status":"publish","type":"post","link":"https:\/\/prohoster.info\/de\/blog\/administrirovanie\/3-way-merge-v-werf-deploj-v-kubernetes-s-helm-na-steroidah","title":{"rendered":"3-way merge in werf: Deployment in Kubernetes mit Helm 'auf Steroiden'","gt_translate_keys":[{"key":"rendered","format":"text"}]},"content":{"rendered":"<p>Es ist geschehen, worauf wir (und nicht nur wir) lange gewartet haben: <noindex><a rel=\"nofollow\" href=\"https:\/\/werf.io\/\">werf<\/a><\/noindex>, unser Open Source-Tool zur Erstellung von Anwendungen und deren Bereitstellung in Kubernetes unterst\u00fctzt jetzt die Anwendung von \u00c4nderungen mit 3-Way-Merge-Patches! Dar\u00fcber hinaus gibt es die M\u00f6glichkeit, vorhandene K8s-Ressourcen in Helm-Releases zu \u00fcbernehmen, ohne diese Ressourcen neu zu erstellen.<\/p>\n<p><img decoding=\"async\" alt=\"3-way merge in werf: Deployment in Kubernetes mit Helm &#039;auf Steroiden&#039;\" src=\"\/wp-content\/uploads\/2019\/11\/e5be3544c201f7b2c97fba216a49506d.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nKurz gesagt, wir setzen <code>WERF_THREE_WAY_MERGE=enabled<\/code> \u2014 und erhalten ein Deployment \u201ewie in <code>kubectl apply<\/code>\u201c, das mit bestehenden Installationen auf Helm 2 kompatibel ist und sogar noch etwas mehr.<\/p>\n<p>Doch lass uns mit der Theorie beginnen: Was sind 3-Way-Merge-Patches, wie kamen die Menschen zu dem Ansatz ihrer Generierung und warum sind sie wichtig in CI\/CD-Prozessen mit Infrastruktur basierend auf Kubernetes? Danach sehen wir uns an, was 3-Way-Merge in werf ist, welche Modi standardm\u00e4\u00dfig verwendet werden und wie man damit umgeht.<noindex><a rel=\"nofollow\" name=\"habracut\"><\/a><\/noindex><\/p>\n<h2>Was ist ein 3-Way-Merge-Patch?<\/h2>\n<p>\nBeginnen wir mit der Aufgabe, Ressourcen, die in YAML-Manifests beschrieben sind, in Kubernetes bereitzustellen.<\/p>\n<p>F\u00fcr die Arbeit mit Ressourcen bietet das Kubernetes-API die grundlegenden Operationen: create, patch, replace und delete. Es wird angenommen, dass man mit ihnen einen kontinuierlichen Rollout von Ressourcen in den Cluster konstruieren kann. Wie?<\/p>\n<h3>Imperative kubectl-Befehle<\/h3>\n<p>\nDer erste Ansatz zur Verwaltung von Objekten in Kubernetes ist die Verwendung imperativer kubectl-Befehle zum Erstellen, \u00c4ndern und L\u00f6schen dieser Objekte. Einfach gesagt:<\/p>\n<ul>\n<li> Wir setzen ein eigenes Passwort f\u00fcr den Benutzer <code>kubectl run<\/code> kann ein Deployment oder Job starten:\n<pre><code class=\"bash\">kubectl run --generator=deployment\/apps.v1 DEPLOYMENT_NAME --image=IMAGE<\/code><\/pre>\n<\/li>\n<li> Wir setzen ein eigenes Passwort f\u00fcr den Benutzer <code>kubectl scale<\/code> \u2014 \u00e4ndert die Anzahl der Replikate:\n<pre><code class=\"bash\">kubectl scale --replicas=3 deployment\/mysql<\/code><\/pre>\n<\/li>\n<li>usw.<\/li>\n<\/ul>\n<p>\nDieser Ansatz mag auf den ersten Blick bequem erscheinen. Es gibt jedoch Probleme: <\/p>\n<ol>\n<li> Es ist schwierig, <b>automatisieren<\/b>.<\/li>\n<li> Wie <b>die Konfiguration<\/b> in Git widerzuspiegeln? Wie macht man die \u00dcberpr\u00fcfung der \u00c4nderungen, die im Cluster stattfinden?<\/li>\n<li> Wie stellt man sicher, <b>Reproduzierbarkeit<\/b> dass die Konfiguration beim Neustart erhalten bleibt?<\/li>\n<li>\u2026<\/li>\n<\/ol>\n<p>\nEs wird klar, dass dieser Ansatz schlecht mit der Speicherung des Codes der Anwendung und Infrastruktur als Code (IaC; oder sogar <noindex><a rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/company\/flant\/blog\/458878\/\">GitOps<\/a><\/noindex> als die modernere Variante, die in der Kubernetes-\u00d6kosystem an Popularit\u00e4t gewinnt) kombiniert werden kann. Daher erhielt dieser Befehlsansatz in kubectl keine weitere Entwicklung.<\/p>\n<h3>Die Operationen create, get, replace und delete<\/h3>\n<p>\nBei der anf\u00e4nglichen <b>Erstellung<\/b> ist alles einfach: Wir senden das Manifest an die <code>create<\/code> kube API und die Ressource wird erstellt. Die YAML-Darstellung des Manifests kann in Git gespeichert werden, und zur Erstellung kann der Befehl <code>kubectl create -f manifest.yaml<\/code>.<\/p>\n<p>C <b>und das L\u00f6schen<\/b> ist ebenfalls einfach: Wir setzen dasselbe <code>manifest.yaml<\/code> aus Git in den Befehl ein: <code>kubectl delete -f manifest.yaml<\/code>.<\/p>\n<p>Operation <b><code>replace<\/code><\/b> erm\u00f6glicht es, die Ressourcenkonfiguration vollst\u00e4ndig durch eine neue zu ersetzen, ohne die Ressource neu zu erstellen. Das bedeutet, dass es sinnvoll ist, vor einer \u00c4nderung an der Ressource die aktuelle Version abzufragen, <code>get<\/code>, diese zu \u00e4ndern und sie dann zu aktualisieren. <code>replace<\/code>Im kube-apiserver ist <noindex><a rel=\"nofollow\" href=\"https:\/\/en.wikipedia.org\/wiki\/Optimistic_concurrency_control\">optimistisches Locking<\/a><\/noindex> implementiert und, wenn sich das Objekt nach der Operation <code>get<\/code> ge\u00e4ndert hat, schl\u00e4gt die Operation <code>replace<\/code> fehl.<\/p>\n<p>Um die Konfiguration in Git zu speichern und mit replace zu aktualisieren, muss man die Operation <code>get<\/code>, die Konfiguration aus Git mit dem, was wir erhalten haben, mergen und <code>replace<\/code>ausf\u00fchren. Standardm\u00e4\u00dfig erlaubt kubectl nur die Verwendung des Befehls <code>kubectl replace -f manifest.yaml<\/code><header> <code>manifest.yaml<\/code> \u2014 ein bereits vollst\u00e4ndig vorbereiteter (in unserem Fall gemergter) Manifest, der installiert werden muss. Das bedeutet, der Benutzer muss die Manifestdateien mergen, was keine triviale Angelegenheit ist\u2026<\/p>\n<p>Es sei auch erw\u00e4hnt, dass obwohl <code>manifest.yaml<\/code> in Git gespeichert wird, wir nicht im Voraus wissen k\u00f6nnen, ob ein Objekt erstellt oder aktualisiert werden muss \u2014 das muss die benutzerspezifische Software erledigen.<\/p>\n<p>Insgesamt: <b>k\u00f6nnen wir ein kontinuierliches Deployment<\/b> nur mit create, replace und delete sicherstellen und die Konfiguration der Infrastruktur zusammen mit dem Code in Git speichern und ein bequemes CI\/CD bereitstellen?<\/p>\n<p>Im Prinzip k\u00f6nnen wir\u2026 Daf\u00fcr <b>muss die Merge-Operation<\/b> der Manifeste und eine Art Wrapper implementiert werden, der:<\/p>\n<ul>\n<li> die Existenz des Objekts im Cluster \u00fcberpr\u00fcft,<\/li>\n<li> die Erstcreation der Ressource durchf\u00fchrt,<\/li>\n<li> sie aktualisiert oder entfernt.<\/li>\n<\/ul>\n<p>\nBei einer Aktualisierung muss ber\u00fccksichtigt werden, dass <i>die Ressource sich ge\u00e4ndert haben k\u00f6nnte<\/i> seit dem letzten <code>get<\/code> und den Fall des optimistischen Lockings automatisch bearbeiten \u2014 Wiederholungsversuche zur Aktualisierung durchf\u00fchren.<\/p>\n<p>Aber warum das Rad neu erfinden, wenn kube-apiserver einen anderen Weg bietet, Ressourcen zu aktualisieren: die Operation <code>patch<\/code>, die dem Benutzer einen Teil der beschriebenen Probleme abnimmt?<\/p>\n<h3>Patch<\/h3>\n<p>\nJetzt sind wir bei den Patches angekommen.<\/p>\n<p>Patches sind der Hauptweg, um \u00c4nderungen an vorhandenen Objekten in Kubernetes anzuwenden. Die Operation <code>patch<\/code> funktioniert so, dass der Benutzer des kube-apiserver einen Patch im JSON-Format senden und das Objekt angeben muss,<\/p>\n<ul>\n<li> und der apiserver selbst den aktuellen Zustand des Objekts analysiert und es in die gew\u00fcnschte Form bringt.<\/li>\n<li> Optimistisches Locking ist in diesem Fall nicht erforderlich. Diese Operation ist deklarativer als replace, obwohl es zun\u00e4chst anders erscheinen mag.<\/li>\n<\/ul>\n<p>\nSomit:<\/p>\n<p>mit der Operation<\/p>\n<ul>\n<li> erstellen wir ein Objekt aus dem Manifest in Git, <code>create<\/code> \u2014 l\u00f6schen wir, wenn das Objekt nicht mehr ben\u00f6tigt wird,<\/li>\n<li> mit <code>delete<\/code> \u2014 \u00e4ndern wir das Objekt und bringen es in die Form, die in Git beschrieben wird.<\/li>\n<li> mit <code>patch<\/code> \u2014 Wir \u00e4ndern das Objekt und bringen es in die im Git beschriebene Form.<\/li>\n<\/ul>\n<p>\nUm dies zu tun, muss jedoch <i>der richtige Patch erstellt werden<\/i>!<\/p>\n<h3>Wie Patches in Helm 2 funktionieren: 2-Wege-Merge<\/h3>\n<p>\nBei der ersten Installation des Helm-Releases f\u00fchrt Helm einen <code>create<\/code> f\u00fcr die Chart-Ressourcen durch.<\/p>\n<p>Beim Aktualisieren des Helm-Releases:<\/p>\n<ul>\n<li> berechnet es den Patch zwischen der Ressourcenversion aus dem vorherigen Chart und der aktuellen Version des Charts,<\/li>\n<li> und wendet diesen Patch an.<\/li>\n<\/ul>\n<p>\nDiesen Patch nennen wir <b>2-Wege-Merge-Patch<\/b>, weil bei dessen Erstellung 2 Manifeste beteiligt sind:<\/p>\n<ul>\n<li> das Manifest der Ressource aus dem vorherigen Release,<\/li>\n<li> das Manifest der Ressource aus der aktuellen Ressource.<\/li>\n<\/ul>\n<p>\nBei der L\u00f6schung wird die Operation <code>delete<\/code> im Kube-API-Server f\u00fcr Ressourcen aufgerufen, die im vorherigen Release deklariert wurden, aber nicht im aktuellen.<\/p>\n<p>Der Ansatz mit dem 2-Wege-Merge-Patch hat ein Problem: Er f\u00fchrt zu <b>einer Dissoziation des tats\u00e4chlichen Zustands der Ressource im Cluster und des Manifests in Git.<\/b>.<\/p>\n<h3>Eine Illustration des Problems anhand von<\/h3>\n<p><\/p>\n<ul>\n<li> In Git wird im Chart ein Manifest gespeichert, in dem das Feld <code>Image<\/code> in der Deployment den Wert <code>ubuntu:18.04<\/code>.<\/li>\n<li> Der Benutzer hat \u00fcber <code>kubectl edit<\/code> den Wert dieses Feldes auf <code>ubuntu:19.04<\/code>.<\/li>\n<li> ge\u00e4ndert. <i>Beim erneuten Deployment des Helm-Charts<\/i>wird kein Patch generiert, <code>Image<\/code> da das Feld<\/li>\n<li> in der vorherigen Version des Releases und im aktuellen Chart gleich sind. <code>Image<\/code> Nach dem erneuten Deployment <code>ubuntu:19.04<\/code>bleibt <code>ubuntu:18.04<\/code>.<\/li>\n<\/ul>\n<p>\n, obwohl im Chart steht,<\/p>\n<h3>Wir haben eine Desynchronisierung erfahren und die Deklarativit\u00e4t verloren.<\/h3>\n<p>\nIm Allgemeinen gilt, <i>Was ist eine synchronisierte Ressource?<\/i> Eine vollst\u00e4ndige<\/p>\n<p>\u00dcbereinstimmung des Ressourcenmanifests im laufenden Cluster und des Manifests aus Git ist unm\u00f6glich. Denn im tats\u00e4chlichen Manifest k\u00f6nnen Verwaltungsannotation\/Labels, zus\u00e4tzliche Container und andere Daten enthalten sein, die dynamisch von bestimmten Controllern hinzugef\u00fcgt und entfernt werden. Diese Daten m\u00f6chten wir nicht in Git speichern. Allerdings m\u00f6chten wir, dass beim Deployment die Felder, die wir ausdr\u00fccklich in Git angegeben haben, die entsprechenden Werte annehmen. <b>Es ergibt sich also die allgemeine<\/b>Regel f\u00fcr synchronisierte Ressourcen:<\/p>\n<h3>Beim Deployment einer Ressource d\u00fcrfen nur die Felder ge\u00e4ndert oder entfernt werden, die eindeutig im Manifest aus Git aufgef\u00fchrt sind (oder in der vorherigen Version aufgef\u00fchrt waren und jetzt entfernt wurden).<\/h3>\n<p>\nDie Grundidee <noindex><a rel=\"nofollow\" href=\"https:\/\/en.wikipedia.org\/wiki\/Merge_(version_control)#Three-way_merge\">Beim Deployment einer Ressource d\u00fcrfen nur die Felder ge\u00e4ndert oder entfernt werden, die eindeutig im Manifest aus Git aufgef\u00fchrt sind (oder in der vorherigen Version aufgef\u00fchrt waren und jetzt entfernt wurden).<\/a><\/noindex>Der 3-Wege-Merge-Patch:<\/p>\n<ul>\n<li> Ein Patch wird zwischen der zuletzt angewendeten Version des Manifests aus Git und der Zielversion des Manifests aus Git unter Ber\u00fccksichtigung der aktuellen Version des Manifests im laufenden Cluster generiert. Der endg\u00fcltige Patch muss der Regel f\u00fcr synchronisierte Ressourcen entsprechen:<\/li>\n<li> Fr\u00fchere vorhandene Felder in der letzten angewendeten Version, die nicht in der Zielversion vorhanden sind, werden mittels eines Patches auf null gesetzt;<\/li>\n<li> Felder in der aktuellen Version des Objekts, die sich von der Zielversion des Manifests unterscheiden, werden mit einem Patch aktualisiert.<\/li>\n<\/ul>\n<p>\nSo generiert das System Patches. <code>kubectl apply<\/code>:<\/p>\n<ul>\n<li> Die letzte angewendete Version des Manifests wird in der Annotation des Objekts gespeichert, <\/li>\n<li> die Zielversion wird aus der angegebenen YAML-Datei entnommen,<\/li>\n<li> die aktuelle aus dem laufenden Cluster.<\/li>\n<\/ul>\n<p>\nJetzt, da wir die Theorie gekl\u00e4rt haben, wollen wir erz\u00e4hlen, was wir bei werf gemacht haben.<\/p>\n<h2>Anwendung von \u00c4nderungen in werf<\/h2>\n<p>\nFr\u00fcher verwendete werf, \u00e4hnlich wie Helm 2, 2-Way-Merge-Patches.<\/p>\n<h3>Repair-Patch<\/h3>\n<p>\nUm auf die neue Art der Patches, die 3-Way-Merge-Patches, umzusteigen, haben wir als ersten Schritt die sogenannten <b>Repair-Patches<\/b>.<\/p>\n<p>verwendet. Bei der Bereitstellung wird ein standardm\u00e4\u00dfiger 2-Way-Merge-Patch verwendet, aber werf generiert zus\u00e4tzlich einen Patch, der den aktuellen Zustand der Ressource mit dem synchronisiert, was in Git geschrieben steht (dieser Patch wird unter Verwendung derselben Regel der synchronisierten Ressource erstellt, die oben beschrieben wurde).<\/p>\n<p>Im Falle einer Desynchronisierung erh\u00e4lt der Benutzer am Ende der Bereitstellung eine WARNUNG mit einer entsprechenden Nachricht und dem Patch, der angewendet werden muss, um die Ressource in den synchronisierten Zustand zu versetzen. Dieser Patch wird auch in einer speziellen Annotation aufgezeichnet <code>werf.io\/repair-patch<\/code>. Es wird davon ausgegangen, dass der Benutzer manuell <b>selbst<\/b> diesen Patch anwendet: werf wird ihn aus Prinzip nicht anwenden.<\/p>\n<p>Die Generierung von Repair-Patches ist eine vor\u00fcbergehende Ma\u00dfnahme, die es erm\u00f6glicht, das Erstellen von Patches nach dem Prinzip des 3-Way-Merge praktisch zu testen, jedoch werden diese Patches nicht automatisch angewendet. Derzeit ist dieser Betriebsmodus standardm\u00e4\u00dfig aktiviert.<\/p>\n<h3>3-Way-Merge-Patch nur f\u00fcr neue Releases<\/h3>\n<p>\nAb dem 1. Dezember 2019 beginnen die Beta- und Alpha-Versionen von werf, vollst\u00e4ndige 3-Way-Merge-Patches zur Anwendung von \u00c4nderungen nur f\u00fcr neue Helm-Releases, die \u00fcber werf ausgerollt werden, zu verwenden. Bereits bestehende Releases werden weiterhin den Ansatz mit 2-Way-Merge + Repair-Patches verwenden. <b>standardm\u00e4\u00dfig<\/b> Dieser Betriebsmodus kann ausdr\u00fccklich durch die Einstellung aktiviert werden<\/p>\n<p>WERF_THREE_WAY_MERGE_MODE=onlyNewReleases <code>: Die Funktion wurde in werf \u00fcber mehrere Releases hinweg eingef\u00fchrt: im Alpha-Kanal wurde sie ab Version<\/code> bereits jetzt heruntergeladen werden.<\/p>\n<p><i><b>Hinweis<\/b>v1.0.5-alpha.19 <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/flant\/werf\/releases\/tag\/v1.0.5-alpha.19\">bereit, im Beta-Kanal ab<\/a><\/noindex>3-Way-Merge-Patch f\u00fcr alle Releases <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/flant\/werf\/releases\/tag\/v1.0.4-beta.20\">v1.0.4-beta.20<\/a><\/noindex>.<\/i><\/p>\n<h3>3-Wege-Merge-Patch f\u00fcr alle Versionen<\/h3>\n<p>\nAb dem 15. Dezember 2019 verwenden die Beta- und Alpha-Versionen von werf standardm\u00e4\u00dfig vollst\u00e4ndige 3-way-merge-Patches, um \u00c4nderungen f\u00fcr alle Releases anzuwenden.<\/p>\n<p>WERF_THREE_WAY_MERGE_MODE=onlyNewReleases <code>WERF_THREE_WAY_MERGE_MODE=enabled<\/code> bereits jetzt heruntergeladen werden.<\/p>\n<h3>Wie gehen wir mit der automatischen Skalierung von Ressourcen um?<\/h3>\n<p>\nIn Kubernetes gibt es 2 Arten der automatischen Skalierung: HPA (horizontal) und VPA (vertikal).<\/p>\n<p>Die horizontale Skalierung w\u00e4hlt automatisch die Anzahl der Replikate, die vertikale Skalierung die Menge der Ressourcen. Sowohl die Anzahl der Replikate als auch die Ressourcenerfordernisse werden im Ressourcenmanifest angegeben (siehe <code>spec.replicas<\/code> oder <code>spec.containers[].resources.limits.cpu<\/code>, <code>spec.containers[].resources.limits.memory<\/code> und <noindex><a rel=\"nofollow\" href=\"https:\/\/kubernetes.io\/docs\/concepts\/configuration\/manage-compute-resources-container\/#resource-requests-and-limits-of-pod-and-container\">andere<\/a><\/noindex>).<\/p>\n<p>Problem: Wenn der Benutzer die Ressource im Chart so konfiguriert, dass bestimmte Werte f\u00fcr Ressourcen oder Replikate festgelegt sind und f\u00fcr diese Ressource Auto-Scaler aktiviert sind, wird werf bei jedem Deployment diese Werte auf das zur\u00fccksetzen, was im Manifest des Charts angegeben ist.<\/p>\n<p>Es gibt zwei L\u00f6sungen f\u00fcr dieses Problem. Zun\u00e4chst ist es am besten, auf die explizite Angabe von automatisch skalierbaren Werten im Manifest des Charts zu verzichten. Falls diese Option aus bestimmten Gr\u00fcnden nicht geeignet ist (zum Beispiel, weil es im Chart praktisch ist, Anfangsbeschr\u00e4nkungen f\u00fcr Ressourcen und die Anzahl der Replikate festzulegen), bietet werf die folgenden Annotationen an:<\/p>\n<ul>\n<li> <code>werf.io\/set-replicas-only-on-creation=true<\/code><\/li>\n<li> <code>werf.io\/set-resources-only-on-creation=true<\/code><\/li>\n<\/ul>\n<p>\nBei Vorliegen einer solchen Annotation wird werf die entsprechenden Werte bei jedem Deployment nicht zur\u00fccksetzen, sondern sie lediglich bei der initialen Erstellung der Ressource festlegen.<\/p>\n<p>Weitere Informationen finden Sie in der Projektdokumentation unter <noindex><a rel=\"nofollow\" href=\"https:\/\/werf.io\/documentation\/reference\/deploy_process\/resources_update_methods_and_adoption.html#deal-with-hpa\">HPA<\/a><\/noindex> und <noindex><a rel=\"nofollow\" href=\"https:\/\/werf.io\/documentation\/reference\/deploy_process\/resources_update_methods_and_adoption.html#deal-with-vpa\">VPA<\/a><\/noindex>.<\/p>\n<h3>Verwendung des 3-way-merge-Patches verbieten<\/h3>\n<p>\nDer Benutzer kann derzeit die Verwendung neuer Patches in werf mit der Umgebungsvariable <code>WERF_THREE_WAY_MERGE_MODE=disabled<\/code>verhindern. Ab dem <b>1. M\u00e4rz 2020 wird dieses Verbot jedoch nicht mehr wirksam sein<\/b> und es wird nur die Verwendung von 3-way-merge-Patches m\u00f6glich sein.<\/p>\n<h2>Adoption von Ressourcen in werf<\/h2>\n<p>\nDie Einf\u00fchrung der Methode zur Anwendung von \u00c4nderungen mit 3-way-merge-Patches hat es uns erm\u00f6glicht, sofort eine Funktion wie die Adoption bestehender Ressourcen im Cluster in Helm-Releases zu implementieren.<\/p>\n<p>Helm 2 hat ein Problem: Es ist nicht m\u00f6glich, eine Ressource, die bereits im Cluster existiert, ohne sie von Grund auf neu zu erstellen, zu den Manifests des Charts hinzuzuf\u00fcgen (siehe <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/helm\/helm\/issues\/6031#issuecomment-531579500\">#6031<\/a><\/noindex>, <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/helm\/helm\/issues\/3275\">#3275<\/a><\/noindex>). Wir haben gelernt, werf dazu zu bringen, bestehende Ressourcen im Release zu akzeptieren. Dazu muss eine Annotation auf die aktuelle Version der Ressource aus dem laufenden Cluster angewendet werden (zum Beispiel mit <code>kubectl edit<\/code>):<\/p>\n<pre><code class=\"plaintext\">\"werf.io\/allow-adoption-by-release\": RELEASE_NAME<\/code><\/pre>\n<p>\nJetzt muss die Ressource im Chart beschrieben werden, und beim n\u00e4chsten Deployment mit werf des Releases unter dem entsprechenden Namen wird die bestehende Ressource in dieses Release \u00fcbernommen und bleibt unter seiner Verwaltung. Dar\u00fcber hinaus wird werf beim \u00dcbernehmen der Ressource den aktuellen Zustand der Ressource aus dem laufenden Cluster in den im Chart beschriebenen Zustand \u00fcberf\u00fchren, indem die gleichen 3-way-merge-Patches und die Regel des synchronisierten Ressourcen verwendet werden.<\/p>\n<p><i><b>Hinweis<\/b>: Konfiguration <code>WERF_THREE_WAY_MERGE_MODE<\/code> beeinflusst nicht die Annahme von Ressourcen \u2013 im Falle einer Annahme wird immer ein 3-way-merge-Patch verwendet.<\/i><\/p>\n<p>Details finden Sie in <noindex><a rel=\"nofollow\" href=\"https:\/\/werf.io\/documentation\/reference\/deploy_process\/resources_update_methods_and_adoption.html#resources-adoption\">Dokumentation<\/a><\/noindex>.<\/p>\n<h2>Ergebnisse und weitere Pl\u00e4ne<\/h2>\n<p>\nIch hoffe, nach diesem Artikel ist klarer geworden, was 3-way-merge-Patches sind und warum sie verwendet werden. Aus praktischer Sicht der Entwicklung des werf-Projekts stellt ihre Implementierung einen weiteren Schritt zur Verbesserung des Helm-\u00e4hnlichen Deployments dar. Man kann nun die Probleme mit der Synchronisierung der Konfiguration, die h\u00e4ufig bei der Verwendung von Helm 2 auftraten, vergessen. Zudem wurde eine neue n\u00fctzliche Funktion zur Annahme bereits heruntergeladener Kubernetes-Ressourcen in das Helm-Release hinzugef\u00fcgt.<\/p>\n<p>Im Helm-\u00e4hnlichen Deployment bestehen weiterhin einige Probleme und Schwierigkeiten, wie die Verwendung von Go-Templates, und wir werden diese weiterhin angehen.<\/p>\n<p>Informationen zu den Methoden zur Aktualisierung von Ressourcen und zur Annahme finden Sie ebenfalls auf <noindex><a rel=\"nofollow\" href=\"https:\/\/werf.io\/documentation\/reference\/deploy_process\/resources_update_methods_and_adoption.html\">dieser Dokumentationsseite<\/a><\/noindex>.<\/p>\n<h3>Helm 3<\/h3>\n<p>\nEine besondere Erw\u00e4hnung verdient die <noindex><a rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/company\/flant\/news\/t\/475722\/\">soeben erschienene<\/a><\/noindex> neue Hauptversion von Helm \u2013 v3 \u2013 die ebenfalls 3-way-merge-Patches verwendet und Tiller eliminiert. Die neue Helm-Version erfordert <noindex><a rel=\"nofollow\" href=\"https:\/\/helm.sh\/docs\/topics\/v2_v3_migration\/\">Migration<\/a><\/noindex> bereits bestehende Installationen, um sie in das neue Format der Release-Speicherung zu konvertieren.<\/p>\n<p>Werf hat seinerseits bereits die Verwendung von Tiller eingestellt, ist auf 3-way-merge umgestiegen und hat <noindex><a rel=\"nofollow\" href=\"https:\/\/werf.io\/documentation\/reference\/deploy_process\/differences_with_helm.html\">vieles mehr<\/a><\/noindex>, dabei jedoch mit bestehenden Installationen auf Helm 2 kompatibel geblieben (es sind keine Migrationsskripte erforderlich). Daher verlieren werf-Benutzer, solange werf nicht auf Helm 3 umgeschaltet ist, nicht die wesentlichen Vorteile von Helm 3 gegen\u00fcber Helm 2 (die sind auch in werf vorhanden).<\/p>\n<p>Dennoch ist der Wechsel von werf zur Codebasis von Helm 3 unvermeidlich und wird in naher Zukunft stattfinden. Vermutlich wird dies werf 1.1 oder werf 1.2 sein (derzeit ist die Hauptversion von werf 1.0; weitere Informationen zur Versionierung von werf finden Sie <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/flant\/werf#backward-compatibility-promise\">hier<\/a><\/noindex>). Bis dahin wird Helm 3 stabiler sein.<\/p>\n<h2>P.S.<\/h2>\n<p>\nLesen Sie auch in unserem Blog:<\/p>\n<ul>\n<li> Eine Serie von Notizen zu neuen Funktionen in werf:\n<ul>\n<li> \u00ab<noindex><a rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/company\/flant\/blog\/468049\/\">Verwendung von werf zum Bereitstellen komplexer Helm-Charts<\/a><\/noindex>\u00bb;<\/li>\n<li> \u00ab<noindex><a rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/company\/flant\/blog\/465131\/\">Unterst\u00fctzung von Monorepo und Multirepo in werf und was hat das mit Docker Registry zu tun<\/a><\/noindex>\u00bb;<\/li>\n<li> \u00ab<noindex><a rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/company\/flant\/blog\/463613\/\">Docker-Images in werf k\u00f6nnen jetzt auch mit einem normalen Dockerfile gebaut werden.<\/a><\/noindex>\u00bb.<\/li>\n<\/ul>\n<\/li>\n<li> \u00ab<noindex><a rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/company\/flant\/blog\/460351\/\">Release des Konsolen-XMPP\/Jabber-Clients profanity 0.7.0<\/a><\/noindex>\u00bb;<\/li>\n<li> \u00ab<noindex><a rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/company\/flant\/blog\/469541\/\">Bau und Deployment identischer Mikrodienste mit werf und GitLab CI<\/a><\/noindex>\u00bb;<\/li>\n<li> \u00ab<noindex><a rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/company\/flant\/blog\/453734\/\">Einf\u00fchrung in Helm 3<\/a><\/noindex>\u00bb.<\/li>\n<\/ul>\n<p>Quelle: <a content=\"nofollow\" rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/company\/flant\/blog\/476646\/\">habr.com<\/a><\/p>","protected":false,"gt_translate_keys":[{"key":"rendered","format":"html"}]},"excerpt":{"rendered":"<p>\u0421\u043b\u0443\u0447\u0438\u043b\u043e\u0441\u044c \u0442\u043e, \u0447\u0435\u0433\u043e \u043c\u044b (\u0438 \u043d\u0435 \u0442\u043e\u043b\u044c\u043a\u043e \u043c\u044b) \u0434\u043e\u043b\u0433\u043e \u0436\u0434\u0430\u043b\u0438: werf, \u043d\u0430\u0448\u0430 Open Source-\u0443\u0442\u0438\u043b\u0438\u0442\u0430 \u0434\u043b\u044f \u0441\u0431\u043e\u0440\u043a\u0438 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0439 \u0438 \u0438\u0445 \u0434\u043e\u0441\u0442\u0430\u0432\u043a\u0438 \u0432 Kubernetes, \u0442\u0435\u043f\u0435\u0440\u044c \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u0442 \u043f\u0440\u0438\u043c\u0435\u043d\u0435\u043d\u0438\u0435 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0439 \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e 3-way-merge-\u043f\u0430\u0442\u0447\u0435\u0439! \u0412 \u0434\u043e\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u0435 \u043a \u044d\u0442\u043e\u043c\u0443, \u043f\u043e\u044f\u0432\u0438\u043b\u0430\u0441\u044c \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c adoption\u2019\u0430 \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u0445 K8s-\u0440\u0435\u0441\u0443\u0440\u0441\u043e\u0432 \u0432 Helm-\u0440\u0435\u043b\u0438\u0437\u044b \u0431\u0435\u0437 \u043f\u0435\u0440\u0435\u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u044d\u0442\u0438\u0445 \u0440\u0435\u0441\u0443\u0440\u0441\u043e\u0432. \u0415\u0441\u043b\u0438 \u0441\u043e\u0432\u0441\u0435\u043c \u043a\u043e\u0440\u043e\u0442\u043a\u043e, \u0442\u043e \u0441\u0442\u0430\u0432\u0438\u043c WERF_THREE_WAY_MERGE=enabled \u2014 \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u043c \u0434\u0435\u043f\u043b\u043e\u0439 \u00ab\u043a\u0430\u043a \u0432 [&hellip;]<\/p>\n","protected":false,"gt_translate_keys":[{"key":"rendered","format":"html"}]},"author":1,"featured_media":53121,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[688],"tags":[],"class_list":["post-53120","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-administrirovanie"],"aioseo_notices":[],"aioseo_head":"\n\t\t<!-- All in One SEO 5.0.1.1 - aioseo.com -->\n\t<meta name=\"description\" content=\"\u0421\u043b\u0443\u0447\u0438\u043b\u043e\u0441\u044c \u0442\u043e, \u0447\u0435\u0433\u043e \u043c\u044b (\u0438 \u043d\u0435 \u0442\u043e\u043b\u044c\u043a\u043e \u043c\u044b) \u0434\u043e\u043b\u0433\u043e \u0436\u0434\u0430\u043b\u0438: werf, \u043d\u0430\u0448\u0430 Open Source-\u0443\u0442\u0438\u043b\u0438\u0442\u0430 \u0434\u043b\u044f \u0441\u0431\u043e\u0440\u043a\u0438 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0439 \u0438 \u0438\u0445 \u0434\u043e\u0441\u0442\u0430\u0432\u043a\u0438 \u0432 Kubernetes, \u0442\u0435\u043f\u0435\u0440\u044c \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u0442.\" \/>\n\t<meta name=\"robots\" content=\"max-image-preview:large\" \/>\n\t<meta name=\"author\" content=\"Yuri Gagarin\"\/>\n\t<link rel=\"canonical\" href=\"https:\/\/prohoster.info\/de\/blog\/administrirovanie\/3-way-merge-v-werf-deploj-v-kubernetes-s-helm-na-steroidah\" \/>\n\t<meta name=\"generator\" content=\"All in One SEO (AIOSEO) 5.0.1.1\" \/>\n\t\t<meta property=\"og:locale\" content=\"de_DE\" \/>\n\t\t<meta property=\"og:site_name\" content=\"ProHoster | \u041a\u0443\u043f\u0438\u0442\u044c \u043d\u0430\u0434\u0435\u0436\u043d\u044b\u0439 \u0445\u043e\u0441\u0442\u0438\u043d\u0433 \u0434\u043b\u044f \u0441\u0430\u0439\u0442\u043e\u0432 \u0441 \u0437\u0430\u0449\u0438\u0442\u043e\u0439 \u043e\u0442 DDoS, VPS VDS \u0441\u0435\u0440\u0432\u0435\u0440\u044b\" \/>\n\t\t<meta property=\"og:type\" content=\"article\" \/>\n\t\t<meta property=\"og:title\" content=\"\ud83e\udd473-way merge \u0432 werf: \u0434\u0435\u043f\u043b\u043e\u0439 \u0432 Kubernetes \u0441 Helm \u00ab\u043d\u0430 \u0441\u0442\u0435\u0440\u043e\u0438\u0434\u0430\u0445\u00bb | ProHoster\" \/>\n\t\t<meta property=\"og:description\" content=\"\u0421\u043b\u0443\u0447\u0438\u043b\u043e\u0441\u044c \u0442\u043e, \u0447\u0435\u0433\u043e \u043c\u044b (\u0438 \u043d\u0435 \u0442\u043e\u043b\u044c\u043a\u043e \u043c\u044b) \u0434\u043e\u043b\u0433\u043e \u0436\u0434\u0430\u043b\u0438: werf, \u043d\u0430\u0448\u0430 Open Source-\u0443\u0442\u0438\u043b\u0438\u0442\u0430 \u0434\u043b\u044f \u0441\u0431\u043e\u0440\u043a\u0438 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0439 \u0438 \u0438\u0445 \u0434\u043e\u0441\u0442\u0430\u0432\u043a\u0438 \u0432 Kubernetes, \u0442\u0435\u043f\u0435\u0440\u044c \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u0442.\" \/>\n\t\t<meta property=\"og:url\" content=\"https:\/\/prohoster.info\/de\/blog\/administrirovanie\/3-way-merge-v-werf-deploj-v-kubernetes-s-helm-na-steroidah\" \/>\n\t\t<meta property=\"og:image\" content=\"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg\" \/>\n\t\t<meta property=\"og:image:secure_url\" content=\"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg\" \/>\n\t\t<meta property=\"og:image:width\" content=\"350\" \/>\n\t\t<meta property=\"og:image:height\" content=\"350\" \/>\n\t\t<meta property=\"article:published_time\" content=\"2019-11-23T21:00:00+00:00\" \/>\n\t\t<meta property=\"article:modified_time\" content=\"2020-02-18T11:00:59+00:00\" \/>\n\t\t<meta property=\"article:publisher\" content=\"https:\/\/www.facebook.com\/prohoster\" \/>\n\t\t<meta property=\"article:author\" content=\"https:\/\/www.facebook.com\/prohoster\" \/>\n\t\t<!-- All in One SEO -->\n\n","aioseo_head_json":{"title":"\ud83e\udd473-Wege-Merge in werf: Deployment in Kubernetes mit Helm \"auf Steroiden\" | ProHoster","description":"Es ist geschehen, worauf wir (und nicht nur wir) lange gewartet haben: werf, unser Open Source-Tool zum Bauen von Anwendungen und deren Bereitstellung in Kubernetes, unterst\u00fctzt jetzt.","canonical_url":"https:\/\/prohoster.info\/de\/blog\/administrirovanie\/3-way-merge-v-werf-deploj-v-kubernetes-s-helm-na-steroidah","robots":"max-image-preview:large","keywords":"","webmasterTools":{"miscellaneous":""},"schema":null,"og:locale":"de_DE","og:site_name":"ProHoster | \u041a\u0443\u043f\u0438\u0442\u044c \u043d\u0430\u0434\u0435\u0436\u043d\u044b\u0439 \u0445\u043e\u0441\u0442\u0438\u043d\u0433 \u0434\u043b\u044f \u0441\u0430\u0439\u0442\u043e\u0432 \u0441 \u0437\u0430\u0449\u0438\u0442\u043e\u0439 \u043e\u0442 DDoS, VPS VDS \u0441\u0435\u0440\u0432\u0435\u0440\u044b","og:type":"article","og:title":"\ud83e\udd473-way merge \u0432 werf: \u0434\u0435\u043f\u043b\u043e\u0439 \u0432 Kubernetes \u0441 Helm \u00ab\u043d\u0430 \u0441\u0442\u0435\u0440\u043e\u0438\u0434\u0430\u0445\u00bb | ProHoster","og:description":"\u0421\u043b\u0443\u0447\u0438\u043b\u043e\u0441\u044c \u0442\u043e, \u0447\u0435\u0433\u043e \u043c\u044b (\u0438 \u043d\u0435 \u0442\u043e\u043b\u044c\u043a\u043e \u043c\u044b) \u0434\u043e\u043b\u0433\u043e \u0436\u0434\u0430\u043b\u0438: werf, \u043d\u0430\u0448\u0430 Open Source-\u0443\u0442\u0438\u043b\u0438\u0442\u0430 \u0434\u043b\u044f \u0441\u0431\u043e\u0440\u043a\u0438 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0439 \u0438 \u0438\u0445 \u0434\u043e\u0441\u0442\u0430\u0432\u043a\u0438 \u0432 Kubernetes, \u0442\u0435\u043f\u0435\u0440\u044c \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u0442.","og:url":"https:\/\/prohoster.info\/de\/blog\/administrirovanie\/3-way-merge-v-werf-deploj-v-kubernetes-s-helm-na-steroidah","og:image":"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg","og:image:secure_url":"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg","og:image:width":350,"og:image:height":350,"article:published_time":"2019-11-23T21:00:00+00:00","article:modified_time":"2020-02-18T11:00:59+00:00","article:publisher":"https:\/\/www.facebook.com\/prohoster","article:author":"https:\/\/www.facebook.com\/prohoster"},"aioseo_meta_data":{"post_id":"53120","title":null,"description":null,"keywords":null,"keyphrases":null,"primary_term":null,"canonical_url":null,"og_title":null,"og_description":null,"og_object_type":"default","og_image_type":"default","og_image_url":null,"og_image_width":null,"og_image_height":null,"og_image_custom_url":null,"og_image_custom_fields":null,"og_video":null,"og_custom_url":null,"og_article_section":null,"og_article_tags":null,"twitter_use_og":false,"twitter_card":"default","twitter_image_type":"default","twitter_image_url":null,"twitter_image_custom_url":null,"twitter_image_custom_fields":null,"twitter_title":null,"twitter_description":null,"schema":{"blockGraphs":[],"customGraphs":[],"default":{"data":{"Article":[],"Course":[],"Dataset":[],"FAQPage":[],"Movie":[],"Person":[],"Product":[],"ProductReview":[],"Car":[],"Recipe":[],"Service":[],"SoftwareApplication":[],"WebPage":[]},"graphName":"","isEnabled":true},"graphs":[]},"schema_type":null,"schema_type_options":null,"pillar_content":false,"robots_default":true,"robots_noindex":false,"robots_noarchive":false,"robots_nosnippet":false,"robots_nofollow":false,"robots_noimageindex":false,"robots_noodp":false,"robots_notranslate":false,"robots_max_snippet":null,"robots_max_videopreview":null,"robots_max_imagepreview":"large","priority":null,"frequency":null,"local_seo":null,"seo_analyzer_scan_date":"2026-01-24 06:11:19","breadcrumb_settings":null,"limit_modified_date":false,"reviewed_by":null,"ai":null,"created":"2021-02-28 20:31:28","updated":"2026-01-24 06:11:19","focus_keyword":null,"additional_keywords":null,"truseo_locale":null},"gt_translate_keys":[{"key":"link","format":"url"}],"_links":{"self":[{"href":"https:\/\/prohoster.info\/de\/wp-json\/wp\/v2\/posts\/53120","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/prohoster.info\/de\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/prohoster.info\/de\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/prohoster.info\/de\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/prohoster.info\/de\/wp-json\/wp\/v2\/comments?post=53120"}],"version-history":[{"count":0,"href":"https:\/\/prohoster.info\/de\/wp-json\/wp\/v2\/posts\/53120\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/prohoster.info\/de\/wp-json\/wp\/v2\/media\/53121"}],"wp:attachment":[{"href":"https:\/\/prohoster.info\/de\/wp-json\/wp\/v2\/media?parent=53120"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/prohoster.info\/de\/wp-json\/wp\/v2\/categories?post=53120"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/prohoster.info\/de\/wp-json\/wp\/v2\/tags?post=53120"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}