Entendendo pipelines de CI/CD

Se você tem lido sobre integração, entrega e implantação contínuas (conhecidas coletivamente como CI/CD - Continuous Integration / Continuous Delivery/Deployment), você provavelmente conhece o termo “pipeline automatizado” e o fato de que ele desempenha um papel central na implementação dessas práticas. Mas o que é exatamente um pipeline de Integração / Entrega Contínua? E como você consegue um?

O objetivo da CI/CD é reduzir o tempo que leva para entregar software aos usuários sem comprometer a qualidade. Você consegue isto verificando as alterações com frequência, testando-as rigorosamente e reagindo ao feedback imediatamente, para que você possa implantar suas alterações em produção com a frequência que desejar.

O que é um pipeline de CI/CD?

Quando falamos de um pipeline de CI/CD, estamos nos referindo à série de etapas pelas quais seu código passa desde o momento em que sai de sua máquina de desenvolvimento, passa pela fase de testes e preparação até finalmente sair pela porta e chegar às mãos de seus usuários.

Como a estratégia de CI/CD é executar esse processo com regularidade, geralmente várias vezes ao dia, é essencial automatizar o máximo possível, com cada etapa ou disparando a seguinte ou levantando uma flag caso algo tenha dado errado.

A automação não apenas acelera o processo geral e, dessa forma, os ciclos de feedback individuais, como também garante que cada etapa seja executada de forma consistente e confiável.

Os estágios de um pipeline de compilação

Embora a forma exata de seu pipeline de CI/CD dependa do tipo de produto que você está construindo, ao lado dos requisitos de sua organização, há um padrão geral que todos os pipelines tendem a seguir, que descrevemos aqui.

O processo começa com um commit ao master (ou qualquer branch que você nomeou como o branch CI), que ou dispara um build ou um conjunto inicial de testes de unidade. Os resultados são enviados de volta a um painel e, se o build ou o teste falhar, ele será marcado com uma notificação automatizada.

Você pode configurar o pipeline para interromper o processo para que você possa resolver o problema e começar novamente com um novo commit ou criar exceções para tipos específicos de falha para que o processo possa continuar.

O estágio seguinte envolve uma série de testes automatizados, com feedback fornecido após cada rodada de testes. Geralmente, os testes são estruturados de forma que os testes mais rápidos sejam executados primeiro, fornecendo feedback o mais cedo possível.

Testes mais elaborados que irão ocupar os servidores por mais tempo, como testes de ponta a ponta, só são executados depois que os testes anteriores tiverem sido executados com sucesso. Isso torna o uso de recursos mais eficiente.

Depois que os testes automatizados são concluídos, o software é geralmente implantado numa série de ambientes de staging, alguns dos quais podem ser usados para testes manuais adicionais, enquanto outros podem ser usados para treinamento, suporte e pré-visualizações do cliente.

O estágio final da arquitetura do pipeline de CI/CD envolve colocar as alterações ao vivo e pode ser acionado manualmente (no caso da entrega contínua) ou automaticamente (como na implantação contínua).

Vejamos algumas considerações para cada um desses estágios com um pouco mais de detalhes.

Flags e branches

O primeiro passo para adotar a integração contínua é colocar toda a sua base de código num sistema de controle de versão (VCS, também conhecido como sistema de controle de fontes ou SCM), como Git, Mercurial ou Perforce, e então fazer com que todos da sua equipe desenvolvam o hábito de fazer commit de suas alterações com frequência. Cada commit para o master inicia o pipeline, construindo e testando o código para fornecer um feedback rápido sobre o que você escreveu.

Embora submissões frequentes sejam uma prática importante de CI/CD, se você estiver trabalhando num recurso maior que levará vários dias ou semanas para ser concluído, fazer submissões periódicas durante esse processo pode parecer uma faca de dois gumes.

Fazer push de suas alterações através do pipeline em incrementos regulares fornece feedback rápido e reduz a probabilidade de conflitos mais complexos do que se você esperar até o fim.

Por outro lado, você provavelmente não vai querer lançar um recurso incompleto para os usuários e também poderá não estar pronto para compartilhar seu trabalho em andamento com usuários internos através dos ambientes de staging.

Flags de recursos e branches de recursos oferecem maneiras de contornar esse problema. Com flags de recursos, você especifica os ambientes nos quais seu código é visível para os usuários. Você ainda faz commit de suas alterações para o master e elas permanecem visíveis para sua equipe, mas você decide quando a funcionalidade estará disponível no staging e produção.

Branches de recursos permitem que você desenvolva seu recurso em uma branch separada, sem perder os benefícios do build e testes automatizados. Ao disparar o pipeline de CI/CD em cada commit para um branch de recurso, assim como você faz com um commit para master, você pode obter um feedback rápido sobre o que construiu.

Construir e testar

Tendo disparado uma instância de seu pipeline com um commit, os próximos estágios são construir e testar. Se você tiver testes de unidade automatizados, eles geralmente são executados antes da construção com linting e verificações de análise estáticas.

