Nossa implementação de Continuous Deployment na plataforma do cliente

Nós da True Engineering montamos um processo para entrega contínua de atualizações aos servidores dos clientes e queremos compartilhar essa experiência.

Para começar, desenvolvemos um sistema online para o cliente e o implantamos em nosso próprio cluster Kubernetes. Agora, nossa solução de alta carga migrou para a plataforma do cliente, para a qual configuramos um processo de implantação contínua totalmente automático. Graças a isso, aceleramos o tempo de colocação no mercado – a entrega de mudanças no ambiente do produto.

Neste artigo falaremos sobre todas as etapas do processo de Continuous Deployment (CD) ou entrega de atualizações na plataforma do cliente:

  1. Como esse processo começa?
  2. sincronização com o repositório Git do cliente,
  3. montagem de backend e frontend,
  4. implantação automática de aplicativos em um ambiente de teste,
  5. implantação automática no Prod.

Compartilharemos os detalhes da configuração ao longo do caminho.

Nossa implementação de Continuous Deployment na plataforma do cliente

1. Inicie o CD

A implantação contínua começa com o desenvolvedor enviando as alterações para o branch de lançamento do nosso repositório Git.

Nosso aplicativo é executado em uma arquitetura de microsserviços e todos os seus componentes são armazenados em um repositório. Graças a isso, todos os microsserviços são coletados e instalados, mesmo que um deles tenha sido alterado.

Organizamos o trabalho por meio de um repositório por vários motivos:

  • Facilidade de desenvolvimento - o aplicativo está em desenvolvimento ativo, para que você possa trabalhar com todo o código de uma vez.
  • Um único pipeline de CI/CD que garante que o aplicativo como um sistema único passe em todos os testes e seja entregue ao ambiente de produção do cliente.
  • Eliminamos a confusão nas versões - não precisamos armazenar um mapa de versões de microsserviços e descrever sua configuração para cada microsserviço em scripts Helm.

2. Sincronização com o repositório Git do código-fonte do cliente

As alterações feitas são sincronizadas automaticamente com o repositório Git do cliente. Lá é configurado o assembly da aplicação, que é lançado após a atualização do branch, e a implantação para a continuação. Ambos os processos se originam em seu ambiente a partir de um repositório Git.

Não podemos trabalhar diretamente com o repositório do cliente porque precisamos de nossos próprios ambientes para desenvolvimento e teste. Usamos nosso repositório Git para esses fins - ele é sincronizado com o repositório Git. Assim que um desenvolvedor publica alterações no branch apropriado de nosso repositório, o GitLab imediatamente envia essas alterações ao cliente.

Nossa implementação de Continuous Deployment na plataforma do cliente

Depois disso você precisa fazer a montagem. Consiste em várias etapas: montagem backend e frontend, teste e entrega à produção.

3. Montagem do backend e frontend

Construir o backend e o frontend são duas tarefas paralelas executadas no sistema GitLab Runner. Sua configuração original do assembly está localizada no mesmo repositório.

Tutorial para escrever um script YAML para construção no GitLab.

O GitLab Runner pega o código do repositório necessário, monta-o com o comando de construção do aplicativo Java e o envia para o registro do Docker. Aqui montamos o backend e o frontend, obtemos imagens Docker, que colocamos em um repositório do lado do cliente. Para gerenciar imagens Docker que usamos Plug-in Gradle.

Sincronizamos as versões de nossas imagens com a versão de lançamento que será publicada no Docker. Para um bom funcionamento, fizemos vários ajustes:

1. Os contêineres não são reconstruídos entre o ambiente de teste e o ambiente de produção. Fizemos parametrizações para que um mesmo container pudesse funcionar com todas as configurações, variáveis ​​de ambiente e serviços tanto no ambiente de testes quanto em produção sem necessidade de reconstrução.

2. Para atualizar uma aplicação via Helm, você deve especificar sua versão. Construímos o backend, o frontend e atualizamos o aplicativo - são três tarefas diferentes, por isso é importante usar a mesma versão do aplicativo em todos os lugares. Para esta tarefa, usamos dados do histórico do Git, já que a configuração e os aplicativos do cluster K8S estão no mesmo repositório Git.

Obtemos a versão do aplicativo a partir dos resultados da execução do comando
git describe --tags --abbrev=7.

4. Implantação automática de todas as alterações no ambiente de teste (UAT)

A próxima etapa neste script de construção é atualizar automaticamente o cluster K8S. Isso ocorre desde que todo o aplicativo tenha sido construído e todos os artefatos tenham sido publicados no Docker Registry. Depois disso, a atualização do ambiente de teste é iniciada.

