DevOps não é para você! Parte 3: como implantar um processo no Azure DevOps.
A plataforma escolhida foi o Azure DevOps. Se você não tem familiaridade com ela ou fez uma escolha diferente, ainda sim poderá utilizar os conceitos. Não iremos cobrir um passo-a-passo, isso não é um tutorial, mas abordaremos o como, o porquê e quando, que poderão ser aplicados em outras plataformas.
O Microsoft Azure DevOps é um conjunto de serviços integrados que cobrem o planejamento (Board), controle de versão (Repos), construção, testes, entrega (Pipelines) e armazenamento de artefatos (Artifacts). Conta ainda com um marketplace com ofertas de extensões.
O Azure Pipelines é onde automatizaremos os processos, ele está integrado com os repositórios de código-fonte, incluindo GitHub e Bitbucket, além do Azure Repos Git e TFS.
Idealmente o repositório de código-fonte deve ficar próximo à ferramenta de pipeline. Isso reduz o tempo total da entrega, principalmente em projetos muito grandes ou repositórios únicos (mono-repo).
Agora é uma boa hora para verificar onde está o código-fonte e qual a estratégia de versionamento. Alguns projetos podem se beneficiar com uma estratégia simples de efetivar as mudanças diretamente na master ou trunk, outros irão preferir utilizar branches, como no modelo de desenvolvimento git-flow. Essa é uma longa e complexa discussão que divide opiniões, algumas bem apaixonadas, então recomendo discutir com a sua equipe caso a caso, porque envolve questões de maturidade, conhecimento da equipe, tamanho, volatilidade do projeto e, é claro, preferências pessoais.
Recomendo novamente o livro Entrega Contínua do Humble e Farley. Os capítulos “Gerência de Configuração” e “Controle de Versão Avançado” lhe darão clareza sobre a importância de prestar atenção a essa decisão.
Lembre-se que o que buscamos é entregar software de qualidade rapidamente, suas escolhas devem manter isso em mente. A minha será pelo trunk, ou seja, tão logo o código-fonte seja confirmado (commit) na master, o processo de entrega iniciará.
O pipeline é normalmente agnóstico a tecnologia, não importando se você está entregando um software em Python, Java ou Node.js, mas cada projeto de software inclui estágios únicos, como pré-processamentos, compilação, ligação (linkage), otimizações dependentes da plataforma, etc.
Não importa muito o que você vai entregar, o processo a ser automatizado é o mesmo que você realiza na máquina do desenvolvedor, a melhoria aqui é manter esse processo em um lugar comum e compartilhado com todos.
Honestamente, não importar com o que você entregará não é totalmente verdadeiro, mas leva a outra discussão – como controlar a versão do artefato criado? Isso está intimamente relacionado a arquitetura do software – como ele está dividido? Em módulos que podem ser entregues individualmente em um repositório como o Azure Artifacts? Ou é um monolítico, estático, entregue como uma única peça?
Seu processo pode entregar uma imagem ISO, Docker ou qualquer outra forma de empacotamento da aplicação e sistema operacional.
Essa é uma boa hora para revisitar a arquitetura da sua aplicação – como ela está dividida? A divisão beneficia o processo de entrega?
Para deixar minha escolha mais genérica e mais próxima do que uso no meu dia a dia, irei empacotar meu software na forma de uma imagem Docker, utilizar o Azure Container Registry para armazená-la e o sistema de tags das imagens para controlar a versão.
Bem, estamos a meio caminho, podemos começar a escrever o nosso processo:
- Iniciar o processo quando alguém fizer uma confirmação (commit) no repositório de código-fonte;
- Obter o código-fonte;
- Avaliar a qualidade do código-fonte (análises estáticas);
- Obter as dependências;
- Compilar;
- Executar testes unitário;
- Empacotar;
- Entregar no repositório de artefatos.
O passo um é o nosso gatilho, iremos configurá-lo para iniciar o processo. Outros possíveis gatilhos são: quando a efetivação for em um determinado branch, o nome de um branch/tag corresponder a uma expressão ou um novo pacote for incluído no Azure Artifacts.
Os demais passos são triviais, exceto a análise estática: essa é a primeira vez que tocamos no assunto qualidade antes dos testes. A tarefa mais comum é executar o SonarQube, mas outras tarefas podem ser incluídas como avaliações de segurança, por exemplo, SAST (Static Application Security Testing, Checkmarx).
Neste ponto você deve se perguntar — e se eu não souber todas as atividades do pipeline? Você pode utilizar um recurso disponível na maioria das plataformas de CI/CD, os grupos de tarefas (task groups). Por exemplo, você pode criar um grupo de tarefas de qualidade do código com uma tarefa dummy [“Script: echo Lembrar de colocar tarefas de segurança”] e adicionar o grupo ao pipeline. Depois é possível revisitar esse grupo e adicionar novas tarefas, assim, todos os pipelines, que utilizarem o grupo, executarão as tarefas da próxima vez que forem instanciados.
Isso leva a outra questão – quais tarefas deverão parar o processo de entrega do software? Algumas são óbvias, o processo é interrompido se não compilar ou não passar nos testes unitários. Mas e as análises de qualidade? O objetivo é um software de qualidade, então o recomendado é parar o processo caso os critérios mínimos não sejam alcançados ou uma vulnerabilidade crítica seja encontrada, mas isso é mais fácil na teoria do que na prática, principalmente se o código não é novo. Uma regra de ouro é executar o processo algumas vezes, aprender com as métricas coletadas e então definir, com a equipe, os critérios de parada.
Ferramentas como o SonarQube e Checkmarx permitem definir patamares. Você encontra na documentação do SonarQube um conceito interessante de parar o vazamento (Fixing the Water Leak), onde o objetivo primário é não acumular mais débitos técnicos ao invés de pagá-los, muito útil para grandes bases de código-fonte legado.
Na próxima parte iremos configurar um pipeline para entrega contínua de um software em um cluster Kubernetes, na Azure, e criar nossa primeira entrega.
A decisão de integrar todas as pessoas envolvidas na confecção do software exige muito esforço e atitude, mas sem automação, em pouco tempo, isso se perderá. DevOps não é para você executar manualmente, isso é um antipadrão, evitar ao máximo trabalho manual e automatizar tudo que for possível deve ser uma das suas metas.
Tenha em mente que precisamos entregar software de qualidade rapidamente, isso é o que esperam de nós, então não vamos complicar as coisas. Não sejamos ingênuos ou desleixados, fazer do jeito certo deve ser mais fácil do que qualquer outro jeito. Nossos processos precisam ser controlados e fornecer feedbacks rápidos para melhorá-los continuamente. Nosso software, não importando a sua finalidade, precisa ser confiável, seguro e entregue quando for necessário.
Vida longa e próspera!