{"id":86902,"date":"2020-07-01T07:42:28","date_gmt":"2020-07-01T05:42:28","guid":{"rendered":"https:\/\/prohoster.info\/blog\/administrirovanie\/udalyaem-ustarevshuyu-feature-branch-v-kubernetes-klastere"},"modified":"2020-07-01T07:42:28","modified_gmt":"2020-07-01T05:42:28","slug":"udalyaem-ustarevshuyu-feature-branch-v-kubernetes-klastere","status":"publish","type":"post","link":"https:\/\/prohoster.info\/de\/blog\/administrirovanie\/udalyaem-ustarevshuyu-feature-branch-v-kubernetes-klastere","title":{"rendered":"Veraltete Feature-Branch im Kubernetes-Cluster l\u00f6schen","gt_translate_keys":[{"key":"rendered","format":"text"}]},"content":{"rendered":"<p><img decoding=\"async\" alt=\"Veraltete Feature-Branch im Kubernetes-Cluster l\u00f6schen\" src=\"\/wp-content\/uploads\/2020\/07\/d97c0cce385c587e16f26f6d19b9d108.png\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p>Hallo! <b>Feature-Branch<\/b> (aka Deploy-Vorschau, Review-App) \u2014 das bedeutet, dass nicht nur der Master-Zweig, sondern auch jeder Pull Request auf einer einzigartigen URL bereitgestellt wird. So kann \u00fcberpr\u00fcft werden, ob der Code in einer Produktionsumgebung funktioniert, und die Funktion kann anderen Programmierern oder Produktmanagern gezeigt werden. W\u00e4hrend Sie an einem Pull Request arbeiten, wird jedes neue Commit die aktuelle Bereitstellung f\u00fcr den alten Code l\u00f6schen, und eine neue Bereitstellung f\u00fcr den neuen Code wird durchgef\u00fchrt. Fragen k\u00f6nnen entstehen, nachdem Sie den Pull Request in den Master-Zweig gemergt haben. Der Feature-Branch ist dann nicht mehr erforderlich, aber die Ressourcen von Kubernetes befinden sich weiterhin im Cluster.<\/p>\n<p><noindex><a rel=\"nofollow\" name=\"habracut\"><\/a><\/noindex><\/p>\n<h2>Mehr \u00fcber Feature-Branches<\/h2>\n<p><\/p>\n<p>Eine der Methoden, um Feature-Branches in Kubernetes zu erstellen, ist die Verwendung von Namespaces. Kurz gesagt, die Produktionskonfiguration sieht so aus:<\/p>\n<p><\/p>\n<pre><code class=\"plaintext\">kind: Namespace\napiVersion: v1\nmetadata:\n  name: habr-back-end\n...\n\nkind: Deployment\napiVersion: apps\/v1\nmetadata:\n  namespace: habr-back-end\nspec:\n  replicas: 3\n...<\/code><\/pre>\n<p><\/p>\n<p>F\u00fcr den Feature-Branch wird ein Namespace mit dessen Identifikator (z.B. Nummer des Pull Requests) und einem bestimmten Pr\u00e4fix\/Suffix erstellt (z.B. <b>-pr-<\/b>):<\/p>\n<p><\/p>\n<pre><code class=\"plaintext\">kind: Namespace\napiVersion: v1\nmetadata:\n  name: habr-back-end-pr-17\n...\n\nkind: Deployment\napiVersion: apps\/v1\nmetadata:\n  namespace: habr-back-end-pr-17\nspec:\n  replicas: 1\n...<\/code><\/pre>\n<p><\/p>\n<p>Insgesamt habe ich geschrieben <b>Kubernetes Operator<\/b> (eine Anwendung, die Zugriff auf die Cluster-Ressourcen hat), <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/dmytrostriletskyi\/stale-feature-branch-operator\">Link zum Projekt auf Github<\/a><\/noindex>. Er l\u00f6scht die Namespaces, die zu alten Feature-Branches geh\u00f6ren. In Kubernetes werden, wenn ein Namespace gel\u00f6scht wird, auch andere Ressourcen in diesem Namespace automatisch gel\u00f6scht.<\/p>\n<p><\/p>\n<pre><code class=\"bash\">$ kubectl get pods --all-namespaces | grep -e \"-pr-\"\nNAMESPACE            ... ALTER\nhabr-back-end-pr-264 ... 4d8h\nhabr-back-end-pr-265 ... 5d7h<\/code><\/pre>\n<p><\/p>\n<p>\u00dcber die Implementierung von Feature-Branches im Cluster kann man lesen <noindex><a rel=\"nofollow\" href=\"https:\/\/itnext.io\/feature-deployments-in-kubernetes-c74bdcff0d8e\">hier<\/a><\/noindex> und <noindex><a rel=\"nofollow\" href=\"https:\/\/codefresh.io\/kubernetes-tutorial\/dynamically-creating-k8s-namespaces-every-branch-pull-request-2\">hier<\/a><\/noindex>.<\/p>\n<p><\/p>\n<h2>Motivation<\/h2>\n<p><\/p>\n<p>Lassen Sie uns den typischen Lebenszyklus eines Pull Requests mit kontinuierlicher Integration anschauen (<code>kontinuierliche Integration<\/code>):<\/p>\n<p><\/p>\n<ol>\n<li>Wir pushen ein neues Commit in den Branch.<\/li>\n<li>Beim Build werden Linter und\/oder Tests ausgef\u00fchrt.<\/li>\n<li>Die Konfigurationen des Kubernetes-Pull Requests werden dynamisch erstellt (z.B. wird seine Nummer in eine fertige Vorlage eingesetzt).<\/li>\n<li>Die Konfigurationen gelangen mit kubectl apply in den Cluster (Deployment).<\/li>\n<li>Der Pull-Request wird in den Master-Zweig zusammengef\u00fchrt.<\/li>\n<\/ol>\n<p><\/p>\n<p>W\u00e4hrend Sie an einem Pull Request arbeiten, wird jedes neue Commit die aktuelle Bereitstellung f\u00fcr den alten Code l\u00f6schen, und eine neue Bereitstellung f\u00fcr den neuen Code wird durchgef\u00fchrt. Aber wenn der Pull Request in den Master-Zweig integriert wird, wird nur der Master-Zweig gebaut. Am Ende stellt sich heraus, dass wir den Pull Request bereits vergessen haben, w\u00e4hrend seine Kubernetes-Ressourcen weiterhin im Cluster sind.<\/p>\n<p><\/p>\n<h2>Wie man es verwendet<\/h2>\n<p><\/p>\n<p>Installieren Sie das Projekt mit dem folgenden Befehl:<\/p>\n<p><\/p>\n<pre><code class=\"bash\">$ kubectl apply -f https:\/\/raw.githubusercontent.com\/dmytrostriletskyi\/stale-feature-branch-operator\/master\/configs\/production.yml<\/code><\/pre>\n<p><\/p>\n<p>Erstellen Sie eine Datei mit folgendem Inhalt und installieren Sie sie \u00fcber <code>kubectl apply -f<\/code>:<\/p>\n<p><\/p>\n<pre><code class=\"plaintext\">apiVersion: feature-branch.dmytrostriletskyi.com\/v1\nkind: StaleFeatureBranch\nmetadata:\n  name: stale-feature-branch\nspec:\n  namespaceSubstring: -pr-\n  afterDaysWithoutDeploy: 3<\/code><\/pre>\n<p><\/p>\n<p>Parameter <b>namespaceSubstring<\/b> ist notwendig, um die Namespaces f\u00fcr Pull Requests von anderen Namespaces zu filtern. Zum Beispiel, wenn im Cluster die folgenden Namespaces vorhanden sind: <code>habr-back-end<\/code>, <code>habr-front-end<\/code>, <code>habr-back-end-pr-17<\/code>, <code>habr-back-end-pr-33<\/code>, dann w\u00e4ren die Kandidaten f\u00fcr die L\u00f6schung <code>habr-back-end-pr-17<\/code>, <code>habr-back-end-pr-33<\/code>.<\/p>\n<p><\/p>\n<p>Parameter <b>afterDaysWithoutDeploy<\/b> notwendig, um alte Namespaces zu entfernen. Zum Beispiel, wenn der Namespace erstellt wurde <code>3 Tagen 1 Stunde<\/code> erstellt wurde, und der Parameter angibt <code>3 Tage<\/code>, wird dieser Namespace gel\u00f6scht. Es funktioniert auch in umgekehrter Richtung, wenn der Namespace vor <code>2 Tagen 23 Stunden<\/code> erstellt wurde, und der Parameter angibt <code>3 Tage<\/code>, wird dieser Namespace nicht gel\u00f6scht.<\/p>\n<p><\/p>\n<p>Es gibt noch einen weiteren Parameter, der festlegt, wie oft alle Namespaces gescannt werden sollen, um nach Tagen ohne Bereitstellung zu pr\u00fcfen \u2014 <b>checkEveryMinutes<\/b>. Standardm\u00e4\u00dfig betr\u00e4gt er <code>30 Minuten<\/code>.<\/p>\n<p><\/p>\n<h2>Die DANE-Spezifikation ist in<\/h2>\n<p><\/p>\n<p>In der Praxis wird Folgendes ben\u00f6tigt:<\/p>\n<p><\/p>\n<ol>\n<li><noindex><a rel=\"nofollow\" href=\"https:\/\/docs.docker.com\/get-docker\">Docker<\/a><\/noindex> um in einer isolierten Umgebung zu arbeiten.<\/li>\n<li><noindex><a rel=\"nofollow\" href=\"https:\/\/kubernetes.io\/docs\/tasks\/tools\/install-minikube\">Minikube<\/a><\/noindex> hebt den Kubernetes-Cluster lokal an.<\/li>\n<li><noindex><a rel=\"nofollow\" href=\"https:\/\/kubernetes.io\/docs\/tasks\/tools\/install-kubectl\">kubectl<\/a><\/noindex> \u2014 Kommandozeileninterface zur Verwaltung des Clusters.<\/li>\n<\/ol>\n<p><\/p>\n<p>Heben wir den Kubernetes-Cluster lokal an:<\/p>\n<p><\/p>\n<pre><code class=\"bash\">$ minikube start --vm-driver=docker\nminikube v1.11.0 auf Darwin 10.15.5\nVerwendung des Docker-Treibers basierend auf dem vorhandenen Profil.\nStarte Steuerungsplane-Node minikube im Cluster minikube.<\/code><\/pre>\n<p><\/p>\n<p>Geben Sie an <code>kubectl<\/code> lokalen Cluster standardm\u00e4\u00dfig verwenden:<\/p>\n<p><\/p>\n<pre><code class=\"bash\">$ kubectl config use-context minikube\nWechsel zu Kontext \"minikube\".<\/code><\/pre>\n<p><\/p>\n<p>Laden Sie Konfigurationen f\u00fcr die Produktionsumgebung herunter:<\/p>\n<p><\/p>\n<pre><code class=\"bash\">$ curl https:\/\/raw.githubusercontent.com\/dmytrostriletskyi\/stale-feature-branch-operator\/master\/configs\/production.yml &gt; stale-feature-branch-production-configs.yml<\/code><\/pre>\n<p><\/p>\n<p>Da die Produktionskonfigurationen eingestellt sind, um alte Namespaces zu \u00fcberpr\u00fcfen, wir jedoch keine in unserem neu gestarteten Cluster haben, ersetzen wir die Umgebungsvariable <code>IS_DEBUG<\/code> auf <code>true<\/code>. Bei diesem Wert wird der Parameter <code>afterDaysWithoutDeploy<\/code> wird nicht ber\u00fccksichtigt und die Namespaces werden nicht auf Tage ohne Bereitstellung \u00fcberpr\u00fcft, nur auf das Vorhandensein eines Substrings (<code>-pr-<\/code>).<\/p>\n<p><\/p>\n<p>Wenn Sie auf <code>Linux<\/code>:<\/p>\n<p><\/p>\n<pre><code class=\"bash\">$ sed -i 's|false|true|g' stale-feature-branch-production-configs.yml<\/code><\/pre>\n<p><\/p>\n<p>Wenn Sie auf <code>macOS<\/code>:<\/p>\n<p><\/p>\n<pre><code class=\"bash\">$ sed -i \"\" 's|false|true|g' stale-feature-branch-production-configs.yml<\/code><\/pre>\n<p><\/p>\n<p>Installieren Sie das Projekt:<\/p>\n<p><\/p>\n<pre><code class=\"bash\">$ kubectl apply -f stale-feature-branch-production-configs.yml<\/code><\/pre>\n<p><\/p>\n<p>\u00dcberpr\u00fcfen Sie, ob die Ressource im Cluster erschienen ist <code>StaleFeatureBranch<\/code>:<\/p>\n<p><\/p>\n<pre><code class=\"bash\">$ kubectl api-resources | grep stalefeaturebranches\nNAME                 ... APIGROUP                             ... KIND\nstalefeaturebranches ... feature-branch.dmytrostriletskyi.com ... StaleFeatureBranch<\/code><\/pre>\n<p><\/p>\n<p>\u00dcberpr\u00fcfen Sie, ob der Operator im Cluster erschienen ist:<\/p>\n<p><\/p>\n<pre><code class=\"bash\">$ kubectl get pods --namespace stale-feature-branch-operator\nNAME                                           ... STATUS  ... AGE\nstale-feature-branch-operator-6bfbfd4df8-m7sch ... Running ... 38s<\/code><\/pre>\n<p><\/p>\n<p>Wenn Sie in seine Protokolle schauen, ist es bereit, Ressourcen zu verarbeiten <code>StaleFeatureBranch<\/code>:<\/p>\n<p><\/p>\n<pre><code class=\"bash\">$ kubectl logs stale-feature-branch-operator-6bfbfd4df8-m7sch -n stale-feature-branch-operator\n... \"msg\":\"Operator Version: 0.0.1\"}\n...\n... \"msg\":\"Starting EventSource\", ... , \"source\":\"kind source: \/, Kind=\"}\n... \"msg\":\"Starting Controller\", ...}\n... \"msg\":\"Starting workers\", ..., \"worker count\":1}<\/code><\/pre>\n<p><\/p>\n<p>Installieren Sie die fertigen <code>fixtures<\/code> (fertige Konfigurationen zur Modellierung von Clusterressourcen) f\u00fcr die Ressource <code>StaleFeatureBranch<\/code>:<\/p>\n<p><\/p>\n<pre><code class=\"bash\">$ kubectl apply -f https:\/\/raw.githubusercontent.com\/dmytrostriletskyi\/stale-feature-branch-operator\/master\/fixtures\/stale-feature-branch.yml<\/code><\/pre>\n<p><\/p>\n<p>In den Konfigurationen ist angegeben, nach Namespaces mit Substring zu suchen <code>-pr-<\/code> alle <code>1 Minute<\/code>.:<\/p>\n<p><\/p>\n<pre><code class=\"plaintext\">apiVersion: feature-branch.dmytrostriletskyi.com\/v1\nkind: StaleFeatureBranch\nmetadata:\n  name: stale-feature-branch\nspec:\n  namespaceSubstring: -pr-\n  afterDaysWithoutDeploy: 1 \n  checkEveryMinutes: 1<\/code><\/pre>\n<p><\/p>\n<p>Der Operator reagierte und ist bereit, die Namespaces zu \u00fcberpr\u00fcfen:<\/p>\n<p><\/p>\n<pre><code class=\"bash\">$ kubectl logs stale-feature-branch-operator-6bfbfd4df8-m7sch -n stale-feature-branch-operator\n... \"msg\":\"Stale feature branch wird verarbeitet.\",\"namespaceSubstring\":\"-pr-\",\"afterDaysWithoutDeploy\":1,\"checkEveryMinutes\":1,\"isDebug\":\"true\"}<\/code><\/pre>\n<p><\/p>\n<p>Installation <code>fixtures<\/code>, die zwei Namespaces enthalten (<code>project-pr-1<\/code>, <code>project-pr-2<\/code>) und deren <code>deployments<\/code>, <code>Dienste<\/code>, <code>ingress<\/code>, und so weiter:<\/p>\n<p><\/p>\n<pre><code class=\"bash\">$ kubectl apply -f https:\/\/raw.githubusercontent.com\/dmytrostriletskyi\/stale-feature-branch-operator\/master\/fixtures\/first-feature-branch.yml -f https:\/\/raw.githubusercontent.com\/dmytrostriletskyi\/stale-feature-branch-operator\/master\/fixtures\/second-feature-branch.yml\n...\nnamespace\/project-pr-1 erstellt\ndeployment.apps\/project-pr-1 erstellt\nservice\/project-pr-1 erstellt\nhorizontalpodautoscaler.autoscaling\/project-pr-1 erstellt\nsecret\/project-pr-1 erstellt\nconfigmap\/project-pr-1 erstellt\ningress.extensions\/project-pr-1 erstellt\nnamespace\/project-pr-2 erstellt\ndeployment.apps\/project-pr-2 erstellt\nservice\/project-pr-2 erstellt\nhorizontalpodautoscaler.autoscaling\/project-pr-2 erstellt\nsecret\/project-pr-2 erstellt\nconfigmap\/project-pr-2 erstellt\ningress.extensions\/project-pr-2 erstellt<\/code><\/pre>\n<p><\/p>\n<p>\u00dcberpr\u00fcfen wir, ob alle oben genannten Ressourcen erfolgreich erstellt wurden:<\/p>\n<p><\/p>\n<pre><code class=\"bash\">$ kubectl get namespace,pods,deployment,service,horizontalpodautoscaler,configmap,ingress -n project-pr-1 &amp;&amp; kubectl get namespace,pods,deployment,service,horizontalpodautoscaler,configmap,ingress -n project-pr-2\n...\nNAME                              ... READY ... STATUS  ... AGE\npod\/project-pr-1-848d5fdff6-rpmzw ... 1\/1   ... Running ... 67s\n\nNAME                         ... READY ... AVAILABLE ... AGE\ndeployment.apps\/project-pr-1 ... 1\/1   ... 1         ... 67s\n...<\/code><\/pre>\n<p><\/p>\n<p>Da wir die <code>debug<\/code>, Namespaces <code>project-pr-1<\/code> und <code>project-pr-2<\/code>, m\u00fcssen auch alle anderen Ressourcen sofort gel\u00f6scht werden, unabh\u00e4ngig vom Parameter <code>afterDaysWithoutDeploy<\/code>. In den Logs des Operators ist das sichtbar:<\/p>\n<p><\/p>\n<pre><code class=\"bash\">$ kubectl logs stale-feature-branch-operator-6bfbfd4df8-m7sch -n stale-feature-branch-operator\n... \"msg\":\"Namespace sollte gel\u00f6scht werden, da der Debugmodus aktiviert ist.\",\"namespaceName\":\"project-pr-1\"}\n... \"msg\":\"Namespace wird verarbeitet.\",\"namespaceName\":\"project-pr-1\",\"namespaceCreationTimestamp\":\"2020-06-16 18:43:58 +0300 EEST\"}\n... \"msg\":\"Namespace wurde gel\u00f6scht.\",\"namespaceName\":\"project-pr-1\"}\n... \"msg\":\"Namespace sollte gel\u00f6scht werden, da der Debugmodus aktiviert ist.\",\"namespaceName\":\"project-pr-2\"}\n... \"msg\":\"Namespace wird verarbeitet.\",\"namespaceName\":\"project-pr-2\",\"namespaceCreationTimestamp\":\"2020-06-16 18:43:58 +0300 EEST\"}\n... \"msg\":\"Namespace wurde gel\u00f6scht.\",\"namespaceName\":\"project-pr-2\"}<\/code><\/pre>\n<p><\/p>\n<p>Wenn wir die Verf\u00fcgbarkeit der Ressourcen \u00fcberpr\u00fcfen, werden sie sich im Status <code>Terminating<\/code> (L\u00f6schprozess) oder bereits gel\u00f6scht (der Befehl gibt nichts aus).<\/p>\n<p><\/p>\n<pre><code class=\"bash\">$ kubectl get namespace,pods,deployment,service,horizontalpodautoscaler,configmap,ingress -n project-pr-1 &amp;&amp; kubectl get namespace,pods,deployment,service,horizontalpodautoscaler,configmap,ingress -n project-pr-2\n...<\/code><\/pre>\n<p><\/p>\n<p>Sie k\u00f6nnen den Erstellungsprozess <code>fixtures<\/code> mehrmals wiederholen und sich vergewissern, dass sie innerhalb einer Minute gel\u00f6scht werden.<\/p>\n<p><\/p>\n<h2>Alternativen<\/h2>\n<p><\/p>\n<p>Was kann man statt eines Operators machen, der im Cluster arbeitet? Es gibt mehrere Ans\u00e4tze, die alle nicht perfekt sind (und ihre M\u00e4ngel subjektiv sind), und jeder entscheidet selbst, was am besten f\u00fcr ein bestimmtes Projekt geeignet ist:<\/p>\n<p><\/p>\n<ol>\n<li>\n<p>Den Feature-Branch w\u00e4hrend des Builds des Master-Branches l\u00f6schen.<\/p>\n<p><\/p>\n<ul>\n<li>Daf\u00fcr muss man wissen, welcher Pull Request zu dem Commit geh\u00f6rt, der gebaut wird. Da der Feature-Branch-Namespace die ID des Pull Requests \u2014 seine Nummer oder den Namen des Branches \u2014 enth\u00e4lt, muss man die ID immer im Commit angeben.<\/li>\n<li>Builds von Master-Branches schlagen fehl. Zum Beispiel haben Sie die folgenden Schritte: Projekt herunterladen, Tests ausf\u00fchren, Projekt bauen, Release erstellen, Benachrichtigungen senden, den Feature-Branch des letzten Pull Requests bereinigen. Wenn der Build beim Senden der Benachrichtigung fehlschl\u00e4gt, m\u00fcssen Sie alle Ressourcen im Cluster manuell l\u00f6schen.<\/li>\n<li>Ohne den richtigen Kontext ist das L\u00f6schen des Feature-Branches im Master-Build nicht offensichtlich.<\/li>\n<\/ul>\n<p>\n<\/li>\n<li>\n<p>Die Verwendung von Webhooks (<noindex><a rel=\"nofollow\" href=\"https:\/\/github.community\/t\/trigger-jenkins-job-when-a-pull-request-is-merged-to-a-branch\/1169\">Beispiel<\/a><\/noindex>).<\/p>\n<p><\/p>\n<ul>\n<li>Vielleicht ist das nicht Ihr Ansatz. Zum Beispiel in <noindex><a rel=\"nofollow\" href=\"https:\/\/www.jenkins.io\">Jenkins<\/a><\/noindex>, nur eine Art von Pipeline unterst\u00fctzt die M\u00f6glichkeit, ihre Konfigurationen im Quellcode zu speichern. Bei der Verwendung von Webhooks muss ein eigenes Skript zur Verarbeitung geschrieben werden. Dieses Skript muss im Jenkins-Interface untergebracht werden, was schwer zu warten ist.<\/li>\n<\/ul>\n<p>\n<\/li>\n<li>\n<p>Eintragen <noindex><a rel=\"nofollow\" href=\"https:\/\/kubernetes.io\/docs\/concepts\/workloads\/controllers\/cron-jobs\/\">Cronjob<\/a><\/noindex> und Kubernetes-Cluster hinzuf\u00fcgen.<\/p>\n<p><\/p>\n<ul>\n<li>Zeitaufwand f\u00fcr das Schreiben und die Wartung.<\/li>\n<li>Der Operator arbeitet bereits in einem \u00e4hnlichen Stil, ist dokumentiert und wird unterst\u00fctzt.<\/li>\n<\/ul>\n<p>\n<\/li>\n<\/ol>\n<p><\/p>\n<p>Vielen Dank f\u00fcr Ihre Aufmerksamkeit zu diesem Artikel. <strong><noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/dmytrostriletskyi\/stale-feature-branch-operator\">Link zum Projekt auf Github<\/a><\/noindex><\/strong>.<\/p>\n<p>Quelle: <a content=\"nofollow\" rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/post\/508534\/\">habr.com<\/a> <\/p>","protected":false,"gt_translate_keys":[{"key":"rendered","format":"html"}]},"excerpt":{"rendered":"<p>\u041f\u0440\u0438\u0432\u0435\u0442! Feature branch (aka deploy preview, review app) \u2014 \u044d\u0442\u043e \u043a\u043e\u0433\u0434\u0430 \u0434\u0435\u043f\u043b\u043e\u0438\u0442\u0441\u044f \u043d\u0435 \u0442\u043e\u043b\u044c\u043a\u043e master \u0432\u0435\u0442\u043a\u0430, \u043d\u043e \u0438 \u043a\u0430\u0436\u0434\u044b\u0439 pull request \u043d\u0430 \u0443\u043d\u0438\u043a\u0430\u043b\u044c\u043d\u044b\u0439 URL. \u041c\u043e\u0436\u043d\u043e \u043f\u0440\u043e\u0432\u0435\u0440\u0438\u0442\u044c \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 \u043b\u0438 \u043a\u043e\u0434 \u0432 production-\u043e\u043a\u0440\u0443\u0436\u0435\u043d\u0438\u0438, \u0444\u0438\u0447\u0443 \u043c\u043e\u0436\u043d\u043e \u043f\u043e\u043a\u0430\u0437\u0430\u0442\u044c \u0434\u0440\u0443\u0433\u0438\u043c \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u0438\u0441\u0442\u0430\u043c \u0438\u043b\u0438 \u043f\u0440\u043e\u0434\u0443\u043a\u0442\u043e\u043b\u043e\u0433\u0430\u043c. \u041f\u043e\u043a\u0430 \u0432\u044b \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442\u0435 \u0432 pull request&#8217;\u0435, \u043a\u0430\u0436\u0434\u044b\u0439 \u043d\u043e\u0432\u044b\u0439 commit \u0442\u0435\u043a\u0443\u0449\u0438\u0439 deploy \u0434\u043b\u044f \u0441\u0442\u0430\u0440\u043e\u0433\u043e \u043a\u043e\u0434\u0430 \u0443\u0434\u0430\u043b\u044f\u0435\u0442\u0441\u044f, \u0430 \u043d\u043e\u0432\u044b\u0439 [&hellip;]<\/p>\n","protected":false,"gt_translate_keys":[{"key":"rendered","format":"html"}]},"author":1,"featured_media":86903,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[688],"tags":[],"class_list":["post-86902","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=\"\u041f\u0440\u0438\u0432\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\/udalyaem-ustarevshuyu-feature-branch-v-kubernetes-klastere\" \/>\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\udd47\u0423\u0434\u0430\u043b\u044f\u0435\u043c \u0443\u0441\u0442\u0430\u0440\u0435\u0432\u0448\u0443\u044e feature branch \u0432 Kubernetes \u043a\u043b\u0430\u0441\u0442\u0435\u0440\u0435 | ProHoster\" \/>\n\t\t<meta property=\"og:description\" content=\"\u041f\u0440\u0438\u0432\u0435\u0442!\" \/>\n\t\t<meta property=\"og:url\" content=\"https:\/\/prohoster.info\/de\/blog\/administrirovanie\/udalyaem-ustarevshuyu-feature-branch-v-kubernetes-klastere\" \/>\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=\"2020-07-01T05:42:28+00:00\" \/>\n\t\t<meta property=\"article:modified_time\" content=\"2020-07-01T05:42:28+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\udd47L\u00f6schen des veralteten Feature-Branches im Kubernetes-Cluster | ProHoster","description":"Hallo!","canonical_url":"https:\/\/prohoster.info\/de\/blog\/administrirovanie\/udalyaem-ustarevshuyu-feature-branch-v-kubernetes-klastere","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\udd47\u0423\u0434\u0430\u043b\u044f\u0435\u043c \u0443\u0441\u0442\u0430\u0440\u0435\u0432\u0448\u0443\u044e feature branch \u0432 Kubernetes \u043a\u043b\u0430\u0441\u0442\u0435\u0440\u0435 | ProHoster","og:description":"\u041f\u0440\u0438\u0432\u0435\u0442!","og:url":"https:\/\/prohoster.info\/de\/blog\/administrirovanie\/udalyaem-ustarevshuyu-feature-branch-v-kubernetes-klastere","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":"2020-07-01T05:42:28+00:00","article:modified_time":"2020-07-01T05:42:28+00:00","article:publisher":"https:\/\/www.facebook.com\/prohoster","article:author":"https:\/\/www.facebook.com\/prohoster"},"aioseo_meta_data":{"post_id":"86902","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":null,"breadcrumb_settings":null,"limit_modified_date":false,"reviewed_by":null,"ai":null,"created":"2021-02-28 14:03:55","updated":"2022-10-03 08:48:02","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\/86902","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=86902"}],"version-history":[{"count":0,"href":"https:\/\/prohoster.info\/de\/wp-json\/wp\/v2\/posts\/86902\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/prohoster.info\/de\/wp-json\/wp\/v2\/media\/86903"}],"wp:attachment":[{"href":"https:\/\/prohoster.info\/de\/wp-json\/wp\/v2\/media?parent=86902"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/prohoster.info\/de\/wp-json\/wp\/v2\/categories?post=86902"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/prohoster.info\/de\/wp-json\/wp\/v2\/tags?post=86902"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}