A atualização do cluster é iniciada usando Atualização do leme. Se, como resultado, algo não sair conforme o planejado, o Helm reverterá automaticamente e de forma independente todas as suas alterações. Seu trabalho não precisa ser controlado.

Fornecemos a configuração do cluster K8S junto com a montagem. Portanto, o próximo passo é atualizá-lo: configMaps, implantações, serviços, segredos e quaisquer outras configurações do K8S que alteramos.

O Helm então executa uma atualização RollOut do próprio aplicativo no ambiente de teste. Antes de o aplicativo ser implantado na produção. Isso é feito para que os usuários possam testar manualmente os recursos de negócios que colocamos no ambiente de teste.

5. Implantação automática de todas as alterações no Prod

Para implantar uma atualização no ambiente de produção, basta clicar em um botão no GitLab - e os contêineres são imediatamente entregues ao ambiente de produção.

O mesmo aplicativo pode funcionar em ambientes diferentes (teste e produção) sem necessidade de reconstrução. Usamos os mesmos artefatos sem alterar nada na aplicação e definimos os parâmetros externamente.

A parametrização flexível das configurações da aplicação depende do ambiente em que a aplicação será executada. Movemos todas as configurações do ambiente externamente: tudo é parametrizado através da configuração do K8S e dos parâmetros do Helm. Quando o Helm implanta um assembly no ambiente de teste, as configurações de teste são aplicadas a ele e as configurações do produto são aplicadas ao ambiente de produção.

O mais difícil foi parametrizar todos os serviços e variáveis ​​​​utilizados que dependem do ambiente, e traduzi-los em variáveis ​​​​de ambiente e configurações de descrição de parâmetros de ambiente para Helm.

As configurações do aplicativo usam variáveis ​​de ambiente. Seus valores são definidos em contêineres usando o configmap K8S, que é modelado usando modelos Go. Por exemplo, definir uma variável de ambiente para o nome de domínio pode ser feito assim:

APP_EXTERNAL_DOMAIN: {{ (pluck .Values.global.env .Values.app.properties.app_external_domain | first) }}

.Valores.global.env – esta variável armazena o nome do ambiente (prod, stage, UAT).
.Values.app.properties.app_external_domain – nesta variável definimos o domínio desejado no arquivo .Values.yaml

Ao atualizar um aplicativo, o Helm cria um arquivo configmap.yaml a partir de modelos e preenche o valor APP_EXTERNAL_DOMAIN com o valor desejado dependendo do ambiente em que a atualização do aplicativo é iniciada. Esta variável já está definida no contêiner. Ela pode ser acessada a partir da aplicação, portanto cada ambiente da aplicação terá um valor diferente para esta variável.

Há relativamente pouco tempo, o suporte K8S apareceu no Spring Cloud, incluindo trabalho com configMaps: Spring Cloud Kubernetes. Embora o projeto esteja se desenvolvendo ativamente e mudando radicalmente, não podemos usá-lo na produção. Mas monitoramos ativamente sua condição e a usamos em configurações DEV. Assim que ele se estabilizar, passaremos do uso de variáveis ​​de ambiente para ele.

No total

Portanto, a implantação contínua está configurada e funcionando. Todas as atualizações ocorrem com um toque de tecla. A entrega de alterações ao ambiente do produto é automática. E, o mais importante, as atualizações não param o sistema.

Nossa implementação de Continuous Deployment na plataforma do cliente

Planos futuros: migração automática de banco de dados

Pensamos em atualizar o banco de dados e na possibilidade de reverter essas alterações. Afinal, duas versões diferentes do aplicativo estão rodando ao mesmo tempo: a antiga está rodando e a nova está ativa. E desligaremos o antigo somente quando tivermos certeza de que a nova versão funciona. A migração do banco de dados deve permitir trabalhar com ambas as versões do aplicativo.

Portanto, não podemos simplesmente alterar o nome da coluna ou outros dados. Mas podemos criar uma nova coluna, copiar os dados da coluna antiga para ela e escrever gatilhos que, ao atualizar os dados, irão copiá-los e atualizá-los simultaneamente em outra coluna. E após a implantação bem-sucedida da nova versão do aplicativo, após o período de suporte pós-lançamento, poderemos excluir a coluna antiga e o gatilho que se tornou desnecessário.

Se a nova versão do aplicativo não funcionar corretamente, podemos reverter para a versão anterior, incluindo a versão anterior do banco de dados. Resumindo, nossas alterações permitirão que você trabalhe simultaneamente com diversas versões do aplicativo.

Planejamos automatizar a migração do banco de dados via job K8S, integrando-o ao processo de CD. E com certeza compartilharemos essa experiência no Habré.

Fonte: habr.com

Adicionar um comentário