Ciclos de lançamento mais rápidos são uma das principais vantagens das arquiteturas de microsserviços. Mas sem um bom processo de CI/CD, você não alcançará a agilidade que os microsserviços prometem. Este artigo descreve os desafios e recomenda algumas abordagens para o problema.
O que é CI/CD?
Quando falamos de CI/CD, estamos realmente falando de vários processos relacionados: integração contínua, entrega contínua e implantação contínua.
de integração contínua. As alterações de código são mescladas com frequência no branch principal. Os processos automatizados de build e teste garantem que o código no branch principal seja sempre de qualidade de produção.
de entrega contínua. Todas as alterações de código que passam o processo de CI são publicadas automaticamente em um ambiente semelhante à produção. A implantação no ambiente de produção ao vivo pode exigir aprovação manual, mas é automatizada de outra forma. O objetivo é que seu código sempre esteja pronto para implantar em produção.
implantação contínua. As alterações de código que passam as duas etapas anteriores são implantadas automaticamente emde produção.
Aqui estão algumas metas de um processo de CI/CD robusto para uma arquitetura de microsserviços:
Cada equipe pode criar e implantar os serviços que possui de forma independente, sem afetar ou interromper outras equipes.
Antes que uma nova versão de um serviço seja implantada na produção, ela será implantada em ambientes de desenvolvimento/teste/QA para validação. As portas de qualidade são impostas em cada estágio.
Uma nova versão de um serviço pode ser implantada lado a lado com a versão anterior.
Políticas de controle de acesso suficientes estão em vigor.
Para cargas de trabalho em contêineres, você pode confiar nas imagens de contêiner implantadas na produção.
Por que um pipeline de CI/CD robusto importa
Em um aplicativo monolítico tradicional, há um único pipeline de build cuja saída é executável pelo aplicativo. Todo o trabalho de desenvolvimento se alimenta desse pipeline. Se um bug de alta prioridade for encontrado, uma correção deverá ser integrada, testada e publicada, o que pode atrasar a versão dos novos recursos. Você pode atenuar esses problemas tendo módulos bem fatorados e usando branches de recursos para minimizar o impacto das alterações de código. Mas à medida que o aplicativo se torna mais complexo e mais recursos são adicionados, o processo de lançamento de um monólito tende a ficar mais frágil e provavelmente será interrompido.
Seguindo a filosofia dos microsserviços, nunca deve haver um treinamento de lançamento longo em que cada equipe tenha que entrar na fila. A equipe que cria o serviço "A" pode liberar uma atualização a qualquer momento, sem esperar que as alterações no serviço "B" sejam mescladas, testadas e implantadas.
diagrama de monolito de CI/CD
Para obter uma alta velocidade de lançamento, o pipeline de lançamento deve ser automatizado e altamente confiável para minimizar o risco. Se você liberar para a produção uma ou mais vezes por dia, regressões ou interrupções de serviço devem ser raras. Ao mesmo tempo, se uma atualização incorreta for implantada, você deverá ter uma maneira confiável de reverter ou reverter rapidamente para uma versão anterior de um serviço.
Desafios
Muitas pequenas bases de código independentes. Cada equipe é responsável por criar seu próprio serviço, com seu próprio pipeline de build. Em algumas organizações, as equipes podem usar repositórios de código separados. Repositórios separados podem levar a uma situação em que o conhecimento de como criar o sistema é distribuído entre equipes e ninguém na organização sabe como implantar todo o aplicativo. Por exemplo, o que acontece em um cenário de recuperação de desastre, se você precisar implantar rapidamente em um novo cluster?
Mitigação: tenha um pipeline unificado e automatizado para criar e implantar serviços, de modo que esse conhecimento não esteja "oculto" em cada equipe.
Várias linguagens e estruturas. Com cada equipe usando sua própria combinação de tecnologias, pode ser difícil criar um único processo de build que funcione em toda a organização. O processo de build deve ser flexível o suficiente para que cada equipe possa adaptá-lo para sua escolha de linguagem ou estrutura.
mitigação: conteinerize o processo de build para cada serviço. Dessa forma, o sistema de build só precisa ser capaz de executar os contêineres.
integração e teste de carga. Com as equipes lançando atualizações em seu próprio ritmo, pode ser desafiador criar testes de ponta a ponta robustos, especialmente quando os serviços têm dependências de outros serviços. Além disso, a execução de um cluster de produção completo pode ser cara, portanto, é improvável que cada equipe execute seu próprio cluster completo em escalas de produção, apenas para teste.
de gerenciamento de versão. Todas as equipes devem ser capazes de implantar uma atualização na produção. Isso não significa que todos os membros da equipe têm permissões para fazer isso. Mas ter uma função centralizada do Gerenciador de Lançamentos pode reduzir a velocidade das implantações.
Mitigação: quanto mais o processo de CI/CD for automatizado e confiável, menos deve haver a necessidade de uma autoridade central. Dito isto, você pode ter políticas diferentes para liberar as principais atualizações de recursos versus correções de bugs secundárias. Ser descentralizado não significa governança zero.
atualizações do serviço . Quando você atualiza um serviço para uma nova versão, ele não deve interromper outros serviços que dependem dele.
mitigação: use técnicas de implantação, como verde-azul ou canário, para alterações sem interrupção. Para alterar a API, implante a nova versão lado a lado com a versão anterior. Dessa forma, os serviços que consomem a API anterior podem ser atualizados e testados para a nova API. Veja de Serviços de Atualização, abaixo.
Monorepo vs. multi-repositório
Antes de criar um fluxo de trabalho de CI/CD, você deve saber como a base de código será estruturada e gerenciada.
- As equipes funcionam em repositórios separados ou em um monorepo (repositório único)?
- Qual é sua estratégia de ramificação?
- Quem pode enviar código por push para a produção? Existe uma função de gerenciador de lançamentos?
A abordagem monorepo vem ganhando favores, mas há vantagens e desvantagens para ambos.
Monorepo | Vários repositórios | |
---|---|---|
vantagens | Compartilhamento de código Mais fácil padronizar código e ferramentas Código de refatoração mais fácil Capacidade de descoberta – exibição única do código |
Limpar a propriedade por equipe Potencialmente menos conflitos de mesclagem Ajuda a impor a desassociação de microsserviços |
desafios | Alterações no código compartilhado podem afetar vários microsserviços Maior potencial para conflitos de mesclagem As ferramentas devem ser dimensionadas para uma base de código grande Controle de acesso Processo de implantação mais complexo |
Mais difícil de compartilhar código Mais difícil de impor padrões de codificação Gerenciamento de dependências Base de código difusa, baixa capacidade de descoberta Falta de infraestrutura compartilhada |
Atualizando serviços
Há várias estratégias para atualizar um serviço que já está em produção. Aqui, discutimos três opções comuns: atualização sem interrupção, implantação azul-verde e versão canário.
Atualizações sem interrupção
Em uma atualização sem interrupção, você implanta novas instâncias de um serviço e as novas instâncias começam a receber solicitações imediatamente. À medida que as novas instâncias aparecem, as instâncias anteriores são removidas.
Exemplo. No Kubernetes, as atualizações sem interrupção são o comportamento padrão quando você atualiza a especificação do pod para umde implantação de
Exemplo. O Azure Service Fabric usa a estratégia de atualização sem interrupção por padrão. Essa estratégia é mais adequada para implantar uma versão de um serviço com novos recursos sem alterar as APIs existentes. O Service Fabric inicia uma implantação de atualização atualizando o tipo de aplicativo para um subconjunto dos nós ou um domínio de atualização. Em seguida, ele avança para o próximo domínio de atualização até que todos os domínios sejam atualizados. Se um domínio de atualização não for atualizado, o tipo de aplicativo reverterá para a versão anterior em todos os domínios. Lembre-se de que um tipo de aplicativo com vários serviços (e se todos os serviços forem atualizados como parte de uma implantação de atualização) está propenso a falhas. Se um serviço não for atualizado, todo o aplicativo será revertido para a versão anterior e os outros serviços não serão atualizados.
Um desafio das atualizações sem interrupção é que, durante o processo de atualização, uma combinação de versões antigas e novas está em execução e recebendo tráfego. Durante esse período, qualquer solicitação pode ser roteada para qualquer uma das duas versões.
Para alterar a API, uma boa prática é dar suporte a ambas as versões lado a lado, até que todos os clientes da versão anterior sejam atualizados. Consultede controle de versão da API
Implantação azul-verde
Em uma implantação azul-verde, você implanta a nova versão junto com a versão anterior. Depois de validar a nova versão, você alterna todo o tráfego de uma vez da versão anterior para a nova versão. Após a opção, você monitora o aplicativo em busca de problemas. Se algo der errado, você poderá alternar de volta para a versão antiga. Supondo que não haja problemas, você pode excluir a versão antiga.
Com um aplicativo monolítico ou N mais tradicional, a implantação azul-verde geralmente significava provisionar dois ambientes idênticos. Você implantaria a nova versão em um ambiente de preparo e redirecionaria o tráfego do cliente para o ambiente de preparo, por exemplo, trocando endereços VIP. Em uma arquitetura de microsserviços, as atualizações ocorrem no nível do microsserviço, portanto, você normalmente implantaria a atualização no mesmo ambiente e usaria um mecanismo de descoberta de serviço para trocar.
exemplo. No Kubernetes, você não precisa provisionar um cluster separado para fazer implantações azul-verde. Em vez disso, você pode aproveitar os seletores. Crie um novo recurso de implantação com uma nova especificação de pod e um conjunto diferente de rótulos. Crie essa implantação, sem excluir a implantação anterior ou modificar o serviço que aponta para ela. Depois que os novos pods estiverem em execução, você poderá atualizar o seletor do serviço para corresponder à nova implantação.
Uma desvantagem da implantação azul-verde é que, durante a atualização, você está executando o dobro de pods para o serviço (atual e próximo). Se os pods exigirem muitos recursos de CPU ou memória, talvez seja necessário escalar horizontalmente o cluster temporariamente para lidar com o consumo de recursos.
Versão canário
Em uma versão canário, você distribui uma versão atualizada para um pequeno número de clientes. Em seguida, você monitora o comportamento do novo serviço antes de distribuí-lo para todos os clientes. Isso permite que você faça uma distribuição lenta de forma controlada, observe dados reais e detecte problemas antes que todos os clientes sejam afetados.
Uma versão canário é mais complexa de gerenciar do que a atualização azul-verde ou sem interrupção, pois você deve rotear dinamicamente solicitações para diferentes versões do serviço.
exemplo. No Kubernetes, você pode configurar um serviço para abranger dois conjuntos de réplicas (um para cada versão) e ajustar as contagens de réplica manualmente. No entanto, essa abordagem é bastante refinada, devido à maneira como a carga do Kubernetes se equilibra entre pods. Por exemplo, se você tiver um total de 10 réplicas, só poderá deslocar o tráfego em 10 incrementos%. Se você estiver usando uma malha de serviço, poderá usar as regras de roteamento de malha de serviço para implementar uma estratégia de lançamento canário mais sofisticada.
Próximas etapas
- Roteiro de aprendizagem: definir e implementar de integração contínua
- Treinamento de : Introdução ao de entrega contínua
- arquitetura de microsserviços
- Por que usar uma abordagem de microsserviços para criar aplicativos