{"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\/ro\/blog\/administrirovanie\/udalyaem-ustarevshuyu-feature-branch-v-kubernetes-klastere","title":{"rendered":"\u0218tergerea unei feature branch \u00eenvechite \u00een clusterul Kubernetes","gt_translate_keys":[{"key":"rendered","format":"text"}]},"content":{"rendered":"<p><img decoding=\"async\" alt=\"\u0218tergerea unei feature branch \u00eenvechite \u00een clusterul Kubernetes\" src=\"\/wp-content\/uploads\/2020\/07\/d97c0cce385c587e16f26f6d19b9d108.png\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p>Bun\u0103! <b>Ramur\u0103 de caracteristici<\/b> (aka deploy preview, review app) \u2014 aceasta \u00eenseamn\u0103 c\u0103 nu se depune doar ramura master, ci \u0219i fiecare pull request pe o adres\u0103 URL unic\u0103. Po\u021bi verifica dac\u0103 codul func\u021bioneaz\u0103 \u00een mediu de produc\u021bie, iar caracteristica poate fi prezentat\u0103 altor programatori sau product manageri. Atunci c\u00e2nd lucrezi la un pull request, fiecare nou commit elimin\u0103 actualul deploy pentru codul vechi \u0219i se realizeaz\u0103 un nou deploy pentru codul nou. Problemele pot ap\u0103rea atunci c\u00e2nd ai fuzionat pull request-ul \u00een ramura master. Ramura de caracteristici nu mai este necesar\u0103, dar resursele Kubernetes sunt \u00eenc\u0103 \u00een cluster.<\/p>\n<p><noindex><a rel=\"nofollow\" name=\"habracut\"><\/a><\/noindex><\/p>\n<h2>\u00cenc\u0103 despre ramurile de caracteristici<\/h2>\n<p><\/p>\n<p>Una dintre abord\u0103rile pentru a realiza ramuri de caracteristici \u00een Kubernetes este utilizarea namespace-urilor. Pe scurt, configura\u021biile de produc\u021bie arat\u0103 a\u0219a:<\/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>Pentru ramura de caracteristici se creeaz\u0103 un namespace cu identificatorul acesteia (de exemplu, num\u0103rul pull request-ului) \u0219i un anumit prefix\/sufix (de exemplu, <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>\u00cen general, am scris <b>Kubernetes Operator<\/b> (o aplica\u021bie care are acces la resursele cluster-ului), <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/dmytrostriletskyi\/stale-feature-branch-operator\">link c\u0103tre proiect pe Github<\/a><\/noindex>. Acesta \u0219terge namespace-urile care apar\u021bin ramurilor de caracteristici vechi. \u00cen Kubernetes, dac\u0103 se \u0219terge un namespace, alte resurse din acest namespace sunt, de asemenea, \u0219terse automat.<\/p>\n<p><\/p>\n<pre><code class=\"bash\">$ kubectl get pods --all-namespaces | grep -e \"-pr-\"\nNAMESPACE            ... AGE\nhabr-back-end-pr-264 ... 4d8h\nhabr-back-end-pr-265 ... 5d7h<\/code><\/pre>\n<p><\/p>\n<p>Despre cum s\u0103 implementezi ramurile de caracteristici \u00een cluster, po\u021bi citi <noindex><a rel=\"nofollow\" href=\"https:\/\/itnext.io\/feature-deployments-in-kubernetes-c74bdcff0d8e\">aici<\/a><\/noindex> \u0219i <noindex><a rel=\"nofollow\" href=\"https:\/\/codefresh.io\/kubernetes-tutorial\/dynamically-creating-k8s-namespaces-every-branch-pull-request-2\">aici<\/a><\/noindex>.<\/p>\n<p><\/p>\n<h2>Motiva\u021bia<\/h2>\n<p><\/p>\n<p>S\u0103 ne uit\u0103m la ciclul de via\u021b\u0103 tipic al unui pull request cu integrare continu\u0103 (<code>continuous integration<\/code>):<\/p>\n<p><\/p>\n<ol>\n<li>Trimitem un nou commit \u00een ramur\u0103.<\/li>\n<li>La construc\u021bie, se ruleaz\u0103 lintere \u0219i\/sau teste.<\/li>\n<li>Configur\u0103rile Kubernetes pentru pull request se formeaz\u0103 \u00een timp real (de exemplu, num\u0103rul s\u0103u este introdus \u00eentr-un \u0219ablon preg\u0103tit).<\/li>\n<li>Cu ajutorul kubectl apply, configura\u021biile ajung \u00een cluster (implementare).<\/li>\n<li>Pull request-ul este fuzionat \u00een ramura master.<\/li>\n<\/ol>\n<p><\/p>\n<p>Atunci c\u00e2nd lucrezi la un pull request, fiecare nou commit elimin\u0103 actualul deploy pentru codul vechi \u0219i se realizeaz\u0103 un nou deploy pentru codul nou. Dar c\u00e2nd pull request-ul este fuzionat \u00een ramura master, se va construi doar ramura master. \u00cen cele din urm\u0103, ajungem la concluzia c\u0103 am uitat de pull request, iar resursele sale Kubernetes sunt \u00eenc\u0103 \u00een cluster.<\/p>\n<p><\/p>\n<h2>Cum s\u0103 folose\u0219ti<\/h2>\n<p><\/p>\n<p>Instaleaz\u0103 proiectul cu comanda de mai jos:<\/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>Creeaz\u0103 un fi\u0219ier cu urm\u0103torul con\u021binut \u0219i instaleaz\u0103-l prin <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>Parametru <b>namespaceSubstring<\/b> este necesar pentru a filtra namespace-urile pentru pull request-uri de la alte namespace-uri. De exemplu, dac\u0103 \u00een cluster exist\u0103 urm\u0103toarele namespace-uri: <code>habr-back-end<\/code>, <code>habr-front-end<\/code>, <code>habr-back-end-pr-17<\/code>, <code>habr-back-end-pr-33<\/code>, atunci candida\u021bii pentru eliminare vor fi <code>habr-back-end-pr-17<\/code>, <code>habr-back-end-pr-33<\/code>.<\/p>\n<p><\/p>\n<p>Parametru <b>afterDaysWithoutDeploy<\/b> este necesar pentru a \u0219terge namespace-urile vechi. De exemplu, dac\u0103 namespace-ul este creat <code>3 zile 1 or\u0103<\/code> \u00een urm\u0103, iar \u00een parametru este specificat <code>3 zile<\/code>, acest namespace va fi eliminat. Func\u021bioneaz\u0103 \u0219i \u00een sens invers, dac\u0103 un namespace a fost creat <code>2 zile 23 ore<\/code> \u00een urm\u0103, iar \u00een parametru este specificat <code>3 zile<\/code>, acest namespace nu va fi eliminat.<\/p>\n<p><\/p>\n<p>Exist\u0103 \u0219i un alt parametru, care r\u0103spunde de c\u00e2t de des s\u0103 scaneze toate namespace-urile \u0219i s\u0103 verifice pentru zile f\u0103r\u0103 deploy \u2014 <b>checkEveryMinutes<\/b>. Implicit, este egal cu <code>30 minute<\/code>.<\/p>\n<p><\/p>\n<h2>Cum func\u021bioneaz\u0103<\/h2>\n<p><\/p>\n<p>\u00cen practic\u0103, este necesar:<\/p>\n<p><\/p>\n<ol>\n<li><noindex><a rel=\"nofollow\" href=\"https:\/\/docs.docker.com\/get-docker\">Docker<\/a><\/noindex> pentru a func\u021biona \u00eentr-un mediu izolat.<\/li>\n<li><noindex><a rel=\"nofollow\" href=\"https:\/\/kubernetes.io\/docs\/tasks\/tools\/install-minikube\">Minikube<\/a><\/noindex> va ridica un cluster Kubernetes local.<\/li>\n<li><noindex><a rel=\"nofollow\" href=\"https:\/\/kubernetes.io\/docs\/tasks\/tools\/install-kubectl\">kubectl<\/a><\/noindex> \u2014 interfa\u021ba de linie de comand\u0103 pentru gestionarea cluster-ului.<\/li>\n<\/ol>\n<p><\/p>\n<p>Ridic\u0103m cluster-ul Kubernetes local:<\/p>\n<p><\/p>\n<pre><code class=\"bash\">$ minikube start --vm-driver=docker\nminikube v1.11.0 pe Darwin 10.15.5\nFolosind driverul docker bazat pe profilul existent.\nPornind nodul control minikube \u00een clusterul minikube.<\/code><\/pre>\n<p><\/p>\n<p>Specifica\u021bi <code>kubectl<\/code> folosi\u021bi cluster-ul local implicit:<\/p>\n<p><\/p>\n<pre><code class=\"bash\">$ kubectl config use-context minikube\nSwitched to context \"minikube\".<\/code><\/pre>\n<p><\/p>\n<p>Desc\u0103rc\u0103m configura\u021biile pentru mediu de produc\u021bie:<\/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>Deoarece configura\u021biile de produc\u021bie sunt setate s\u0103 verifice namespace-urile vechi, iar \u00een clusterul nostru nou ridicat acestea nu exist\u0103, vom \u00eenlocui variabila de mediu <code>IS_DEBUG<\/code> pe <code>true<\/code>. Cu aceast\u0103 valoare, parametrul <code>afterDaysWithoutDeploy<\/code> nu este luat\u0103 \u00een considerare \u0219i namespace-urile nu sunt verificate pentru zile f\u0103r\u0103 deploy, doar pentru apari\u021bia sub\u0219irului (<code>-pr-<\/code>).<\/p>\n<p><\/p>\n<p>Dac\u0103 sunte\u021bi pe <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>Dac\u0103 sunte\u021bi pe <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>Instal\u0103m proiectul:<\/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>Verific\u0103m c\u0103 resursa a ap\u0103rut \u00een cluster <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>Verific\u0103m c\u0103 operatorul a ap\u0103rut \u00een cluster:<\/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>Dac\u0103 ne uit\u0103m \u00een jurnalele sale, este gata s\u0103 proceseze resursele <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\":\"Versiunea Operatorului: 0.0.1\"}\n...\n... \"msg\":\"Pornire EventSource\", ... , \"source\":\"kind source: \\\/, Kind=\"}\n... \"msg\":\"Pornire Controller\", ...}\n... \"msg\":\"Pornire lucr\u0103tori\", ..., \"worker count\":1}<\/code><\/pre>\n<p><\/p>\n<p>Instal\u0103m fixture-urile <code>prize<\/code> (configura\u021bii gata f\u0103cute pentru modelarea resurselor clusterului) pentru resurs\u0103 <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>Configura\u021biile specific\u0103 c\u0103 trebuie s\u0103 c\u0103ut\u0103m namespace-uri care con\u021bin sub\u0219iruri <code>-pr-<\/code> o dat\u0103 la <code>1 minut<\/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>Operatorul a reac\u021bionat \u0219i este preg\u0103tit s\u0103 verifice namespace-urile:<\/p>\n<p><\/p>\n<pre><code class=\"bash\">$ kubectl logs stale-feature-branch-operator-6bfbfd4df8-m7sch -n stale-feature-branch-operator\n... \"msg\":\"Feature branch \u00eenghe\u021bat este procesat.\",\"namespaceSubstring\":\"-pr-\",\"afterDaysWithoutDeploy\":1,\"checkEveryMinutes\":1,\"isDebug\":\"true\"}<\/code><\/pre>\n<p><\/p>\n<p>Instal\u0103m <code>prize<\/code>, con\u021bin\u00e2nd dou\u0103 namespace-uri (<code>project-pr-1<\/code>, <code>project-pr-2<\/code>) \u0219i ale lor <code>deployments<\/code>, <code>servicii<\/code>, <code>ingress<\/code>, \u0219i a\u0219a mai departe:<\/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 created\ndeployment.apps\/project-pr-1 created\nservice\/project-pr-1 created\nhorizontalpodautoscaler.autoscaling\/project-pr-1 created\nsecret\/project-pr-1 created\nconfigmap\/project-pr-1 created\ningress.extensions\/project-pr-1 created\nnamespace\/project-pr-2 created\ndeployment.apps\/project-pr-2 created\nservice\/project-pr-2 created\nhorizontalpodautoscaler.autoscaling\/project-pr-2 created\nsecret\/project-pr-2 created\nconfigmap\/project-pr-2 created\ningress.extensions\/project-pr-2 created<\/code><\/pre>\n<p><\/p>\n<p>Verific\u0103m c\u0103 toate resursele de mai sus au fost create cu succes:<\/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>Deoarece am activat <code>debug<\/code>, namespace-uri <code>project-pr-1<\/code> \u0219i <code>project-pr-2<\/code>, prin urmare \u0219i toate celelalte resurse, vor trebui s\u0103 fie imediat \u0219terse f\u0103r\u0103 a lua \u00een considerare parametrul <code>afterDaysWithoutDeploy<\/code>. \u00cen log-urile operatorului se vede acest lucru:<\/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-ul ar trebui s\u0103 fie \u0219ters deoarece modul de depanare este activat.\",\"namespaceName\":\"project-pr-1\"}\n... \"msg\":\"Namespace-ul este procesat.\",\"namespaceName\":\"project-pr-1\",\"namespaceCreationTimestamp\":\"2020-06-16 18:43:58 +0300 EEST\"}\n... \"msg\":\"Namespace-ul a fost \u0219ters.\",\"namespaceName\":\"project-pr-1\"}\n... \"msg\":\"Namespace-ul ar trebui s\u0103 fie \u0219ters deoarece modul de depanare este activat.\",\"namespaceName\":\"project-pr-2\"}\n... \"msg\":\"Namespace-ul este procesat.\",\"namespaceName\":\"project-pr-2\",\"namespaceCreationTimestamp\":\"2020-06-16 18:43:58 +0300 EEST\"}\n... \"msg\":\"Namespace-ul a fost \u0219ters.\",\"namespaceName\":\"project-pr-2\"}<\/code><\/pre>\n<p><\/p>\n<p>Dac\u0103 verific\u0103m prezen\u021ba resurselor, ele vor fi \u00een starea <code>Terminating<\/code> (proces de \u0219tergere) sau deja \u0219terse (ie\u0219irea comenzii este goal\u0103).<\/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>Pute\u021bi repeta procesul de creare <code>prize<\/code> de mai multe ori \u0219i s\u0103 v\u0103 asigura\u021bi c\u0103 acestea vor fi \u0219terse \u00een decurs de un minut.<\/p>\n<p><\/p>\n<h2>Alternative<\/h2>\n<p><\/p>\n<p>Ce se poate face \u00een locul operatorului care func\u021bioneaz\u0103 \u00eentr-un cluster? Exist\u0103 c\u00e2teva abord\u0103ri, toate imperfecte (iar dezavantajele lor sunt subiective), iar fiecare decide ce se potrive\u0219te cel mai bine pentru proiectul s\u0103u specific:<\/p>\n<p><\/p>\n<ol>\n<li>\n<p>A elimina ramura feature \u00een timpul construc\u021biei ramurii master de integrare continu\u0103.<\/p>\n<p><\/p>\n<ul>\n<li>Pentru asta trebuie s\u0103 \u0219ti\u021bi ce pull request este legat de commit-ul care este construit. Deoarece namespace-ul feature branch con\u021bine identificatorul pull request-ului \u2014 num\u0103rul s\u0103u, sau numele ramurii, identificatorul va trebui s\u0103 fie \u00eentotdeauna specificat \u00een commit.<\/li>\n<li>Build-urile ramurii master e\u0219ueaz\u0103. De exemplu, ave\u021bi urm\u0103toarele etape: desc\u0103rca\u021bi proiectul, rula\u021bi testele, construi\u021bi proiectul, face\u021bi publicare, trimite\u021bi notific\u0103ri, cur\u0103\u021ba\u021bi feature branch-ul ultimului pull request. Dac\u0103 build-ul e\u0219ueaz\u0103 la trimiterea notific\u0103rii, va trebui s\u0103 \u0219terge\u021bi toate resursele din cluster manual.<\/li>\n<li>F\u0103r\u0103 un context adecvat, \u0219tergerea feature branch-ului \u00een build-ul master nu este evident\u0103.<\/li>\n<\/ul>\n<p>\n<\/li>\n<li>\n<p>Utilizarea webhook-urilor (<noindex><a rel=\"nofollow\" href=\"https:\/\/github.community\/t\/trigger-jenkins-job-when-a-pull-request-is-merged-to-a-branch\/1169\">exemplu<\/a><\/noindex>).<\/p>\n<p><\/p>\n<ul>\n<li>Este posibil ca acesta s\u0103 nu fie abordarea ta. De exemplu, \u00een <noindex><a rel=\"nofollow\" href=\"https:\/\/www.jenkins.io\">Jenkins<\/a><\/noindex>, doar un tip de pipeline accept\u0103 posibilitatea de a salva configura\u021biile sale \u00een codul surs\u0103. Atunci c\u00e2nd se utilizeaz\u0103 webhook-uri, trebuie s\u0103 scrie\u021bi propriul script pentru procesarea acestora. Acest script va trebui s\u0103 fie plasat \u00een interfa\u021ba Jenkins-ului, ceea ce este greu de \u00eentre\u021binut.<\/li>\n<\/ul>\n<p>\n<\/li>\n<li>\n<p>Scrie\u021bi <noindex><a rel=\"nofollow\" href=\"https:\/\/kubernetes.io\/docs\/concepts\/workloads\/controllers\/cron-jobs\/\">Cronjob<\/a><\/noindex> \u0219i adaug\u0103 clusterul Kubernetes.<\/p>\n<p><\/p>\n<ul>\n<li>Cheltuiala de timp pentru scrierea \u0219i suportul acestuia.<\/li>\n<li>Operatorul func\u021bioneaz\u0103 deja \u00eentr-un stil similar, fiind documentat \u0219i \u00eentre\u021binut.<\/li>\n<\/ul>\n<p>\n<\/li>\n<\/ol>\n<p><\/p>\n<p>Mul\u021bumim pentru aten\u021bia acordat\u0103 articolului. <strong><noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/dmytrostriletskyi\/stale-feature-branch-operator\">Link c\u0103tre proiectul de pe Github<\/a><\/noindex><\/strong>.<\/p>\n<p>Sursa: <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.2.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\/ro\/blog\/administrirovanie\/udalyaem-ustarevshuyu-feature-branch-v-kubernetes-klastere\" \/>\n\t<meta name=\"generator\" content=\"All in One SEO (AIOSEO) 5.0.2.1\" \/>\n\t\t<meta property=\"og:locale\" content=\"ro_RO\" \/>\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\/ro\/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\udd47Eliminarea ramurii feature \u00eenvechite \u00een clusterul Kubernetes | ProHoster","description":"Bun\u0103!","canonical_url":"https:\/\/prohoster.info\/ro\/blog\/administrirovanie\/udalyaem-ustarevshuyu-feature-branch-v-kubernetes-klastere","robots":"max-image-preview:large","keywords":"","webmasterTools":{"miscellaneous":""},"schema":null,"og:locale":"ro_RO","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\/ro\/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\/ro\/wp-json\/wp\/v2\/posts\/86902","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/prohoster.info\/ro\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/prohoster.info\/ro\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/prohoster.info\/ro\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/prohoster.info\/ro\/wp-json\/wp\/v2\/comments?post=86902"}],"version-history":[{"count":0,"href":"https:\/\/prohoster.info\/ro\/wp-json\/wp\/v2\/posts\/86902\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/prohoster.info\/ro\/wp-json\/wp\/v2\/media\/86903"}],"wp:attachment":[{"href":"https:\/\/prohoster.info\/ro\/wp-json\/wp\/v2\/media?parent=86902"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/prohoster.info\/ro\/wp-json\/wp\/v2\/categories?post=86902"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/prohoster.info\/ro\/wp-json\/wp\/v2\/tags?post=86902"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}