{"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\/hr\/blog\/administrirovanie\/udalyaem-ustarevshuyu-feature-branch-v-kubernetes-klastere","title":{"rendered":"Bri\u0161emo zastarjeli feature branch u Kubernetes klasteru","gt_translate_keys":[{"key":"rendered","format":"text"}]},"content":{"rendered":"<p><img decoding=\"async\" alt=\"Bri\u0161emo zastarjeli feature branch u Kubernetes klasteru\" src=\"\/wp-content\/uploads\/2020\/07\/d97c0cce385c587e16f26f6d19b9d108.png\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p>Pozdrav! <b>Feature branch<\/b> (aka deploy preview, review app) \u2014 to je kada se ne depoyje samo master grana, ve\u0107 i svaki pull request na jedinstvenom URL-u. Mo\u017eete provjeriti radi li kod u produkcijskom okru\u017eenju, a funkcionalnost mo\u017eete pokazati drugim programerima ili produktnim menad\u017eerima. Dok radite na pull requestu, svaki novi commit trenutnog depoya bri\u0161e stari kod, dok se novi deploy za novi kod lansira. Pitanja se mogu pojaviti kada ste spojili pull request u master granu. Feature branch vi\u0161e nije potrebna, ali resursi Kubernetes-a i dalje se nalaze u klasteru.<\/p>\n<p><noindex><a rel=\"nofollow\" name=\"habracut\"><\/a><\/noindex><\/p>\n<h2>Jo\u0161 o feature branch-ima<\/h2>\n<p><\/p>\n<p>Jedan od pristupa za izradu feature branch-a u Kubernetes-u je kori\u0161tenje namespace-ova. Ukratko, produkcijska konfiguracija izgleda ovako:<\/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>Za feature branch se kreira namespace s njenim identifikatorom (npr. broj pull request-a) i nekim prefiksom\/postfiksom (npr., <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>Uglavnom, napisao sam <b>Kubernetes Operator<\/b> (aplikacija koja ima pristup resursima klastera), <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/dmytrostriletskyi\/stale-feature-branch-operator\">veza na projekt na Github-u<\/a><\/noindex>. On uklanja namespace-ove koji se odnose na stare feature branch-e. U Kubernetes-u, ako se ukloni namespace, drugi resursi u tom namespace-u se tako\u0111er automatski uklanjaju.<\/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>O tome kako implementirati feature branch-e u klaster mo\u017eete pro\u010ditati <noindex><a rel=\"nofollow\" href=\"https:\/\/itnext.io\/feature-deployments-in-kubernetes-c74bdcff0d8e\">ovdje<\/a><\/noindex> i <noindex><a rel=\"nofollow\" href=\"https:\/\/codefresh.io\/kubernetes-tutorial\/dynamically-creating-k8s-namespaces-every-branch-pull-request-2\">ovdje<\/a><\/noindex>.<\/p>\n<p><\/p>\n<h2>Motivacija<\/h2>\n<p><\/p>\n<p>Hajde da pogledamo tipi\u010dan \u017eivotni ciklus pull request-a s neprekidnom integracijom (<code>kontinuirana integracija<\/code>):<\/p>\n<p><\/p>\n<ol>\n<li>Guramo novi commit u granu.<\/li>\n<li>Na gradnji se pokre\u0107u linters i\/ili testovi.<\/li>\n<li>Konfiguracije Kubernetes pull request-a se formiraju u letu (npr. njegov broj se umetne u gotov \u0161ablon).<\/li>\n<li>Pomo\u0107u kubectl apply konfiguracije se \u0161alju u klaster (deploy).<\/li>\n<li>Pull request se spaja u master granu.<\/li>\n<\/ol>\n<p><\/p>\n<p>Dok radite na pull requestu, svaki novi commit trenutnog depoya bri\u0161e stari kod, dok se novi deploy za novi kod lansira. No, kada se pull request spoji u master granu, gradi se samo master grana. Na kraju, zaboravimo na pull request, a njegovi Kubernetes resursi i dalje se nalaze u klasteru.<\/p>\n<p><\/p>\n<h2>Kako koristiti<\/h2>\n<p><\/p>\n<p>Instalirati projekt naredbom ispod:<\/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>Kreirati datoteku s sljede\u0107im sadr\u017eajem i instalirati preko <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>Parametar <b>namespaceSubstring<\/b> potrebno je za filtriranje namespace-ova za pull request-ove od drugih namespace-ova. Na primjer, ako u klasteru postoje sljede\u0107i namespace-ovi: <code>habr-back-end<\/code>, <code>habr-front-end<\/code>, <code>habr-back-end-pr-17<\/code>, <code>habr-back-end-pr-33<\/code>, tada \u0107e kandidati za brisanje biti <code>habr-back-end-pr-17<\/code>, <code>habr-back-end-pr-33<\/code>.<\/p>\n<p><\/p>\n<p>Parametar <b>afterDaysWithoutDeploy<\/b> potrebno je za brisanje starih namespace-ova. Na primjer, ako je namespace kreiran <code>prije 3 dana i 1 sat<\/code> , a u parametru je navedeno <code>3 dana<\/code>, ovaj namespace \u0107e biti obrisan. Radi i u obrnutom smjeru, ako je namespace kreiran <code>prije 2 dana i 23 sata<\/code> , a u parametru je navedeno <code>3 dana<\/code>, ovaj namespace ne\u0107e biti obrisan.<\/p>\n<p><\/p>\n<p>Postoji jo\u0161 jedan parametar koji odre\u0111uje koliko \u010desto skenirati sve namespace-ove i provjeravati dane bez depoya \u2014 <b>checkEveryMinutes<\/b>. Po defaultu je postavljen na <code>30 minuta<\/code>.<\/p>\n<p><\/p>\n<h2>Kako to funkcionira<\/h2>\n<p><\/p>\n<p>U praksi, potrebno je:<\/p>\n<p><\/p>\n<ol>\n<li><noindex><a rel=\"nofollow\" href=\"https:\/\/docs.docker.com\/get-docker\">Docker<\/a><\/noindex> za rad u izoliranom okru\u017eenju.<\/li>\n<li><noindex><a rel=\"nofollow\" href=\"https:\/\/kubernetes.io\/docs\/tasks\/tools\/install-minikube\">Minikube<\/a><\/noindex> pokrenuti Kubernetes klaster lokalno.<\/li>\n<li><noindex><a rel=\"nofollow\" href=\"https:\/\/kubernetes.io\/docs\/tasks\/tools\/install-kubectl\">kubectl<\/a><\/noindex> \u2014 komandna linija za upravljanje klasterom.<\/li>\n<\/ol>\n<p><\/p>\n<p>Pokre\u0107emo Kubernetes klaster lokalno:<\/p>\n<p><\/p>\n<pre><code class=\"bash\">$ minikube start --vm-driver=docker\nminikube v1.11.0 na Darwin 10.15.5\nKoriste\u0107i docker driver na osnovu postoje\u0107eg profila.\nPokre\u0107em kontrolnu platformu minikube u klasteru minikube.<\/code><\/pre>\n<p><\/p>\n<p>Unesite <code>kubectl<\/code> koristiti lokalni klaster po defaultu:<\/p>\n<p><\/p>\n<pre><code class=\"bash\">$ kubectl config use-context minikube\nPre\u0161ao na kontekst \"minikube\".<\/code><\/pre>\n<p><\/p>\n<p>Preuzimamo konfiguracije za production okru\u017eenje:<\/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>Budu\u0107i da su produkcijske konfiguracije postavljene da provjeravaju stare namespace-ove, a u na\u0161em novom podignutom klasteru ih nema, zamijenit \u0107emo varijablu okru\u017eenja <code>IS_DEBUG<\/code> na <code>true<\/code>. Sa ovom vrijedno\u0161\u0107u, parametar <code>afterDaysWithoutDeploy<\/code> ne uzima se u obzir i namespace-ovi se ne provjeravaju na dane bez depoya, samo na prisutnost podstringa (<code>-pr-<\/code>).<\/p>\n<p><\/p>\n<p>Ako ste na <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>Ako ste na <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>Instaliramo 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>Provjeravamo da li je resurs <code>StaleFeatureBranch<\/code>:<\/p>\n<p><\/p>\n<pre><code class=\"bash\">$ kubectl api-resources | grep stalefeaturebranches\nIME                 ... APIGROUP                             ... VRSTA\nstalefeaturebranches ... feature-branch.dmytrostriletskyi.com ... StaleFeatureBranch<\/code><\/pre>\n<p><\/p>\n<p>Provjeravamo da li je u klasteru instaliran operator:<\/p>\n<p><\/p>\n<pre><code class=\"bash\">$ kubectl get pods --namespace stale-feature-branch-operator\nIME                                               ... STATUS  ... STAROST\nstale-feature-branch-operator-6bfbfd4df8-m7sch ... Radi ... 38s<\/code><\/pre>\n<p><\/p>\n<p>Ako pogledamo njegove logove, spreman je za obradu resursa <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>Instaliramo gotove <code>fixtures<\/code> (gotove konfiguracije za modeliranje resursa klastera) za resurs <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>U konfiguracijama je navedeno tra\u017eiti namespace-ove koji sadr\u017ee podstring <code>-pr-<\/code> jednom u <code>1 minuta<\/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>Operator je reagirao i spreman je provjeriti namespace-ove:<\/p>\n<p><\/p>\n<pre><code class=\"bash\">$ kubectl logs stale-feature-branch-operator-6bfbfd4df8-m7sch -n stale-feature-branch-operator\n... \"msg\":\"Obra\u0111uje se zastarjela funkcionalna grana.\",\"namespaceSubstring\":\"-pr-\",\"afterDaysWithoutDeploy\":1,\"checkEveryMinutes\":1,\"isDebug\":\"true\"}<\/code><\/pre>\n<p><\/p>\n<p>Instaliramo <code>fixtures<\/code>, koji sadr\u017ee dva namespace-a (<code>project-pr-1<\/code>, <code>project-pr-2<\/code>) i njihove <code>deploymente<\/code>, <code>servise<\/code>, <code>ingress<\/code>, i tako dalje:<\/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 kreiran\ndeployment.apps\/project-pr-1 kreiran\nservice\/project-pr-1 kreiran\nhorizontalpodautoscaler.autoscaling\/project-pr-1 kreiran\nsecret\/project-pr-1 kreiran\nconfigmap\/project-pr-1 kreiran\ningress.extensions\/project-pr-1 kreiran\nnamespace\/project-pr-2 kreiran\ndeployment.apps\/project-pr-2 kreiran\nservice\/project-pr-2 kreiran\nhorizontalpodautoscaler.autoscaling\/project-pr-2 kreiran\nsecret\/project-pr-2 kreiran\nconfigmap\/project-pr-2 kreiran\ningress.extensions\/project-pr-2 kreiran<\/code><\/pre>\n<p><\/p>\n<p>Provjeravamo da li su svi resursi gore uspje\u0161no kreirani:<\/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>Budu\u0107i da smo uklju\u010dili <code>debug<\/code>, namespace-ove <code>project-pr-1<\/code> i <code>project-pr-2<\/code>, stoga \u0107e se svi ostali resursi odmah ukloniti bez obzira na parametar <code>afterDaysWithoutDeploy<\/code>. U logovima operatora to je vidljivo:<\/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 treba biti izbrisan zbog aktiviranog debug moda.\",\"namespaceName\":\"project-pr-1\"\n... \"msg\":\"Namespace se obra\u0111uje.\",\"namespaceName\":\"project-pr-1\",\"namespaceCreationTimestamp\":\"2020-06-16 18:43:58 +0300 EEST\"\n... \"msg\":\"Namespace je izbrisan.\",\"namespaceName\":\"project-pr-1\"\n... \"msg\":\"Namespace treba biti izbrisan zbog aktiviranog debug moda.\",\"namespaceName\":\"project-pr-2\"\n... \"msg\":\"Namespace se obra\u0111uje.\",\"namespaceName\":\"project-pr-2\",\"namespaceCreationTimestamp\":\"2020-06-16 18:43:58 +0300 EEST\"\n... \"msg\":\"Namespace je izbrisan.\",\"namespaceName\":\"project-pr-2\"}<\/code><\/pre>\n<p><\/p>\n<p>Ako provjerite prisutnost resursa, bit \u0107e u statusu <code>Terminating<\/code> (proces uklanjanja) ili su ve\u0107 uklonjeni (izlaz komande je prazan).<\/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>Mo\u017eete ponoviti proces kreiranja <code>fixtures<\/code> several times and ensure that they will be removed within a minute.<\/p>\n<p><\/p>\n<h2>Alternatives<\/h2>\n<p><\/p>\n<p>What can be done instead of an operator that works in a cluster? There are several approaches, all of them are not ideal (and their disadvantages are subjective), and everyone decides what suits their specific project best:<\/p>\n<p><\/p>\n<ol>\n<li>\n<p>Delete the feature branch during the continuous integration build of the master branch.<\/p>\n<p><\/p>\n<ul>\n<li>Za to je potrebno znati koji pull request se odnosi na commit koji se gradi. Budu\u0107i da namespace funkcionalne grane sadr\u017ei identifikator pull request-a \u2014 njegov broj ili naziv grane, identifikator \u0107e uvijek biti potreban u commitu.<\/li>\n<li>Gradnje master grana ne prolaze. Na primjer, imate sljede\u0107e faze: preuzimanje projekta, pokretanje testova, izrada projekta, izrada verzije, slanje obavijesti, \u010di\u0161\u0107enje funkcionalne grane posljednjeg pull request-a. Ako gradnja ne pro\u0111e pri slanju obavijesti, morat \u0107ete ru\u010dno izbrisati sve resurse u klasteru.<\/li>\n<li>Bez odgovaraju\u0107eg konteksta, brisanje funkcionalne grane u master izgradnji nije o\u010dito.<\/li>\n<\/ul>\n<p>\n<\/li>\n<li>\n<p>Kori\u0161tenje webhook-ova (<noindex><a rel=\"nofollow\" href=\"https:\/\/github.community\/t\/trigger-jenkins-job-when-a-pull-request-is-merged-to-a-branch\/1169\">primjer<\/a><\/noindex>).<\/p>\n<p><\/p>\n<ul>\n<li>Perhaps this is not your approach. For example, in <noindex><a rel=\"nofollow\" href=\"https:\/\/www.jenkins.io\">Jenkins<\/a><\/noindex>, samo jedan tip pipeline-a podr\u017eava mogu\u0107nost pohranjivanja njegove konfiguracije u izvornom kodu. Pri kori\u0161tenju webhook-ova potrebno je napisati vlastiti skript za njihovu obradu. Ovaj skript treba postaviti u su\u010delje Jenkins-a, \u0161to je te\u0161ko odr\u017eavati.<\/li>\n<\/ul>\n<p>\n<\/li>\n<li>\n<p>Write <noindex><a rel=\"nofollow\" href=\"https:\/\/kubernetes.io\/docs\/concepts\/workloads\/controllers\/cron-jobs\/\">Cronjob<\/a><\/noindex> and add the Kubernetes cluster.<\/p>\n<p><\/p>\n<ul>\n<li>Time spent on writing and maintaining.<\/li>\n<li>The operator already works in a similar style, is documented, and supported.<\/li>\n<\/ul>\n<p>\n<\/li>\n<\/ol>\n<p><\/p>\n<p>Thank you for your attention to the article. <strong><noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/dmytrostriletskyi\/stale-feature-branch-operator\">Link to the project on Github<\/a><\/noindex><\/strong>.<\/p>\n<p>Izvor: <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.4 - 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\/hr\/blog\/administrirovanie\/udalyaem-ustarevshuyu-feature-branch-v-kubernetes-klastere\" \/>\n\t\t<meta name=\"generator\" content=\"All in One SEO (AIOSEO) 5.0.4\" \/>\n\t\t<meta property=\"og:locale\" content=\"hr_HR\" \/>\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\/hr\/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\udd47Deleting the outdated feature branch in the Kubernetes cluster | ProHoster","description":"Pozdrav!","canonical_url":"https:\/\/prohoster.info\/hr\/blog\/administrirovanie\/udalyaem-ustarevshuyu-feature-branch-v-kubernetes-klastere","robots":"max-image-preview:large","keywords":"","webmasterTools":{"miscellaneous":""},"schema":null,"og:locale":"hr_HR","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\/hr\/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\/hr\/wp-json\/wp\/v2\/posts\/86902","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/prohoster.info\/hr\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/prohoster.info\/hr\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/prohoster.info\/hr\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/prohoster.info\/hr\/wp-json\/wp\/v2\/comments?post=86902"}],"version-history":[{"count":0,"href":"https:\/\/prohoster.info\/hr\/wp-json\/wp\/v2\/posts\/86902\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/prohoster.info\/hr\/wp-json\/wp\/v2\/media\/86903"}],"wp:attachment":[{"href":"https:\/\/prohoster.info\/hr\/wp-json\/wp\/v2\/media?parent=86902"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/prohoster.info\/hr\/wp-json\/wp\/v2\/categories?post=86902"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/prohoster.info\/hr\/wp-json\/wp\/v2\/tags?post=86902"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}