{"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\/pt\/blog\/administrirovanie\/3-way-merge-v-werf-deploj-v-kubernetes-s-helm-na-steroidah","title":{"rendered":"Mesclagem de 3 vias em werf: implanta\u00e7\u00e3o no Kubernetes com Helm \"turbinado\"","gt_translate_keys":[{"key":"rendered","format":"text"}]},"content":{"rendered":"<p>Aconteceu o que est\u00e1vamos (e n\u00e3o s\u00f3 n\u00f3s) esperando h\u00e1 muito tempo: <noindex><a rel=\"nofollow\" href=\"https:\/\/werf.io\/\">werf<\/a><\/noindex>, nossa ferramenta Open Source para constru\u00e7\u00e3o de aplica\u00e7\u00f5es e sua entrega em Kubernetes, agora suporta a aplica\u00e7\u00e3o de mudan\u00e7as atrav\u00e9s de patches de 3 vias! Al\u00e9m disso, surgiu a possibilidade de ado\u00e7\u00e3o de recursos existentes do K8s em releases do Helm sem re-cria\u00e7\u00e3o desses recursos.<\/p>\n<p><img decoding=\"async\" alt=\"Mesclagem de 3 vias em werf: implanta\u00e7\u00e3o no Kubernetes com Helm &quot;turbinado&quot;\" src=\"\/wp-content\/uploads\/2019\/11\/e5be3544c201f7b2c97fba216a49506d.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nEm termos simples, basta definir <code>WERF_THREE_WAY_MERGE=enabled<\/code> \u2014 e obtemos um deploy 'como em <code>kubectl apply<\/code>', compat\u00edvel com instala\u00e7\u00f5es existentes no Helm 2 e at\u00e9 um pouco mais.<\/p>\n<p>Mas vamos come\u00e7ar pela teoria: o que s\u00e3o patches de 3 vias, como as pessoas chegaram ao conceito de sua gera\u00e7\u00e3o e por que eles s\u00e3o importantes nos processos de CI\/CD com infraestrutura baseada em Kubernetes? Em seguida, veremos o que realmente \u00e9 3-way-merge no werf, quais modos s\u00e3o usados por padr\u00e3o e como gerenci\u00e1-los.<noindex><a rel=\"nofollow\" name=\"habracut\"><\/a><\/noindex><\/p>\n<h2>O que \u00e9 um patch de 3 vias?<\/h2>\n<p>\nEnt\u00e3o, vamos come\u00e7ar com a tarefa de implantar recursos descritos em manifests YAML no Kubernetes.<\/p>\n<p>Para trabalhar com recursos, a API do Kubernetes oferece as seguintes opera\u00e7\u00f5es principais: create, patch, replace e delete. Sup\u00f5e-se que com elas seja poss\u00edvel construir um roll-out cont\u00ednuo de recursos no cluster. Como?<\/p>\n<h3>Comandos imperativos do kubectl<\/h3>\n<p>\nA primeira abordagem para gerenciar objetos no Kubernetes \u00e9 usar comandos imperativos do kubectl para criar, modificar e deletar esses objetos. Em termos simples:<\/p>\n<ul>\n<li> com o comando <code>kubectl run<\/code> pode iniciar um Deployment ou Job:\n<pre><code class=\"bash\">kubectl run --generator=deployment\/apps.v1 NOME_DO_DEPLOYMENT --image=IMAGEM<\/code><\/pre>\n<\/li>\n<li> com o comando <code>kubectl scale<\/code> \u2014 altera o n\u00famero de r\u00e9plicas:\n<pre><code class=\"bash\">kubectl scale --replicas=3 deployment\/mysql<\/code><\/pre>\n<\/li>\n<li>etc.<\/li>\n<\/ul>\n<p>\nEssa abordagem pode parecer conveniente \u00e0 primeira vista. No entanto, existem problemas: <\/p>\n<ol>\n<li> \u00c9 dif\u00edcil <b>automatizar<\/b>.<\/li>\n<li> Como <b>refletir a configura\u00e7\u00e3o<\/b> no Git? Como fazer uma revis\u00e3o das mudan\u00e7as que ocorrem no cluster?<\/li>\n<li> Como garantir <b>a reprodutibilidade<\/b> da configura\u00e7\u00e3o ao reiniciar?<\/li>\n<li>\u2026<\/li>\n<\/ol>\n<p>\n\u00c9 claro que essa abordagem combina mal com o armazenamento junto ao c\u00f3digo do aplicativo e a infraestrutura como c\u00f3digo (IaC; ou at\u00e9 mesmo <noindex><a rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/company\/flant\/blog\/458878\/\">GitOps<\/a><\/noindex> como uma variante mais moderna que est\u00e1 ganhando popularidade no ecossistema Kubernetes). Portanto, essas equipes n\u00e3o tiveram mais desenvolvimento no kubectl.<\/p>\n<h3>Opera\u00e7\u00f5es create, get, replace e delete<\/h3>\n<p>\nCom a cria\u00e7\u00e3o prim\u00e1ria <b>\u00e9 simples: enviamos o manifest para a opera\u00e7\u00e3o<\/b> do kube API e o recurso \u00e9 criado. A representa\u00e7\u00e3o YAML do manifest pode ser armazenada no Git, e para criar - utilizamos o comando <code>create<\/code> kubectl create -f manifest.yaml <code>a remo\u00e7\u00e3o<\/code>.<\/p>\n<p>Com <b>tamb\u00e9m \u00e9 simples: inserimos o mesmo<\/b> manifest.yaml <code>do Git no comando<\/code> kubectl delete -f manifest.yaml <code>replace<\/code>.<\/p>\n<p>Opera\u00e7\u00e3o <b><code>replace<\/code><\/b> permite substituir completamente a configura\u00e7\u00e3o do recurso por uma nova, sem a necessidade de recriar o recurso. Isso significa que, antes de fazer uma altera\u00e7\u00e3o no recurso, \u00e9 l\u00f3gico solicitar a vers\u00e3o atual por meio da opera\u00e7\u00e3o <code>get<\/code>, alter\u00e1-la e atualiz\u00e1-la com a opera\u00e7\u00e3o <code>replace<\/code>. O kube apiserver possui <noindex><a rel=\"nofollow\" href=\"https:\/\/en.wikipedia.org\/wiki\/Optimistic_concurrency_control\">bloqueio otimista<\/a><\/noindex> , e, se ap\u00f3s a opera\u00e7\u00e3o <code>get<\/code> o objeto tiver mudado, a opera\u00e7\u00e3o <code>replace<\/code> n\u00e3o ser\u00e1 bem-sucedida.<\/p>\n<p>Para armazenar a configura\u00e7\u00e3o no Git e atualizar usando replace, \u00e9 necess\u00e1rio realizar a opera\u00e7\u00e3o <code>get<\/code>, mesclar a configura\u00e7\u00e3o do Git com o que recebemos e executar <code>replace<\/code>. Normalmente, o kubectl permite apenas usar o comando <code>kubectl replace -f manifest.yaml<\/code>, onde <code>do Git no comando<\/code> \u2014 um manifesto j\u00e1 completamente preparado (neste caso, mesclado) que deve ser instalado. Portanto, o usu\u00e1rio precisa implementar a mesclagem de manifestos, o que n\u00e3o \u00e9 uma tarefa trivial\u2026<\/p>\n<p>Vale ressaltar que, embora <code>do Git no comando<\/code> seja armazenado no Git, n\u00e3o podemos saber de antem\u00e3o se devemos criar um objeto ou atualiz\u00e1-lo \u2014 isso deve ser feito pelo software do usu\u00e1rio.<\/p>\n<p>No total: <b>podemos construir uma implanta\u00e7\u00e3o cont\u00ednua<\/b> apenas com create, replace e delete, garantindo o armazenamento da configura\u00e7\u00e3o da infraestrutura no Git junto com o c\u00f3digo e um CI\/CD conveniente?<\/p>\n<p>Em princ\u00edpio, podemos\u2026 Para isso <b>ser\u00e1 necess\u00e1rio implementar a opera\u00e7\u00e3o de mesclagem<\/b> de manifestos e algum tipo de envolt\u00f3rio que:<\/p>\n<ul>\n<li> verifica a presen\u00e7a do objeto no cluster,<\/li>\n<li> realiza a cria\u00e7\u00e3o inicial do recurso,<\/li>\n<li> atualiza ou o remove.<\/li>\n<\/ul>\n<p>\nAo atualizar, \u00e9 necess\u00e1rio levar em conta que <i>o recurso pode ter mudado<\/i> desde a \u00faltima <code>get<\/code> e deve tratar automaticamente o caso de bloqueio otimista \u2014 fazendo novas tentativas de atualiza\u00e7\u00e3o.<\/p>\n<p>No entanto, por que reinventar a roda, quando o kube-apiserver oferece uma maneira alternativa de atualizar recursos: a opera\u00e7\u00e3o <code>patch<\/code>, que remove parte dos problemas descritos do usu\u00e1rio?<\/p>\n<h3>Patch<\/h3>\n<p>\nChegamos aos patches.<\/p>\n<p>Patches s\u00e3o a principal forma de aplicar altera\u00e7\u00f5es a objetos existentes no Kubernetes. A opera\u00e7\u00e3o <code>patch<\/code> funciona da seguinte forma:<\/p>\n<ul>\n<li> o usu\u00e1rio do kube-apiserver precisa enviar um patch em formato JSON e especificar o objeto,<\/li>\n<li> e o apiserver ir\u00e1 entender o estado atual do objeto e traz\u00ea-lo para a forma desejada.<\/li>\n<\/ul>\n<p>\nO bloqueio otimista n\u00e3o \u00e9 necess\u00e1rio neste caso. Esta opera\u00e7\u00e3o \u00e9 mais declarativa em compara\u00e7\u00e3o ao replace, embora possa parecer o contr\u00e1rio \u00e0 primeira vista.<\/p>\n<p>Assim:<\/p>\n<ul>\n<li> com a opera\u00e7\u00e3o <code>create<\/code> n\u00f3s criamos um objeto a partir do manifesto do Git,<\/li>\n<li> com <code>delete<\/code> \u2014 removemos se o objeto n\u00e3o for mais necess\u00e1rio,<\/li>\n<li> com <code>patch<\/code> \u2014 alteramos o objeto, moldando-o da maneira descrita no Git.<\/li>\n<\/ul>\n<p>\nNo entanto, para fazer isso, \u00e9 necess\u00e1rio criar <i>um patch correto<\/i>!<\/p>\n<h3>Como os patches funcionam no Helm 2: 2-way-merge<\/h3>\n<p>\nNa primeira instala\u00e7\u00e3o do release, o Helm executa uma opera\u00e7\u00e3o <code>create<\/code> para os recursos do chart.<\/p>\n<p>Ao atualizar o release do Helm para cada recurso:<\/p>\n<ul>\n<li> ele calcula o patch entre a vers\u00e3o do recurso do chart anterior e a vers\u00e3o atual do chart,<\/li>\n<li> aplica esse patch.<\/li>\n<\/ul>\n<p>\nEsse patch chamamos de <b>2-way-merge patch<\/b>, porque na sua cria\u00e7\u00e3o participam 2 manifestos:<\/p>\n<ul>\n<li> o manifesto do recurso da vers\u00e3o anterior do release,<\/li>\n<li> o manifesto do recurso da vers\u00e3o atual.<\/li>\n<\/ul>\n<p>\nAo excluir, a opera\u00e7\u00e3o <code>delete<\/code> \u00e9 invocada no kube apiserver para recursos que foram declarados no release anterior, mas n\u00e3o declarados no atual.<\/p>\n<p>A abordagem com 2 way merge patch tem um problema: ela leva a <b>desincroniza\u00e7\u00f5es entre o estado real do recurso no cluster e o manifesto no Git<\/b>.<\/p>\n<h3>Ilustra\u00e7\u00e3o do problema com um exemplo<\/h3>\n<p><\/p>\n<ul>\n<li> No Git, no chart, h\u00e1 um manifesto onde o campo <code>image<\/code> no Deployment tem o valor <code>ubuntu:18.04<\/code>.<\/li>\n<li> O usu\u00e1rio por meio de <code>kubectl edit<\/code> mudou o valor desse campo para <code>ubuntu:19.04<\/code>.<\/li>\n<li> Ao reaplicar o chart do Helm <i>n\u00e3o \u00e9 gerado um patch,<\/i>porque o campo <code>image<\/code> na vers\u00e3o anterior do release e no chart atual s\u00e3o iguais.<\/li>\n<li> Ap\u00f3s a reaplica\u00e7\u00e3o <code>image<\/code> permanece <code>ubuntu:19.04<\/code>, embora no chart esteja escrito <code>ubuntu:18.04<\/code>.<\/li>\n<\/ul>\n<p>\nA desincroniza\u00e7\u00e3o ocorreu e perdemos a declaratividade.<\/p>\n<h3>O que \u00e9 um recurso sincronizado?<\/h3>\n<p>\nDe modo geral, <i>n\u00e3o \u00e9 poss\u00edvel obter a<\/i> correspond\u00eancia total entre o manifesto do recurso no cluster em funcionamento e o manifesto no Git. Porque no manifesto real podem haver anota\u00e7\u00f5es\/etiquetas de servi\u00e7o, cont\u00eaineres adicionais e outros dados, que s\u00e3o adicionados e removidos do recurso dinamicamente por controladores. Esses dados n\u00e3o podemos e n\u00e3o queremos manter no Git. No entanto, queremos que, ao aplicar, os campos que indicamos claramente no Git assumam os valores correspondentes.<\/p>\n<p>Assim, surge uma <b>regra geral para um recurso sincronizado<\/b>: ao aplicar um recurso, s\u00f3 se pode alterar ou remover aqueles campos que est\u00e3o claramente especificados no manifesto do Git (ou que foram especificados na vers\u00e3o anterior e agora foram removidos).<\/p>\n<h3>3-way-merge patch<\/h3>\n<p>\nA ideia principal <noindex><a rel=\"nofollow\" href=\"https:\/\/en.wikipedia.org\/wiki\/Merge_(version_control)#Three-way_merge\">3-way-merge patch<\/a><\/noindex>: gera-se um patch entre a \u00faltima vers\u00e3o aplicada do manifesto do Git e a vers\u00e3o-alvo do manifesto do Git, levando em conta a vers\u00e3o atual do manifesto do cluster em funcionamento. O patch final deve estar em conformidade com a regra do recurso sincronizado:<\/p>\n<ul>\n<li> Novos campos adicionados na vers\u00e3o de destino s\u00e3o inclu\u00eddos por meio de um patch;<\/li>\n<li> Os campos existentes na \u00faltima vers\u00e3o aplicada e que n\u00e3o est\u00e3o presentes na vers\u00e3o de destino s\u00e3o zerados por meio do patch;<\/li>\n<li> Os campos na vers\u00e3o atual do objeto que diferem da vers\u00e3o de destino do manifesto s\u00e3o atualizados por meio de um patch.<\/li>\n<\/ul>\n<p>\n\u00c9 exatamente assim que os patches s\u00e3o gerados <code>kubectl apply<\/code>:<\/p>\n<ul>\n<li> A \u00faltima vers\u00e3o aplicada do manifesto \u00e9 salva na anota\u00e7\u00e3o do pr\u00f3prio objeto, <\/li>\n<li> o alvo \u00e9 retirado do arquivo YAML especificado,<\/li>\n<li> o atual vem do cluster em funcionamento.<\/li>\n<\/ul>\n<p>\nAgora que entendemos a teoria, \u00e9 hora de contar o que fizemos no werf.<\/p>\n<h2>Aplica\u00e7\u00e3o de altera\u00e7\u00f5es no werf<\/h2>\n<p>\nAnteriormente, o werf, assim como o Helm 2, usava patches de mesclagem de 2 vias.<\/p>\n<h3>Repair patch<\/h3>\n<p>\nPara migrar para o novo tipo de patches \u2014 3-way-merge \u2014 o primeiro passo foi a introdu\u00e7\u00e3o dos chamados <b>repair-patches<\/b>.<\/p>\n<p>Durante o deployment, \u00e9 utilizado um patch padr\u00e3o de mesclagem de 2 vias, mas o werf tamb\u00e9m gera um patch adicional que sincroniza o estado real do recurso com o que est\u00e1 escrito no Git (um patch \u00e9 criado utilizando a mesma regra de recurso sincronizado descrita anteriormente).<\/p>\n<p>Em caso de desvio, no final do deployment o usu\u00e1rio recebe um WARNING com a mensagem correspondente e um patch que deve ser aplicado para trazer o recurso ao estado sincronizado. Esse patch tamb\u00e9m \u00e9 registrado em uma anota\u00e7\u00e3o especial <code>werf.io\/repair-patch<\/code>. Espera-se que o usu\u00e1rio <b>aplique-o manualmente;<\/b> o werf n\u00e3o aplicar\u00e1 esse patch de forma alguma.<\/p>\n<p>A gera\u00e7\u00e3o de repair-patches \u00e9 uma medida tempor\u00e1ria que permite testar a cria\u00e7\u00e3o de patches com base no princ\u00edpio de 3-way-merge, mas esses patches n\u00e3o s\u00e3o aplicados automaticamente. No momento, esse modo de opera\u00e7\u00e3o est\u00e1 habilitado por padr\u00e3o.<\/p>\n<h3>3-way-merge patch apenas para novos lan\u00e7amentos<\/h3>\n<p>\nA partir de 1\u00ba de dezembro de 2019, vers\u00f5es beta e alpha do werf come\u00e7am <b>padr\u00e3o<\/b> a usar patches completos de 3-way-merge para aplicar altera\u00e7\u00f5es apenas para novos lan\u00e7amentos do Helm, implementados por meio do werf. Lan\u00e7amentos j\u00e1 existentes continuar\u00e3o a utilizar a abordagem de 2-way-merge + repair-patches.<\/p>\n<p>Esse modo de opera\u00e7\u00e3o pode ser explicitamente habilitado configurando <code>WERF_THREE_WAY_MERGE_MODE=onlyNewReleases<\/code> j\u00e1 agora.<\/p>\n<p><i><b>Nota<\/b>: a funcionalidade apareceu no werf ao longo de v\u00e1rios lan\u00e7amentos: no canal alpha, ela se tornou est\u00e1vel na vers\u00e3o <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/flant\/werf\/releases\/tag\/v1.0.5-alpha.19\">v1.0.5-alpha.19<\/a><\/noindex>, e no canal beta \u2014 a partir de <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/flant\/werf\/releases\/tag\/v1.0.4-beta.20\">v1.0.4-beta.20<\/a><\/noindex>.<\/i><\/p>\n<h3>3-way-merge patch para todos os lan\u00e7amentos<\/h3>\n<p>\nA partir de 15 de dezembro de 2019, as vers\u00f5es beta e alpha do werf come\u00e7ar\u00e3o a usar, por padr\u00e3o, patches de mesclagem 3-way completos para aplicar altera\u00e7\u00f5es em todos os lan\u00e7amentos.<\/p>\n<p>Esse modo de opera\u00e7\u00e3o pode ser explicitamente habilitado configurando <code>WERF_THREE_WAY_MERGE_MODE=enabled<\/code> j\u00e1 agora.<\/p>\n<h3>Como lidar com o dimensionamento autom\u00e1tico de recursos?<\/h3>\n<p>\nNo Kubernetes, existem 2 tipos de dimensionamento autom\u00e1tico: HPA (horizontal) e VPA (vertical).<\/p>\n<p>O horizontal seleciona automaticamente o n\u00famero de r\u00e9plicas, enquanto o vertical determina a quantidade de recursos. Tanto o n\u00famero de r\u00e9plicas quanto os requisitos de recursos s\u00e3o especificados no manifesto do recurso (consulte <code>spec.replicas<\/code> ou <code>spec.containers[].resources.limits.cpu<\/code>, <code>spec.containers[].resources.limits.memory<\/code> e <noindex><a rel=\"nofollow\" href=\"https:\/\/kubernetes.io\/docs\/concepts\/configuration\/manage-compute-resources-container\/#resource-requests-and-limits-of-pod-and-container\">outros<\/a><\/noindex>).<\/p>\n<p>Problema: se o usu\u00e1rio configurar um recurso no chart de forma que valores espec\u00edficos de recursos ou r\u00e9plicas sejam indicados e se escaladores autom\u00e1ticos forem ativados para esse recurso, a cada implanta\u00e7\u00e3o o werf ir\u00e1 redefinir esses valores para o que est\u00e1 registrado no manifesto do chart.<\/p>\n<p>H\u00e1 duas solu\u00e7\u00f5es para o problema. Primeiro, \u00e9 melhor evitar especificar explicitamente valores escal\u00e1veis no manifesto do chart. No entanto, se essa op\u00e7\u00e3o n\u00e3o for vi\u00e1vel por algum motivo (por exemplo, porque \u00e9 conveniente definir limites iniciais de recursos e o n\u00famero de r\u00e9plicas no chart), o werf oferece as seguintes anota\u00e7\u00f5es:<\/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>\nCom essa anota\u00e7\u00e3o, o werf n\u00e3o redefinir\u00e1 os valores correspondentes em cada implanta\u00e7\u00e3o, mas apenas os definir\u00e1 na cria\u00e7\u00e3o inicial do recurso.<\/p>\n<p>Para mais informa\u00e7\u00f5es, consulte a documenta\u00e7\u00e3o do projeto sobre <noindex><a rel=\"nofollow\" href=\"https:\/\/werf.io\/documentation\/reference\/deploy_process\/resources_update_methods_and_adoption.html#deal-with-hpa\">HPA<\/a><\/noindex> e <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>Proibir o uso de patch 3-way-merge<\/h3>\n<p>\nPor enquanto, o usu\u00e1rio pode proibir o uso de novos patches no werf atrav\u00e9s da vari\u00e1vel de ambiente <code>WERF_THREE_WAY_MERGE_MODE=disabled<\/code>. No entanto, a partir de <b>1 de mar\u00e7o de 2020, essa proibi\u00e7\u00e3o deixar\u00e1 de funcionar<\/b> e apenas patches de mesclagem 3-way poder\u00e3o ser utilizados.<\/p>\n<h2>Ado\u00e7\u00e3o de recursos no werf<\/h2>\n<p>\nA implementa\u00e7\u00e3o do m\u00e9todo de aplica\u00e7\u00e3o de altera\u00e7\u00f5es utilizando patches de mesclagem 3-way nos permitiu imediatamente implementar um recurso como a ado\u00e7\u00e3o de recursos existentes no cluster em lan\u00e7amentos do Helm.<\/p>\n<p>O Helm 2 tem um problema: n\u00e3o \u00e9 poss\u00edvel adicionar um recurso que j\u00e1 existe no cluster aos manifestos do chart sem recriar esse recurso do zero (consulte <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>). N\u00f3s ensinamos o werf a aceitar recursos existentes no lan\u00e7amento. Para isso, \u00e9 necess\u00e1rio definir uma anota\u00e7\u00e3o na vers\u00e3o atual do recurso do cluster ativo (por exemplo, usando <code>kubectl edit<\/code>):<\/p>\n<pre><code class=\"plaintext\">\"werf.io\/allow-adoption-by-release\": RELEASE_NAME<\/code><\/pre>\n<p>\nAgora, o recurso precisa ser descrito no gr\u00e1fico e, na pr\u00f3xima implanta\u00e7\u00e3o do lan\u00e7amento com o nome correspondente, o recurso existente ser\u00e1 aceito nesse lan\u00e7amento e permanecer\u00e1 sob sua gest\u00e3o. Al\u00e9m disso, durante o processo de aceita\u00e7\u00e3o do recurso no lan\u00e7amento, o werf levar\u00e1 o estado atual do recurso do cluster ativo para o estado descrito no gr\u00e1fico, usando os mesmos patches de 3-way-merge e a regra de recurso sincronizado.<\/p>\n<p><i><b>Nota<\/b>: configura\u00e7\u00e3o <code>WERF_THREE_WAY_MERGE_MODE<\/code> n\u00e3o afeta a ado\u00e7\u00e3o de recursos \u2014 em caso de ado\u00e7\u00e3o, sempre \u00e9 utilizado um patch de 3-way-merge.<\/i><\/p>\n<p>Detalhes podem ser encontrados em <noindex><a rel=\"nofollow\" href=\"https:\/\/werf.io\/documentation\/reference\/deploy_process\/resources_update_methods_and_adoption.html#resources-adoption\">documenta\u00e7\u00e3o<\/a><\/noindex>.<\/p>\n<h2>Conclus\u00f5es e planos futuros<\/h2>\n<p>\nEspero que, ap\u00f3s este artigo, tenha ficado mais claro o que s\u00e3o patches de 3-way-merge e por que chegamos a isso. Do ponto de vista pr\u00e1tico do desenvolvimento do projeto werf, sua implementa\u00e7\u00e3o foi mais um passo na dire\u00e7\u00e3o da melhoria das implanta\u00e7\u00f5es semelhantes ao Helm. Agora podemos esquecer os problemas de sincroniza\u00e7\u00e3o de configura\u00e7\u00e3o que frequentemente surgiam ao usar o Helm 2. Ao mesmo tempo, uma nova e \u00fatil funcionalidade de ado\u00e7\u00e3o de recursos Kubernetes j\u00e1 baixados para o lan\u00e7amento do Helm foi adicionada.<\/p>\n<p>Na implanta\u00e7\u00e3o semelhante ao Helm, ainda permanecem alguns problemas e dificuldades, como o uso de templates Go, e continuaremos a resolv\u00ea-los.<\/p>\n<p>Informa\u00e7\u00f5es sobre m\u00e9todos de atualiza\u00e7\u00e3o de recursos e ado\u00e7\u00e3o tamb\u00e9m podem ser encontradas em <noindex><a rel=\"nofollow\" href=\"https:\/\/werf.io\/documentation\/reference\/deploy_process\/resources_update_methods_and_adoption.html\">esta p\u00e1gina de documenta\u00e7\u00e3o<\/a><\/noindex>.<\/p>\n<h3>Helm 3<\/h3>\n<p>\nUm ponto separado que merece aten\u00e7\u00e3o \u00e9 <noindex><a rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/company\/flant\/news\/t\/475722\/\">o lan\u00e7amento<\/a><\/noindex> recentemente da nova vers\u00e3o maior do Helm \u2014 v3, que tamb\u00e9m utiliza patches de 3-way-merge e elimina o Tiller. A nova vers\u00e3o do Helm requer <noindex><a rel=\"nofollow\" href=\"https:\/\/helm.sh\/docs\/topics\/v2_v3_migration\/\">migra\u00e7\u00e3o<\/a><\/noindex> que as instala\u00e7\u00f5es j\u00e1 existentes sejam convertidas para o novo formato de armazenamento de lan\u00e7amentos.<\/p>\n<p>O werf, por sua vez, j\u00e1 se livrou do uso do Tiller, mudou para 3-way-merge e adicionou <noindex><a rel=\"nofollow\" href=\"https:\/\/werf.io\/documentation\/reference\/deploy_process\/differences_with_helm.html\">muito mais<\/a><\/noindex>, permanecendo compat\u00edvel com as instala\u00e7\u00f5es existentes do Helm 2 (nenhum script de migra\u00e7\u00e3o precisa ser executado). Portanto, enquanto o werf n\u00e3o migrar para o Helm 3, os usu\u00e1rios do werf n\u00e3o perdem as principais vantagens do Helm 3 sobre o Helm 2 (elas tamb\u00e9m est\u00e3o presentes no werf).<\/p>\n<p>No entanto, a migra\u00e7\u00e3o do werf para a base de c\u00f3digo do Helm 3 \u00e9 inevit\u00e1vel e acontecer\u00e1 em um futuro pr\u00f3ximo. Presumivelmente, ser\u00e1 no werf 1.1 ou 1.2 (no momento, a vers\u00e3o principal do werf \u00e9 1.0; mais detalhes sobre a estrutura de versionamento do werf podem ser vistos em <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/flant\/werf#backward-compatibility-promise\">aqui<\/a><\/noindex>). Nesse meio tempo, o Helm 3 deve se estabilizar.<\/p>\n<h2>P.S.<\/h2>\n<p>\nConfira tamb\u00e9m em nosso blog:<\/p>\n<ul>\n<li> Ciclo de notas sobre novidades no werf:\n<ul>\n<li> \u00ab<noindex><a rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/company\/flant\/blog\/468049\/\">Uso do werf para implanta\u00e7\u00f5es de charts Helm complexos<\/a><\/noindex>\u00bb;<\/li>\n<li> \u00ab<noindex><a rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/company\/flant\/blog\/465131\/\">Suporte a monorepo e multirepo no werf e qual a rela\u00e7\u00e3o com o Docker Registry.<\/a><\/noindex>\u00bb;<\/li>\n<li> \u00ab<noindex><a rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/company\/flant\/blog\/463613\/\">Agora \u00e9 poss\u00edvel construir imagens Docker no werf tamb\u00e9m usando um Dockerfile comum<\/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 nossa ferramenta para CI\/CD no Kubernetes (vis\u00e3o geral e v\u00eddeo da apresenta\u00e7\u00e3o)<\/a><\/noindex>\u00bb;<\/li>\n<li> \u00ab<noindex><a rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/company\/flant\/blog\/469541\/\">Constru\u00e7\u00e3o e implanta\u00e7\u00e3o de microsservi\u00e7os semelhantes com werf e GitLab CI<\/a><\/noindex>\u00bb;<\/li>\n<li> \u00ab<noindex><a rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/company\/flant\/blog\/453734\/\">Introdu\u00e7\u00e3o ao Helm 3<\/a><\/noindex>\u00bb.<\/li>\n<\/ul>\n<p>Fonte: <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.3 - 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\/pt\/blog\/administrirovanie\/3-way-merge-v-werf-deploj-v-kubernetes-s-helm-na-steroidah\" \/>\n\t\t<meta name=\"generator\" content=\"All in One SEO (AIOSEO) 5.0.3\" \/>\n\t\t<meta property=\"og:locale\" content=\"pt_PT\" \/>\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\/pt\/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-way no werf: implanta\u00e7\u00e3o no Kubernetes com Helm \"turbinado\" | ProHoster","description":"Aconteceu o que n\u00f3s (e n\u00e3o s\u00f3 n\u00f3s) est\u00e1vamos aguardando h\u00e1 muito tempo: werf, nossa ferramenta Open Source para constru\u00e7\u00e3o de aplica\u00e7\u00f5es e sua entrega no Kubernetes, agora suporta.","canonical_url":"https:\/\/prohoster.info\/pt\/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":"pt_PT","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\/pt\/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\/pt\/wp-json\/wp\/v2\/posts\/53120","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/prohoster.info\/pt\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/prohoster.info\/pt\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/prohoster.info\/pt\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/prohoster.info\/pt\/wp-json\/wp\/v2\/comments?post=53120"}],"version-history":[{"count":0,"href":"https:\/\/prohoster.info\/pt\/wp-json\/wp\/v2\/posts\/53120\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/prohoster.info\/pt\/wp-json\/wp\/v2\/media\/53121"}],"wp:attachment":[{"href":"https:\/\/prohoster.info\/pt\/wp-json\/wp\/v2\/media?parent=53120"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/prohoster.info\/pt\/wp-json\/wp\/v2\/categories?post=53120"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/prohoster.info\/pt\/wp-json\/wp\/v2\/tags?post=53120"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}