Mesclagem de três vias para werf: implantação no Kubernetes com Helm “com esteróides”

O que nós (e não só nós) esperávamos há muito tempo aconteceu: bem, nosso utilitário de código aberto para criar aplicativos e entregá-los ao Kubernetes, agora oferece suporte à aplicação de alterações usando patches de mesclagem de três vias! Além disso, é possível adotar recursos K3s existentes em versões do Helm sem reconstruir esses recursos.

Mesclagem de três vias para werf: implantação no Kubernetes com Helm “com esteróides”

Se for muito curto, então colocamos WERF_THREE_WAY_MERGE=enabled - obtemos implantação “como em kubectl apply", compatível com instalações existentes do Helm 2 e até um pouco mais.

Mas vamos começar com a teoria: o que exatamente são patches de mesclagem de três vias, como as pessoas criaram a abordagem para gerá-los e por que eles são importantes nos processos de CI/CD com infraestrutura baseada em Kubernetes? E depois disso, vamos ver o que é mesclagem de 3 vias no werf, quais modos são usados ​​​​por padrão e como gerenciá-lo.

O que é um patch de mesclagem de três vias?

Então, vamos começar com a tarefa de implementar os recursos descritos nos manifestos YAML no Kubernetes.

Para trabalhar com recursos, a API Kubernetes oferece as seguintes operações básicas: criar, corrigir, substituir e excluir. Supõe-se que com a ajuda deles seja necessário construir uma implementação contínua e conveniente de recursos para o cluster. Como?

Comandos imperativos do kubectl

A primeira abordagem para gerenciar objetos no Kubernetes é usar comandos imperativos kubectl para criar, modificar e excluir esses objetos. Simplificando:

  • a equipe kubectl run você pode executar a implantação ou o trabalho:
    kubectl run --generator=deployment/apps.v1 DEPLOYMENT_NAME --image=IMAGE
  • a equipe kubectl scale — altere o número de réplicas:
    kubectl scale --replicas=3 deployment/mysql
  • и т.д.

Esta abordagem pode parecer conveniente à primeira vista. No entanto, existem problemas:

  1. É difícil automatizar.
  2. Как refletir configuração no Git? Como revisar as mudanças que acontecem no cluster?
  3. Como fornecer reprodutibilidade configurações na reinicialização?
  4. ...

É claro que esta abordagem não se adapta bem ao armazenamento de aplicações e infra-estruturas como código (IaC; ou mesmo GitOps como uma opção mais moderna, ganhando popularidade no ecossistema Kubernetes). Portanto, esses comandos não receberam desenvolvimento adicional no kubectl.

Criar, obter, substituir e excluir operações

Com primário a criação de é simples: envie o manifesto para a operação create kube api e o recurso foi criado. A representação YAML do manifesto pode ser armazenada no Git e criada usando o comando kubectl create -f manifest.yaml.

С removendo também simples: substitua o mesmo manifest.yaml do Git para a equipe kubectl delete -f manifest.yaml.

Operação replace permite substituir completamente a configuração do recurso por uma nova, sem recriar o recurso. Isto significa que antes de fazer uma alteração em um recurso, é lógico consultar a versão atual com a operação get, altere-o e atualize-o com a operação replace. kube apiserver está integrado bloqueio otimista e, se após a cirurgia get o objeto mudou, então a operação replace não vai passar.

Para armazenar a configuração no Git e atualizá-la usando replace, você precisa fazer a operação get, mescle a configuração do Git com o que recebemos e execute replace. Por padrão, o kubectl só permite usar o comando kubectl replace -f manifest.yamlOnde manifest.yaml — um manifesto já totalmente preparado (no nosso caso, mesclado) que precisa ser instalado. Acontece que o usuário precisa implementar manifestos de mesclagem, e isso não é uma questão trivial...

Também vale a pena notar que embora manifest.yaml e está armazenado no Git, não podemos saber antecipadamente se é necessário criar um objeto ou atualizá-lo - isso deve ser feito pelo software do usuário.

