{"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\/pl\/blog\/administrirovanie\/3-way-merge-v-werf-deploj-v-kubernetes-s-helm-na-steroidah","title":{"rendered":"Trzyetapowe scalanie w werf: wdra\u017canie w Kubernetes z Helm \u00abna sterydach\u00bb","gt_translate_keys":[{"key":"rendered","format":"text"}]},"content":{"rendered":"<p>Nasta\u0142o to, na co d\u0142ugo czekali\u015bmy (i nie tylko my): <noindex><a rel=\"nofollow\" href=\"https:\/\/werf.io\/\">werf<\/a><\/noindex>, nasze narz\u0119dzie Open Source do tworzenia aplikacji i ich dostarczania w Kubernetes, teraz wspiera wprowadzanie zmian za pomoc\u0105 patchy 3-way-merge! Dodatkowo pojawi\u0142a si\u0119 mo\u017cliwo\u015b\u0107 adoptowania istniej\u0105cych zasob\u00f3w K8s do wyda\u0144 Helm bez konieczno\u015bci ich ponownego tworzenia.<\/p>\n<p><img decoding=\"async\" alt=\"Trzyetapowe scalanie w werf: wdra\u017canie w Kubernetes z Helm \u00abna sterydach\u00bb\" src=\"\/wp-content\/uploads\/2019\/11\/e5be3544c201f7b2c97fba216a49506d.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nM\u00f3wi\u0105c kr\u00f3tko, ustawiamy <code>WERF_THREE_WAY_MERGE=enabled<\/code> \u2014 otrzymujemy wdro\u017cenie \u201ejak w <code>kubectl apply<\/code>\u201d, kompatybilne z istniej\u0105cymi instalacjami na Helm 2, a nawet troch\u0119 wi\u0119cej.<\/p>\n<p>Ale zacznijmy od teorii: czym w og\u00f3le s\u0105 patchy 3-way-merge, jak ludzie doszli do podej\u015bcia z ich generowaniem i dlaczego s\u0105 wa\u017cne w procesach CI\/CD opartych na infrastrukturze Kubernetes? A potem przyjrzymy si\u0119, czym jest 3-way-merge w werf, jakie tryby s\u0105 domy\u015blnie u\u017cywane i jak nimi zarz\u0105dza\u0107.<noindex><a rel=\"nofollow\" name=\"habracut\"><\/a><\/noindex><\/p>\n<h2>Czym jest patch 3-way-merge?<\/h2>\n<p>\nZaczynamy od zadania wdro\u017cenia zasob\u00f3w opisanych w manifestach YAML w Kubernetes.<\/p>\n<p>Do pracy z zasobami API Kubernetes oferuje takie podstawowe operacje jak: create, patch, replace i delete. Zak\u0142ada si\u0119, \u017ce za ich pomoc\u0105 nale\u017cy skonstruowa\u0107 wygodne, ci\u0105g\u0142e wdra\u017canie zasob\u00f3w w klastrze. Jak?<\/p>\n<h3>Impertywne komendy kubectl<\/h3>\n<p>\nPierwszym podej\u015bciem do zarz\u0105dzania obiektami w Kubernetes jest u\u017cycie impertywnych komend kubectl do tworzenia, modyfikowania i usuwania tych obiekt\u00f3w. M\u00f3wi\u0105c pro\u015bciej:<\/p>\n<ul>\n<li> poleceniem <code>kubectl run<\/code> mo\u017cemy uruchomi\u0107 Deployment lub Job:\n<pre><code class=\"bash\">kubectl run --generator=deployment\/apps.v1 NAZWA_DEPOLAMENTU --image=IMAGE<\/code><\/pre>\n<\/li>\n<li> poleceniem <code>kubectl scale<\/code> \u2014 zmieni\u0107 liczb\u0119 replik:\n<pre><code class=\"bash\">kubectl scale --replicas=3 deployment\/mysql<\/code><\/pre>\n<\/li>\n<li>itd.<\/li>\n<\/ul>\n<p>\nTo podej\u015bcie mo\u017ce wydawa\u0107 si\u0119 wygodne na pierwszy rzut oka. Jednak s\u0105 problemy: <\/p>\n<ol>\n<li> Jak odzwierciedli\u0107 konfiguracj\u0119 <b>automatyzowa\u0107<\/b>.<\/li>\n<li> Jak <b>w Git? Jak dokonywa\u0107 przegl\u0105du zmian, kt\u00f3re zachodz\u0105 w klastrze?<\/b> Jak zapewni\u0107<\/li>\n<li> konfiguracj\u0119 po restarcie? <b>odtwarzalno\u015b\u0107<\/b> Jasne jest, \u017ce takie podej\u015bcie \u017ale komponuje si\u0119 z przechowywaniem razem z kodem aplikacji i infrastruktur\u0105 jako kodem (IaC; a nawet<\/li>\n<li>\u2026<\/li>\n<\/ol>\n<p>\njako bardziej nowoczesna wersja, zdobywaj\u0105ca popularno\u015b\u0107 w ekosystemie Kubernetes). Dlatego dalszy rozw\u00f3j tych komend w kubectl nie znalaz\u0142 uznania. <noindex><a rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/company\/flant\/blog\/458878\/\">GitOps<\/a><\/noindex> Operacje create, get, replace i delete<\/p>\n<h3>Z podstawowym<\/h3>\n<p>\ntworzeniem <b>wszystko jest proste: wysy\u0142amy manifest do operacji<\/b> w kube api i zas\u00f3b jest stworzony. Reprezentacja YAML manifestu mo\u017ce by\u0107 przechowywana w Git, a do utworzenia \u2014 u\u017cywamy komendy <code>create<\/code> kubectl create -f manifest.yaml <code>usuni\u0119cie<\/code>.<\/p>\n<p>Z <b>te\u017c jest proste: podstawiamy ten sam<\/b> manifest.yaml <code>z Git do komendy<\/code> kubectl delete -f manifest.yaml <code>kubectl delete -f manifest.yaml<\/code>.<\/p>\n<p>Operacja <b><code>replace<\/code><\/b> umo\u017cliwia ca\u0142kowit\u0105 wymian\u0119 konfiguracji zasobu na now\u0105, bez tworzenia zasobu od nowa. Oznacza to, \u017ce przed dokonaniem zmiany w zasobie warto zapyta\u0107 o obecn\u0105 wersj\u0119 w operacji <code>get<\/code>, zmieni\u0107 j\u0105 i zaktualizowa\u0107 operacj\u0105 <code>replace<\/code>. W kube apiserver wbudowane jest <noindex><a rel=\"nofollow\" href=\"https:\/\/en.wikipedia.org\/wiki\/Optimistic_concurrency_control\">optymistyczne blokowanie<\/a><\/noindex> , i je\u015bli po operacji <code>get<\/code> obiekt si\u0119 zmieni, to operacja <code>replace<\/code> nie powiedzie si\u0119.<\/p>\n<p>Aby przechowywa\u0107 konfiguracj\u0119 w Git i aktualizowa\u0107 za pomoc\u0105 replace, nale\u017cy wykona\u0107 operacj\u0119 <code>get<\/code>, po\u0142\u0105czy\u0107 konfiguracj\u0119 z Gita z tym, co otrzymali\u015bmy, i wykona\u0107 <code>replace<\/code>. Standardowo kubectl pozwala jedynie korzysta\u0107 z komendy <code>kubectl replace -f manifest.yaml<\/code>, gdzie <code>z Git do komendy<\/code> \u2014 ju\u017c ca\u0142kowicie przygotowany (w naszym przypadku \u2014 po\u0142\u0105czony) manifest, kt\u00f3ry nale\u017cy zainstalowa\u0107. Wynika z tego, \u017ce u\u017cytkownik musi wdro\u017cy\u0107 \u0142\u0105czenie manifest\u00f3w, a to nie jest proste zadanie\u2026<\/p>\n<p>Warto r\u00f3wnie\u017c zauwa\u017cy\u0107, \u017ce chocia\u017c <code>z Git do komendy<\/code> jest przechowywana w Gicie, nie mo\u017cemy z g\u00f3ry wiedzie\u0107, czy nale\u017cy tworzy\u0107 obiekt, czy go aktualizowa\u0107 \u2014 to musi zrobi\u0107 oprogramowanie u\u017cytkownika.<\/p>\n<p>Podsumowuj\u0105c: <b>czy mo\u017cemy zbudowa\u0107 ci\u0105g\u0142e wdro\u017cenie<\/b> tylko za pomoc\u0105 create, replace i delete, zapewniaj\u0105c przechowywanie konfiguracji infrastruktury w Gicie razem z kodem i wygodnym CI\/CD?<\/p>\n<p>W zasadzie, mo\u017cemy\u2026 Aby to osi\u0105gn\u0105\u0107, <b>nale\u017cy zrealizowa\u0107 operacj\u0119 \u0142\u0105czenia<\/b> manifest\u00f3w oraz jak\u0105\u015b obudow\u0119, kt\u00f3ra:<\/p>\n<ul>\n<li> sprawdza, czy obiekt istnieje w klastrze,<\/li>\n<li> wykonuje pocz\u0105tkowe utworzenie zasobu,<\/li>\n<li> aktualizuje lub usuwa go.<\/li>\n<\/ul>\n<p>\nPodczas aktualizacji nale\u017cy wzi\u0105\u0107 pod uwag\u0119, \u017ce <i>zas\u00f3b m\u00f3g\u0142 si\u0119 zmieni\u0107<\/i> od ostatniego <code>get<\/code> i automatycznie obs\u0142ugiwa\u0107 przypadek optymistycznego blokowania \u2014 wykonywa\u0107 ponowne pr\u00f3by aktualizacji.<\/p>\n<p>Jednak dlaczego wynajdowa\u0107 ko\u0142o na nowo, skoro kube-apiserver oferuje inny spos\u00f3b aktualizacji zasob\u00f3w: operacj\u0119 <code>patch<\/code>, kt\u00f3ra uwalnia u\u017cytkownika od cz\u0119\u015bci opisanych problem\u00f3w?<\/p>\n<h3>Patch<\/h3>\n<p>\nZ dotarli\u015bmy do poprawek.<\/p>\n<p>Poprawki to podstawowy spos\u00f3b wprowadzania zmian w istniej\u0105cych obiektach w Kubernetes. Operacja <code>patch<\/code> dzia\u0142a w ten spos\u00f3b, \u017ce:<\/p>\n<ul>\n<li> u\u017cytkownik kube-apiserver musi wys\u0142a\u0107 poprawk\u0119 w formacie JSON i wskaza\u0107 obiekt,<\/li>\n<li> a apiserver sam rozwi\u0105\u017ce aktualny stan obiektu i przekszta\u0142ci go do wymaganego kszta\u0142tu.<\/li>\n<\/ul>\n<p>\nOptymistyczne blokowanie w tym przypadku nie jest wymagane. Ta operacja jest bardziej deklaratywna w por\u00f3wnaniu z replace, chocia\u017c pocz\u0105tkowo mo\u017ce si\u0119 wydawa\u0107 odwrotnie.<\/p>\n<p>Tak wi\u0119c:<\/p>\n<ul>\n<li> za pomoc\u0105 operacji <code>create<\/code> tworzymy obiekt na podstawie manifestu z Gita,<\/li>\n<li> z pomoc\u0105 <code>usu\u0144<\/code> \u2014 usuwamy, je\u015bli obiekt nie jest ju\u017c potrzebny,<\/li>\n<li> z pomoc\u0105 <code>patch<\/code> \u2014 zmieniamy obiekt, przekszta\u0142caj\u0105c go do formy opisanej w Gicie.<\/li>\n<\/ul>\n<p>\nAby to zrobi\u0107, nale\u017cy stworzy\u0107 <i>odpowiedni\u0105 \u0142atk\u0119<\/i>!<\/p>\n<h3>Jak dzia\u0142aj\u0105 \u0142atki w Helm 2: 2-way-merge<\/h3>\n<p>\nPodczas pierwszej instalacji wersji Helm wykonuje operacj\u0119 <code>create<\/code> dla zasob\u00f3w wykresu.<\/p>\n<p>Podczas aktualizacji wersji Helm dla ka\u017cdego zasobu:<\/p>\n<ul>\n<li> oblicza \u0142atk\u0119 mi\u0119dzy wersj\u0105 zasobu z poprzedniego wykresu a aktualn\u0105 wersj\u0105 wykresu,<\/li>\n<li> zastosowuje t\u0119 \u0142atk\u0119.<\/li>\n<\/ul>\n<p>\nTak\u0105 \u0142atk\u0119 b\u0119dziemy nazywa\u0107 <b>2-way-merge patch,<\/b>poniewa\u017c w jej tworzeniu bior\u0105 udzia\u0142 2 manifesty:<\/p>\n<ul>\n<li> manifest zasobu z poprzedniej wersji,<\/li>\n<li> manifest zasobu z aktualnej wersji.<\/li>\n<\/ul>\n<p>\nPodczas usuwania operacja <code>usu\u0144<\/code> w kube apiserver jest wywo\u0142ywana dla zasob\u00f3w, kt\u00f3re zosta\u0142y zadeklarowane w poprzedniej wersji, ale nie s\u0105 zadeklarowane w aktualnej.<\/p>\n<p>Podej\u015bcie z 2-way-merge patch ma problem: prowadzi to do <b>niesynchronizacji rzeczywistego stanu zasobu w klastrze i manifestu w Git<\/b>.<\/p>\n<h3>Ilustracja problemu na przyk\u0142adzie<\/h3>\n<p><\/p>\n<ul>\n<li> W Git, w wykresie jest zapisany manifest, w kt\u00f3rym pole <code>image<\/code> w Deployment ma warto\u015b\u0107 <code>ubuntu:18.04<\/code>.<\/li>\n<li> U\u017cytkownik przez <code>kubectl edit<\/code> zmieni\u0142 warto\u015b\u0107 tego pola na <code>ubuntu:19.04<\/code>.<\/li>\n<li> Podczas ponownego wdra\u017cania wykresu Helm <i>nie generuje \u0142atki,<\/i>poniewa\u017c pole <code>image<\/code> w poprzedniej wersji wydania i w aktualnym wykresie s\u0105 identyczne.<\/li>\n<li> Po ponownym wdro\u017ceniu <code>image<\/code> pozostaje <code>ubuntu:19.04<\/code>, chocia\u017c w wykresie napisano <code>ubuntu:18.04<\/code>.<\/li>\n<\/ul>\n<p>\nUzyskali\u015bmy niesynchronizacj\u0119 i stracili\u015bmy deklaratywno\u015b\u0107.<\/p>\n<h3>Co to jest zsynchronizowany zas\u00f3b?<\/h3>\n<p>\nOg\u00f3lnie rzecz bior\u0105c, <i>Pe\u0142ne<\/i> zgodno\u015b\u0107 manifestu zasobu w dzia\u0142aj\u0105cym klastrze z manifestem z Git jest niemo\u017cliwe do osi\u0105gni\u0119cia. Poniewa\u017c w rzeczywistym manife\u015bcie mog\u0105 by\u0107 adnotacje\/etykiety, dodatkowe kontenery i inne dane, kt\u00f3re s\u0105 dynamicznie dodawane i usuwane przez jakie\u015b kontrolery. Te dane chcemy trzyma\u0107 poza Git. Jednak chcemy, aby przy wdra\u017caniu te pola, kt\u00f3re wyra\u017anie wskazali\u015bmy w Git, przyjmowa\u0142y odpowiednie warto\u015bci.<\/p>\n<p>Powstaje og\u00f3lne <b>zasada zsynchronizowanego zasobu<\/b>: przy wdra\u017caniu zasobu mo\u017cna zmienia\u0107 lub usuwa\u0107 tylko te pola, kt\u00f3re s\u0105 wyra\u017anie okre\u015blone w manife\u015bcie z Git (lub by\u0142y okre\u015blone w poprzedniej wersji, a teraz zosta\u0142y usuni\u0119te).<\/p>\n<h3>3-way-merge patch<\/h3>\n<p>\nPodstawowa idea <noindex><a rel=\"nofollow\" href=\"https:\/\/en.wikipedia.org\/wiki\/Merge_(version_control)#Three-way_merge\">3-way-merge patch<\/a><\/noindex>: Generuje \u0142atk\u0119 mi\u0119dzy ostatni\u0105 zastosowan\u0105 wersj\u0105 manifestu z Git a docelow\u0105 wersj\u0105 manifestu z Git, uwzgl\u0119dniaj\u0105c aktualn\u0105 wersj\u0119 manifestu z dzia\u0142aj\u0105cego klastra. Ostateczna \u0142atka musi odpowiada\u0107 zasadzie zsynchronizowanego zasobu:<\/p>\n<ul>\n<li> Nowe pola, dodane do wersji docelowej, s\u0105 dodawane za pomoc\u0105 \u0142atki;<\/li>\n<li> Pola, kt\u00f3re wcze\u015bniej istnia\u0142y w ostatniej zastosowanej wersji i nie istniej\u0105 w docelowej, s\u0105 zerowane za pomoc\u0105 \u0142aty;<\/li>\n<li> Pola w bie\u017c\u0105cej wersji obiektu, r\u00f3\u017cni\u0105ce si\u0119 od docelowej wersji manifestu, s\u0105 aktualizowane za pomoc\u0105 \u0142aty.<\/li>\n<\/ul>\n<p>\nTo jest zasada, wed\u0142ug kt\u00f3rej generowane s\u0105 \u0142atki. <code>kubectl apply<\/code>:<\/p>\n<ul>\n<li> Ostatnia zastosowana wersja manifestu jest zapisywana w adnotacji samego obiektu, <\/li>\n<li> docelowa \u2014 jest pobierana z okre\u015blonego pliku YAML,<\/li>\n<li> bie\u017c\u0105ca \u2014 z dzia\u0142aj\u0105cego klastra.<\/li>\n<\/ul>\n<p>\nTeraz, kiedy wyja\u015bnili\u015bmy teori\u0119, pora opowiedzie\u0107, co zrobili\u015bmy w werf.<\/p>\n<h2>Zastosowanie zmian w werf<\/h2>\n<p>\nWcze\u015bniej werf, podobnie jak Helm 2, u\u017cywa\u0142 \u0142at 2-way-merge.<\/p>\n<h3>Repair patch<\/h3>\n<p>\nAby przej\u015b\u0107 na nowy typ \u0142atek \u2014 3-way-merge \u2014 pierwszym krokiem wprowadzili\u015bmy tzw. <b>\u0142atki repair<\/b>.<\/p>\n<p>Podczas wdra\u017cania u\u017cywana jest standardowa \u0142atka 2-way-merge, ale werf dodatkowo generuje tak\u0105 \u0142atk\u0119, kt\u00f3ra synchronizuje rzeczywisty stan zasobu z tym, co jest napisane w Git (ta \u0142atka jest tworzona z u\u017cyciem tej samej zasady synchronizowanego zasobu, opisanej powy\u017cej).<\/p>\n<p>W przypadku wyst\u0105pienia niesynchronizacji, na ko\u0144cu wdro\u017cenia u\u017cytkownik otrzymuje OSTRZE\u017bENIE z odpowiednim komunikatem oraz \u0142atk\u0105, kt\u00f3r\u0105 nale\u017cy zastosowa\u0107, aby przywr\u00f3ci\u0107 zas\u00f3b do stanu synchronizowanego. Ta \u0142atka jest r\u00f3wnie\u017c zapisywana w specjalnej adnotacji <code>werf.io\/repair-patch<\/code>. Zak\u0142ada si\u0119, \u017ce u\u017cytkownik r\u0119cznie <b>sam<\/b> zastosuje t\u0119 \u0142atk\u0119: werf jej nie zastosuje zasadniczo.<\/p>\n<p>Generowanie \u0142at repair jest tymczasowym \u015brodkiem, kt\u00f3ry umo\u017cliwia przetestowanie w praktyce tworzenie \u0142atek wed\u0142ug zasady 3-way-merge, ale nie ich automatyczne stosowanie. Obecnie ten tryb pracy jest w\u0142\u0105czony domy\u015blnie.<\/p>\n<h3>\u0141atka 3-way-merge tylko dla nowych wersji<\/h3>\n<p>\nOd 1 grudnia 2019 r. wersje beta i alfa werf zaczynaj\u0105 <b>domy\u015blnie<\/b> u\u017cywa\u0107 pe\u0142nych \u0142at 3-way-merge do stosowania zmian tylko dla nowych wyda\u0144 Helm, wdra\u017canych przez werf. Ju\u017c istniej\u0105ce wydania b\u0119d\u0105 nadal korzysta\u0107 z podej\u015bcia 2-way-merge + \u0142atki repair.<\/p>\n<p>Ten tryb pracy mo\u017cna w\u0142\u0105czy\u0107 jawnie przez ustawienie <code>WERF_THREE_WAY_MERGE_MODE=onlyNewReleases<\/code> ju\u017c teraz.<\/p>\n<p><i><b>Uwaga<\/b>: funkcja ta by\u0142a wprowadzana w werf przez kilka wyda\u0144: w kanale alfa zosta\u0142a uko\u0144czona od wersji <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/flant\/werf\/releases\/tag\/v1.0.5-alpha.19\">v1.0.5-alpha.19<\/a><\/noindex>, a w kanale beta \u2014 od <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>\u0142atka 3-way-merge dla wszystkich wyda\u0144<\/h3>\n<p>\nOd 15 grudnia 2019 r. wersje beta i alfa werf automatycznie u\u017cywaj\u0105 pe\u0142nych \u0142atek 3-way-merge do wprowadzania zmian w wszystkich wydaniach.<\/p>\n<p>Ten tryb pracy mo\u017cna w\u0142\u0105czy\u0107 jawnie przez ustawienie <code>WERF_THREE_WAY_MERGE_MODE=enabled<\/code> ju\u017c teraz.<\/p>\n<h3>Jak poradzi\u0107 sobie z automatycznym skalowaniem zasob\u00f3w?<\/h3>\n<p>\nW Kubernetesie istniej\u0105 dwa typy automatycznego skalowania: HPA (horyzontalne) i VPA (wertykalne).<\/p>\n<p>Horyzontalne automatycznie wybiera liczb\u0119 replik, wertykalne \u2014 liczb\u0119 zasob\u00f3w. Zar\u00f3wno liczba replik, jak i wymagania dotycz\u0105ce zasob\u00f3w s\u0105 okre\u015blane w manife\u015bcie zasobu (patrz: <code>spec.replicas<\/code> lub <code>spec.containers[].resources.limits.cpu<\/code>, <code>spec.containers[].resources.limits.memory<\/code> i <noindex><a rel=\"nofollow\" href=\"https:\/\/kubernetes.io\/docs\/concepts\/configuration\/manage-compute-resources-container\/#resource-requests-and-limits-of-pod-and-container\">inne<\/a><\/noindex>).<\/p>\n<p>Problem: je\u015bli u\u017cytkownik skonfiguruje zas\u00f3b w wykresie tak, \u017ce b\u0119d\u0105 w nim okre\u015blone warto\u015bci dla zasob\u00f3w lub replik, a dla danego zasobu w\u0142\u0105czone b\u0119d\u0105 auto-skaler, to przy ka\u017cdym wdro\u017ceniu werf zresetuje te warto\u015bci do tych, kt\u00f3re s\u0105 zapisane w manife\u015bcie wykresu.<\/p>\n<p>Rozwi\u0105zania dla problemu s\u0105 dwa. Na pocz\u0105tek najlepiej jest zrezygnowa\u0107 z wyra\u017anego okre\u015blenia automatycznie skalowanych warto\u015bci w manife\u015bcie wykresu. Je\u015bli jednak ten wariant z jakich\u015b powod\u00f3w nie jest odpowiedni (na przyk\u0142ad, poniewa\u017c w wykresie wygodnie jest okre\u015bli\u0107 pocz\u0105tkowe ograniczenia zasob\u00f3w i liczb\u0119 replik), werf oferuje nast\u0119puj\u0105ce adnotacje:<\/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>\nW przypadku posiadania takiej adnotacji werf nie zresetuje odpowiednich warto\u015bci przy ka\u017cdym wdro\u017ceniu, a jedynie ustawi je przy pocz\u0105tkowym utworzeniu zasobu.<\/p>\n<p>Szczeg\u00f3\u0142y \u2014 patrz w dokumentacji projektu na <noindex><a rel=\"nofollow\" href=\"https:\/\/werf.io\/documentation\/reference\/deploy_process\/resources_update_methods_and_adoption.html#deal-with-hpa\">HPA<\/a><\/noindex> i <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>Zabro\u0144 u\u017cycia 3-way-merge patch<\/h3>\n<p>\nU\u017cytkownik mo\u017ce na razie zabroni\u0107 u\u017cywania nowych \u0142atek w werf poprzez zmienn\u0105 \u015brodowiskow\u0105 <code>WERF_THREE_WAY_MERGE_MODE=disabled<\/code>. Jednak od <b>1 marca 2020 roku ten zakaz przestanie dzia\u0142a\u0107<\/b> i mo\u017cliwe b\u0119dzie jedynie u\u017cycie \u0142atek 3-way-merge.<\/p>\n<h2>Adopcja zasob\u00f3w w werf<\/h2>\n<p>\nOpanowanie metody wprowadzania zmian za pomoc\u0105 \u0142atek 3-way-merge pozwoli\u0142o nam od razu wdro\u017cy\u0107 tak\u0105 funkcj\u0119 jak adopcja istniej\u0105cych w klastrze zasob\u00f3w w wydaniu Helm.<\/p>\n<p>Helm 2 ma problem: nie mo\u017cna doda\u0107 do manifest\u00f3w wykresu zasobu, kt\u00f3ry ju\u017c istnieje w klastrze, bez jego przeregenerowania od podstaw (patrz: <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>). Nauczyli\u015bmy werf przyjmowa\u0107 istniej\u0105ce zasoby w wydaniu. W tym celu nale\u017cy na bie\u017c\u0105c\u0105 wersj\u0119 zasobu z dzia\u0142aj\u0105cego klastra ustawi\u0107 adnotacj\u0119 (na przyk\u0142ad za pomoc\u0105 <code>kubectl edit<\/code>):<\/p>\n<pre><code class=\"plaintext\">\"werf.io\/allow-adoption-by-release\": RELEASE_NAME<\/code><\/pre>\n<p>\nTeraz zas\u00f3b musi by\u0107 opisany w wykresie, a przy nast\u0119pnym wdra\u017caniu za pomoc\u0105 werf, o odpowiedniej nazwie, istniej\u0105cy zas\u00f3b zostanie przyj\u0119ty do tego wydania i pozostanie pod jego zarz\u0105dem. Co wi\u0119cej, podczas przyjmowania zasobu do wydania werf przekszta\u0142ci obecny stan zasobu z dzia\u0142aj\u0105cego klastra do stanu opisanego w wykresie, u\u017cywaj\u0105c tych samych \u0142atek 3-way-merge i zasady synchronizowanego zasobu.<\/p>\n<p><i><b>Uwaga<\/b>: konfiguracja <code>WERF_THREE_WAY_MERGE_MODE<\/code> nie wp\u0142ywa na adopcj\u0119 zasob\u00f3w \u2014 w przypadku adopcji zawsze u\u017cywana jest \u0142atka 3-way-merge.<\/i><\/p>\n<p>Szczeg\u00f3\u0142y \u2014 w <noindex><a rel=\"nofollow\" href=\"https:\/\/werf.io\/documentation\/reference\/deploy_process\/resources_update_methods_and_adoption.html#resources-adoption\">dokumentacji<\/a><\/noindex>.<\/p>\n<h2>Wnioski i dalsze plany<\/h2>\n<p>\nMam nadziej\u0119, \u017ce po tym artykule sta\u0142o si\u0119 jasne, czym s\u0105 \u0142atki 3-way-merge i dlaczego do nich doszli\u015bmy. Z praktycznego punktu widzenia rozwoju projektu werf ich wdro\u017cenie sta\u0142o si\u0119 jeszcze jednym krokiem w kierunku ulepszania wdro\u017ce\u0144 podobnych do Helm. Teraz mo\u017cna zapomnie\u0107 o problemach z synchronizacj\u0105 konfiguracji, kt\u00f3re cz\u0119sto wyst\u0119powa\u0142y przy u\u017cywaniu Helm 2. Jednocze\u015bnie dodano now\u0105 u\u017cyteczn\u0105 funkcj\u0119 adopcji ju\u017c pobranych zasob\u00f3w Kubernetes w wydaniu Helm.<\/p>\n<p>W wdro\u017ceniach podobnych do Helm wci\u0105\u017c pozostaj\u0105 pewne problemy i trudno\u015bci, takie jak u\u017cycie szablon\u00f3w Go, i b\u0119dziemy je dalej rozwi\u0105zywa\u0107.<\/p>\n<p>Informacje o metodach aktualizacji zasob\u00f3w i adopcji mo\u017cna r\u00f3wnie\u017c znale\u017a\u0107 na <noindex><a rel=\"nofollow\" href=\"https:\/\/werf.io\/documentation\/reference\/deploy_process\/resources_update_methods_and_adoption.html\">tej stronie dokumentacji<\/a><\/noindex>.<\/p>\n<h3>Helm 3<\/h3>\n<p>\nOsobnej uwagi wymaga <noindex><a rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/company\/flant\/news\/t\/475722\/\">niedawno wydana<\/a><\/noindex> dos\u0142ownie w ci\u0105gu ostatnich dni nowa g\u0142\u00f3wna wersja Helm \u2014 v3, \u2014 kt\u00f3ra r\u00f3wnie\u017c wykorzystuje \u0142atki 3-way-merge i eliminuje Tiller. Nowa wersja Helm wymaga <noindex><a rel=\"nofollow\" href=\"https:\/\/helm.sh\/docs\/topics\/v2_v3_migration\/\">migracji<\/a><\/noindex> ju\u017c istniej\u0105cych instalacji, aby przekonwertowa\u0107 je na nowy format przechowywania wyda\u0144.<\/p>\n<p>Werf ze swojej strony ju\u017c teraz pozby\u0142 si\u0119 u\u017cycia Tiller, przeszed\u0142 na 3-way-merge i doda\u0142 <noindex><a rel=\"nofollow\" href=\"https:\/\/werf.io\/documentation\/reference\/deploy_process\/differences_with_helm.html\">wiele innych<\/a><\/noindex>, pozostaj\u0105c przy tym kompatybilnym z ju\u017c istniej\u0105cymi instalacjami na Helm 2 (nie ma potrzeby wykonywania \u017cadnych skrypt\u00f3w migracyjnych). Dlatego, dop\u00f3ki werf nie zosta\u0142 prze\u0142\u0105czony na Helm 3, u\u017cytkownicy werf nie trac\u0105 podstawowych zalet Helm 3 przed Helm 2 (te\u017c s\u0105 obecne w werf).<\/p>\n<p>Niemniej jednak, prze\u0142\u0105czenie werf na baz\u0119 kodu Helm 3 jest nieuniknione i nast\u0105pi w najbli\u017cszej przysz\u0142o\u015bci. Przypuszczalnie b\u0119dzie to werf 1.1 lub werf 1.2 (aktualnie g\u0142\u00f3wna wersja werf to 1.0; wi\u0119cej o systemie wersjonowania werf mo\u017cna znale\u017a\u0107 <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/flant\/werf#backward-compatibility-promise\">tutaj<\/a><\/noindex>). W tym czasie Helm 3 zd\u0105\u017cy si\u0119 ustabilizowa\u0107.<\/p>\n<h2>P.S.<\/h2>\n<p>\nPrzeczytaj tak\u017ce na naszym blogu:<\/p>\n<ul>\n<li> Cykl notatek o nowo\u015bciach w werf:\n<ul>\n<li> \u00ab<noindex><a rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/company\/flant\/blog\/468049\/\">U\u017cycie werf do wdra\u017cania z\u0142o\u017conych chart\u00f3w Helm<\/a><\/noindex>\u00bb;<\/li>\n<li> \u00ab<noindex><a rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/company\/flant\/blog\/465131\/\">Wsparcie dla monorepo i multirepo w werf i jakie ma to znaczenie dla Docker Registry<\/a><\/noindex>\u00bb;<\/li>\n<li> \u00ab<noindex><a rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/company\/flant\/blog\/463613\/\">Budowanie obraz\u00f3w Docker w werf jest teraz mo\u017cliwe r\u00f3wnie\u017c za pomoc\u0105 zwyk\u0142ego Dockerfile<\/a><\/noindex>\u00bb.<\/li>\n<\/ul>\n<\/li>\n<li> \u00ab<noindex><a rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/company\/flant\/blog\/460351\/\">werf \u2014 nasze narz\u0119dzie do CI\/CD w Kubernetes (przegl\u0105d i wideo wyk\u0142adu)<\/a><\/noindex>\u00bb;<\/li>\n<li> \u00ab<noindex><a rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/company\/flant\/blog\/469541\/\">Budowa i wdro\u017cenie jednorodnych mikrous\u0142ug z werf i GitLab CI<\/a><\/noindex>\u00bb;<\/li>\n<li> \u00ab<noindex><a rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/company\/flant\/blog\/453734\/\">Wprowadzenie do Helm 3<\/a><\/noindex>\u00bb.<\/li>\n<\/ul>\n<p>\u0179r\u00f3d\u0142o: <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\/pl\/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=\"pl_PL\" \/>\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\/pl\/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\udd47Merge 3-dro\u017cny w werf: wdro\u017cenie w Kubernetes z Helm \u201ena sterydach\u201d | ProHoster","description":"Wydarzy\u0142o si\u0119 to, na co d\u0142ugo czekali\u015bmy (i nie tylko my): werf, nasze narz\u0119dzie Open Source do budowy aplikacji i ich dostarczania w Kubernetes, teraz ma wsparcie.","canonical_url":"https:\/\/prohoster.info\/pl\/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":"pl_PL","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\/pl\/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\/pl\/wp-json\/wp\/v2\/posts\/53120","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/prohoster.info\/pl\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/prohoster.info\/pl\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/prohoster.info\/pl\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/prohoster.info\/pl\/wp-json\/wp\/v2\/comments?post=53120"}],"version-history":[{"count":0,"href":"https:\/\/prohoster.info\/pl\/wp-json\/wp\/v2\/posts\/53120\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/prohoster.info\/pl\/wp-json\/wp\/v2\/media\/53121"}],"wp:attachment":[{"href":"https:\/\/prohoster.info\/pl\/wp-json\/wp\/v2\/media?parent=53120"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/prohoster.info\/pl\/wp-json\/wp\/v2\/categories?post=53120"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/prohoster.info\/pl\/wp-json\/wp\/v2\/tags?post=53120"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}