Na True Engineering, configuramos o processo de entrega contínua de atualizações para os servidores do cliente e queremos compartilhar essa experiência.
Primeiro, desenvolvemos um sistema online para o cliente e o implantamos em nosso próprio cluster Kubernetes. Agora, nossa solução altamente carregada mudou para a plataforma do cliente, para a qual configuramos o processo de implantação contínua totalmente automático. Graças a isso, aceleramos o tempo de colocação no mercado - entrega de alterações no ambiente do produto.
Neste artigo, falaremos sobre todos os estágios do processo de implantação contínua (CD) ou entrega de atualizações para a plataforma do cliente:
- como esse processo começa
- sincronização com o repositório Git do cliente,
- montagem de back-end e front-end
- implantação automática do aplicativo em um ambiente de teste,
- implantação automática no Prod.
No processo, compartilharemos os detalhes das configurações.

1. Inicie o CD
A Implantação Contínua começa com o fato de o desenvolvedor postar as alterações na ramificação de lançamento do nosso repositório Git.
Nosso aplicativo funciona com base na arquitetura de microsserviço e todos os seus componentes são armazenados em um repositório. Graças a isso, todos os microsserviços são montados e instalados, mesmo que um deles tenha sido alterado.
Organizamos o trabalho através de um repositório por vários motivos:
- Facilidade de desenvolvimento - o aplicativo está desenvolvendo ativamente, para que você possa trabalhar imediatamente com todo o código.
- 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 produtos do cliente.
- Excluímos confusão nas versões - não precisamos armazenar um mapa de versões de microsserviço e descrever nossa configuração para cada microsserviço nos 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á, o conjunto do aplicativo é configurado, que é iniciado após a atualização da ramificação e a implantação no prod. Ambos os processos ocorrem em seu ambiente a partir do repositório Git.
Não podemos trabalhar diretamente com o repositório do cliente, porque precisamos de nossos próprios ambientes de desenvolvimento e teste. Usamos nosso repositório Git para esses fins - ele é sincronizado com o repositório Git. Assim que o desenvolvedor postar as alterações na ramificação apropriada do nosso repositório, o GitLab envia imediatamente essas alterações ao cliente.