Total: podemos construir uma implementação contínua usando apenas criar, substituir e excluir, garantindo que a configuração da infraestrutura seja armazenada no Git junto com o código e CI/CD conveniente?

Em princípio, podemos... Para isso você precisará implementar a operação de mesclagem manifestos e algum tipo de ligação que:

  • verifica a presença de um objeto no cluster,
  • executa a criação inicial de recursos,
  • atualiza ou exclui.

Ao atualizar, observe que recurso pode ter mudado desde a última get e lidar automaticamente com o caso de bloqueio otimista - faça repetidas tentativas de atualização.

No entanto, por que reinventar a roda quando o kube-apiserver oferece outra maneira de atualizar recursos: a operação patch, o que alivia o usuário de alguns dos problemas descritos?

Remendo

Agora chegamos aos patches.

Patches são a principal forma de aplicar alterações a objetos existentes no Kubernetes. Operação patch funciona assim:

  • o usuário kube-apiserver precisa enviar um patch no formato JSON e especificar o objeto,
  • e o próprio apiserver tratará do estado atual do objeto e o trará para a forma exigida.

O bloqueio otimista não é necessário neste caso. Esta operação é mais declarativa do que substituir, embora à primeira vista possa parecer o contrário.

Assim:

  • usando uma operação create criamos um objeto de acordo com o manifesto do Git,
  • via delete — excluir se o objeto não for mais necessário,
  • via patch — alteramos o objeto, trazendo-o para a forma descrita no Git.

No entanto, para fazer isso, você precisa criar correção correta!

Como os patches funcionam no Helm 2: mesclagem bidirecional

Quando você instala uma versão pela primeira vez, o Helm executa a operação create para recursos de gráfico.

Ao atualizar uma versão do Helm para cada recurso:

  • considera o patch entre a versão do recurso do gráfico anterior e a versão atual do gráfico,
  • aplica este patch.

Chamaremos esse patch Patch de mesclagem bidirecional, porque 2 manifestos estão envolvidos na sua criação:

  • manifesto de recursos da versão anterior,
  • manifesto do recurso do recurso atual.

Ao remover a operação delete no kube apiserver é chamado para recursos que foram declarados na versão anterior, mas não declarados na versão atual.

A abordagem de patch de mesclagem bidirecional tem um problema: ela leva a fora de sincronia com o estado real do recurso no cluster e o manifesto no Git.

Ilustração do problema com um exemplo

  • No Git, um gráfico armazena um manifesto no qual o campo image A implantação é importante ubuntu:18.04.
  • Usuário via kubectl edit alterou o valor deste campo para ubuntu:19.04.
  • Ao reimplantar o gráfico Helm não gera um patch, porque o campo image na versão anterior do lançamento e no gráfico atual são iguais.
  • Após a reimplantação image restos ubuntu:19.04, embora o gráfico diga ubuntu:18.04.

Obtivemos dessincronização e perdemos a declaratividade.

O que é um recurso sincronizado?

De um modo geral cheio É impossível obter uma correspondência entre o manifesto do recurso em um cluster em execução e o manifesto do Git. Porque em um manifesto real pode haver anotações/rótulos de serviço, contêineres adicionais e outros dados que são adicionados e removidos do recurso dinamicamente por alguns controladores. Não podemos e não queremos manter esses dados no Git. No entanto, queremos que os campos que especificamos explicitamente no Git assumam os valores apropriados após a implementação.

Acontece que é tão geral regra de recurso sincronizado: ao implementar um recurso, você pode alterar ou excluir apenas os campos especificados explicitamente no manifesto do Git (ou que foram especificados na versão anterior e agora foram excluídos).

Patch de mesclagem bidirecional