A ferramenta de build que você usa (como Ant ou Maven) e os detalhes das etapas de build dependem da linguagem e do framework no qual você está trabalhando. Ao executar o build automatizado num servidor de build dedicado, você pode evitar problemas posteriores causados por dependências ausentes; o clássico problema “funciona na minha máquina”.

A saída da etapa de build inclui os instaladores, binários ou containers (os artefatos de build), que são então implantados em ambientes de teste e combinados com outras partes do sistema para executar testes automatizados de nível superior: testes de integração, testes de componentes e testes ponta a ponta, bem como testes não funcionais, como análises de desempenho e segurança.

Esses testes podem ser executados em paralelo para acelerar o pipeline e fornecer um feedback mais rápido.

Containers vs VMs

Para que os resultados dos seus testes automatizados sejam confiáveis, você precisa garantir que eles sejam executados de forma consistente.

O ideal é que seus ambientes de teste sejam configurados para se assemelhar ao máximo possível com a produção e devem ser reiniciados entre cada execução dos testes para evitar que inconsistências do ambiente interfiram nos resultados do teste.

As máquinas virtuais (VMs) são há muito tempo uma escolha popular para a execução de ambientes de teste, já que você pode programar em linguagem script todo o processo de atualizá-los para cada novo build em teste.

No entanto, encerrar e reiniciar novas VMs leva tempo, enquanto seus scripts precisarão incluir as configurações de cada ambiente virtual, para que possa fornecer todas as dependências de que o software precisa para ser executado. Quando novas dependências são adicionadas, os scripts do ambiente precisam ser atualizados: um detalhe fácil de esquecer até que você se pergunte por que seu build não está executando.

Você pode evitar esses problemas empacotando seu código em um container como parte da etapa inicial do build. Um container inclui todas as dependências que o software precisa para executar, fazendo com que ele seja altamente portátil e mais fácil de implantar em diferentes ambientes.

Se você estiver hospedando seu CI/CD em sua própria infraestrutura, ainda precisará de VMs para implantar os contêineres, mas há menos trabalho envolvido na preparação do ambiente de teste, o que ajuda a manter o pipeline operando com eficiência. Se você estiver executando seu pipeline na nuvem, adotar containers significa que você pode usar serviços gerenciados e transferir o lado da infraestrutura para o seu provedor de nuvem.

Ambientes de pré-produção

O número de ambientes de teste e preparação em sua arquitetura de pipeline dependerá do que você está criando e das necessidades dos diferentes grupos de partes interessadas na sua organização. Os exemplos incluem testes exploratórios, análises de segurança, pesquisa de usuário, demonstrações de vendas, ambientes de treinamento e sandboxes para que a equipe de suporte possa replicar os problemas do cliente.

Automatizar a criação e implantação nesses ambientes é mais eficiente do que atualizá-los manualmente, e você pode configurar diferentes gatilhos de pipeline para diferentes ambientes.

Por exemplo, embora seus ambientes de teste possam ser atualizados a cada build, você pode decidir atualizar os ambientes de teste com menos frequência, talvez apenas uma vez por dia ou uma vez por semana junto com o último build de sucesso.

Implante

Depois que suas alterações de código tiverem passado por cada um dos estágios anteriores do pipeline com sucesso, elas estarão prontas para serem liberadas para produção. Essa etapa final pode ser manual ou automática.

Liberar manualmente (conhecido como entrega contínua) é útil se você deseja controlar quando novos recursos ou funcionalidades são disponibilizados, se seu processo de implantação envolve tempo de inatividade para seus usuários ou se seu produto está instalado e você deseja agrupar as alterações e entregar de acordo com um cronograma de lançamento regular.

Com um processo de implantação contínua totalmente automatizado, as mudanças são implantadas em produção desde que tenham passado por todos os estágios anteriores.

Dependendo do número de desenvolvedores que trabalham na base de código e da frequência das suas submissões, isso pode significar que você está implantando atualizações para os usuários dezenas de vezes por dia; uma façanha praticamente impossível sem um pipeline automatizado.

Noções básicas sobre pipelines de CI/CD: para resumir

A CI/CD torna o desenvolvimento de software mais eficiente, chamando a atenção para os problemas o mais cedo possível; ajuda você a falhar rapidamente ao provocar interações mais cedo e receber feedback mais cedo (também conhecido como desvio para a esquerda). Construir um pipeline automatizado ajuda a colocar essas técnicas em prática.

Quando se trata de projetar seu próprio processo de CI/CD, é útil construí-lo em etapas, começando com a integração contínua. Os estágios exatos do pipeline e a lógica que determina quando cada estágio é disparado dependem do seu produto e da sua organização.

A escolha de uma plataforma de CI/CD que lhe proporcione a flexibilidade para configurar seu pipeline de acordo com seus requisitos e, ao mesmo tempo, seja fácil de gerenciar, vai lhe ajudar a criar um processo de lançamento confiável e a melhorar a qualidade de seu software.