Depois disso, você precisa fazer uma montagem. Consiste em várias etapas: montagem do back-end e front-end, teste e entrega ao produto.
3. Crie o back-end e o front-end
Montagem de back-end e front-end são duas tarefas paralelas que são executadas no sistema GitLab Runner. Sua configuração da montagem original está no mesmo repositório.
Tutorial para escrever um script YAML para compilar no GitLab .
O GitLab Runner pega o código do repositório desejado, coleta o comando de construção do aplicativo Java e o envia ao registro do Docker. Aqui, coletamos o back-end e o front-end, obtemos imagens do Docker, que colocamos no repositório no lado do cliente. Para gerenciar imagens do Doker, use o
plug-in Gradle .
Sincronizamos as versões de nossas imagens com a versão do lançamento, que será publicada no Docker. Para um bom funcionamento, fizemos várias configurações:
1. Entre o ambiente de teste e os contêineres de supermercado, não são remontados. Fizemos a parametrização para que o mesmo contêiner pudesse funcionar sem reconstruir com todas as configurações, variáveis de ambiente e serviços, tanto no ambiente de teste quanto no produto.
2. Para atualizar o aplicativo através do Helm, você deve especificar sua versão. Temos o conjunto de back-end, o front-end e a atualização do aplicativo - essas são três tarefas diferentes, por isso é importante usar a mesma versão do aplicativo em qualquer lugar. Para esta tarefa, usamos dados do histórico do Git, pois temos uma configuração de cluster K8S e os aplicativos estão no mesmo repositório Git.
Obtemos a versão do aplicativo a partir dos resultados do comando
git describe --tags --abbrev=7
.
4. Implantação automática de todas as alterações em um ambiente de teste (UAT)
A próxima etapa deste script de construção é atualizar automaticamente o cluster K8S. Isso acontece desde que todo o aplicativo seja montado e todos os artefatos sejam publicados no Docker Registry. Depois disso, a atualização do ambiente de teste é iniciada.
A atualização de cluster é iniciada usando o
Helm Update . Se, como resultado, algo der errado, o Helm reverterá automaticamente e independentemente todas as alterações. Seu trabalho não precisa ser controlado.
Juntamente com a montagem, entregamos a configuração do cluster K8S. Portanto, a próxima etapa é atualizá-lo: configMaps, implantações, serviços, segredos e quaisquer outras configurações do K8S que alteramos.
Depois disso, o Helm inicia o RollOut e atualiza o aplicativo em um ambiente de teste. Antes de o aplicativo ser implantado no prod. Isso é feito para que os usuários verifiquem manualmente os recursos comerciais que publicamos no ambiente de teste.
5. Implante automaticamente todas as alterações no Prod
Para implantar a atualização no ambiente do produto, basta clicar em um botão no GitLab - e os contêineres são entregues imediatamente no ambiente do produto.
Um mesmo aplicativo pode funcionar sem reconstruir em ambientes diferentes - teste e produção. Usamos os mesmos artefatos sem alterar nada no aplicativo e configuramos os parâmetros de fora.
A parametrização flexível das configurações do aplicativo depende do ambiente em que esse aplicativo será executado. Tiramos todas as configurações do ambiente: tudo é parametrizado através da configuração do K8S e dos parâmetros Helm. Quando o Helm implanta uma montagem em um ambiente de teste, os parâmetros de teste se aplicam a ele e os parâmetros do produto se aplicam ao ambiente do produto.
O mais difícil foi parametrizar todos os serviços e variáveis usadas, que dependem do ambiente, e convertê-los em variáveis de ambiente e uma descrição-configuração dos parâmetros de ambiente do Helm.
Os parâmetros 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, a configuração de uma variável de ambiente como um nome de domínio pode ser feita assim:
APP_EXTERNAL_DOMAIN: {{ (pluck .Values.global.env .Values.app.properties.app_external_domain | first) }}
.Values.global.env - o nome do ambiente (prod, stage, UAT) é armazenado nessa variável.
.Values.app.properties.app_external_domain - nessa variável, no arquivo .Values.yaml, definimos o domínio desejado
Ao atualizar o aplicativo, o Helm cria o arquivo configmap.yaml a partir dos modelos e preenche o valor APP_EXTERNAL_DOMAIN com o valor necessário, dependendo do ambiente em que a atualização do aplicativo é iniciada. Essa variável já está definida no contêiner. O acesso a ele é do aplicativo, respectivamente, em cada ambiente do aplicativo, haverá um valor diferente dessa variável.
Relativamente recente, o Spring Cloud introduziu o suporte ao K8S, incluindo o trabalho com o configMaps:
Spring Cloud Kubernetes . Enquanto o projeto estiver ativamente desenvolvendo e mudando drasticamente, não podemos usá-lo na produção. Mas monitoramos ativamente sua condição e a usamos nas configurações de DEV. Assim que estabilizar, passaremos de usar variáveis de ambiente para ele.
Total
Portanto, a implantação contínua está em funcionamento. Todas as atualizações ocorrem com o clique de um botão. A entrega de alterações no ambiente alimentar é automática. E, o mais importante, as atualizações não param o sistema.

Planos futuros: migração automática de base
Pensamos em atualizar o banco de dados e na capacidade de reverter essas alterações. Afinal, duas versões diferentes do aplicativo funcionam simultaneamente: a antiga funciona e a nova aumenta. E desligaremos a antiga somente quando estivermos convencidos de que a nova versão está funcionando. A migração do banco de dados deve permitir trabalhar com ambas as versões do aplicativo.
Portanto, não podemos apenas mudar 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, quando os dados forem atualizados, os copiarão e atualizarão 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, podemos 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. Em uma palavra, nossas alterações permitirão trabalhar simultaneamente com várias versões do aplicativo.
Planejamos automatizar a migração do banco de dados através do trabalho K8S, incorporando-o ao processo do CD. E certamente compartilharemos essa experiência em Habré.