idéia central Patch de mesclagem bidirecional: geramos um patch entre a última versão aplicada do manifesto do Git e a versão alvo do manifesto do Git, levando em consideração a versão atual do manifesto do cluster em execução. O patch resultante deve estar em conformidade com a regra de recursos sincronizados:

  • novos campos adicionados à versão de destino são adicionados usando um patch;
  • campos anteriormente existentes na última versão aplicada e não existentes na versão de destino são redefinidos por meio de um patch;
  • os campos na versão atual do objeto que diferem da versão de destino do manifesto são atualizados usando o patch.

É neste princípio que ele gera patches kubectl apply:

  • a última versão aplicada do manifesto é armazenada na anotação do próprio objeto,
  • alvo - retirado do arquivo YAML especificado,
  • o atual é de um cluster em execução.

Agora que resolvemos a teoria, é hora de contar o que fizemos no werf.

Aplicando alterações ao werf

Anteriormente, o werf, como o Helm 2, usava patches de mesclagem bidirecional.

Patch de reparo

Para mudar para um novo tipo de patches - mesclagem de 3 vias - o primeiro passo foi introduzir o chamado reparar patches.

Ao implantar, um patch de mesclagem bidirecional padrão é usado, mas o werf também gera um patch que sincronizaria o estado real do recurso com o que está escrito no Git (esse patch é criado usando a mesma regra de recurso sincronizado descrita acima) .

Caso ocorra uma dessincronização, ao final da implantação o usuário recebe um AVISO com uma mensagem correspondente e um patch que deve ser aplicado para trazer o recurso para uma forma sincronizada. Este patch também é registrado em uma anotação especial werf.io/repair-patch. Supõe-se que as mãos do usuário se aplicará este patch: o werf não o aplicará de forma alguma.

A geração de patches de reparo é uma medida temporária que permite testar a criação de patches com base no princípio de mesclagem de três vias, mas não aplica automaticamente esses patches. No momento, este modo de operação está habilitado por padrão.

Patch de mesclagem de 3 vias apenas para novos lançamentos

A partir de 1º de dezembro de 2019, as versões beta e alfa do werf começarão por padrão use patches de mesclagem de três vias completos para aplicar alterações apenas a novas versões do Helm lançadas por meio do werf. As versões existentes continuarão a usar a abordagem de mesclagem bidirecional + patches de reparo.

Este modo de operação pode ser habilitado explicitamente configurando WERF_THREE_WAY_MERGE_MODE=onlyNewReleases agora

Nota: o recurso apareceu no werf ao longo de vários lançamentos: no canal alfa ficou pronto com a versão v1.0.5-alfa.19, e no canal beta - com v1.0.4-beta.20.

Patch de mesclagem de 3 vias para todas as versões

A partir de 15 de dezembro de 2019, as versões beta e alfa do werf começarão a usar patches completos de mesclagem de três vias por padrão para aplicar alterações a todas as versões.

Este modo de operação pode ser habilitado explicitamente configurando WERF_THREE_WAY_MERGE_MODE=enabled agora

O que fazer com o escalonamento automático de recursos?

Existem 2 tipos de escalonamento automático no Kubernetes: HPA (horizontal) e VPA (vertical).

Horizontal seleciona automaticamente o número de réplicas, vertical - o número de recursos. Tanto o número de réplicas quanto os requisitos de recursos são especificados no manifesto de recursos (consulte Manifesto de Recursos). spec.replicas ou spec.containers[].resources.limits.cpu, spec.containers[].resources.limits.memory и outros).

Problema: se um usuário configurar um recurso em um gráfico para especificar determinados valores para recursos ou réplicas e escalonadores automáticos estiverem habilitados para esse recurso, então, com cada implantação, o werf redefinirá esses valores para o que está escrito no manifesto do gráfico .

Existem duas soluções para o problema. Para começar, é melhor evitar especificar explicitamente valores de escalonamento automático no manifesto do gráfico. Se esta opção não for adequada por algum motivo (por exemplo, porque é conveniente definir limites iniciais de recursos e o número de réplicas no gráfico), então o werf oferece as seguintes anotações:

  • werf.io/set-replicas-only-on-creation=true
  • werf.io/set-resources-only-on-creation=true

Se tal anotação estiver presente, o werf não redefinirá os valores correspondentes em cada implantação, mas apenas os definirá quando o recurso for criado inicialmente.

Para obter mais detalhes, consulte a documentação do projeto para HPA и VPA.

Proibir o uso de patch de mesclagem de 3 vias

Atualmente, o usuário pode proibir o uso de novos patches no werf usando uma variável de ambiente WERF_THREE_WAY_MERGE_MODE=disabled. Porém, começando A partir de 1º de março de 2020, esta proibição não será mais aplicada. e só será possível usar patches de mesclagem de 3 vias.

Adoção de recursos no werf

Dominar o método de aplicação de alterações com patches de mesclagem de três vias nos permitiu implementar imediatamente um recurso como a adoção de recursos existentes no cluster na versão do Helm.

O Helm 2 tem um problema: você não pode adicionar um recurso aos manifestos do gráfico que já existe no cluster sem recriar esse recurso do zero (consulte. #6031, #3275). Ensinamos o werf a aceitar os recursos existentes para liberação. Para fazer isso, você precisa instalar uma anotação na versão atual do recurso do cluster em execução (por exemplo, usando kubectl edit):

"werf.io/allow-adoption-by-release": RELEASE_NAME

Agora o recurso precisa ser descrito no gráfico e na próxima vez que o werf implantar uma versão com o nome apropriado, o recurso existente será aceito nesta versão e permanecerá sob seu controle. Além disso, no processo de aceitação de um recurso para liberação, o werf trará o estado atual do recurso do cluster em execução para o estado descrito no gráfico, usando os mesmos patches de mesclagem de 3 vias e a regra de recursos sincronizados.

Nota: configuração WERF_THREE_WAY_MERGE_MODE não afeta a adoção de recursos - no caso de adoção, é sempre utilizado um patch de mesclagem de 3 vias.

Detalhes - em documentação.

Conclusões e planos futuros

Espero que depois deste artigo tenha ficado mais claro o que são os patches de mesclagem de 3 vias e por que eles vieram até eles. Do ponto de vista prático do desenvolvimento do projeto werf, a sua implementação foi mais um passo para melhorar a implantação do tipo Helm. Agora você pode esquecer os problemas com a sincronização de configuração, que muitas vezes surgiam ao usar o Helm 2. Ao mesmo tempo, um novo recurso útil de adoção de recursos já baixados do Kubernetes foi adicionado à versão do Helm.

Ainda existem alguns problemas e desafios com implantações semelhantes ao Helm, como o uso de modelos Go, que continuaremos a abordar.

Informações sobre métodos de atualização de recursos e adoção também podem ser encontradas em esta página de documentação.

Elmo 3

Digno de nota especial lançado outro dia, uma nova versão principal do Helm - v3 - que também usa patches de mesclagem de 3 vias e se livra do Tiller. A nova versão do Helm requer migração instalações existentes para convertê-las no novo formato de armazenamento de lançamento.

Werf, por sua vez, atualmente se livrou do uso do Tiller, mudou para mesclagem de 3 vias e adicionou muito mais, permanecendo compatível com as instalações existentes do Helm 2 (nenhum script de migração precisa ser executado). Portanto, até que o werf mude para o Helm 3, os usuários do werf não perderão as principais vantagens do Helm 3 sobre o Helm 2 (o werf também as possui).

No entanto, a mudança do werf para a base de código Helm 3 é inevitável e acontecerá em um futuro próximo. Presumivelmente, será o werf 1.1 ou o werf 1.2 (no momento, a versão principal do werf é 1.0; para obter mais informações sobre o dispositivo de controle de versão do werf, consulte aqui). Durante este tempo, o Helm 3 terá tempo para se estabilizar.

PS

Leia também em nosso blog:

Fonte: habr.com

Adicionar um comentário