Introdução
A Integração Contínua detecta bugs no momento do merge, não em produção. O custo de um teste falhando no CI é alguns minutos da atenção de um desenvolvedor. O custo do mesmo bug em produção é muito maior. O GitLab CI é integrado ao GitLab, não requer nenhum serviço separado para funcionar e é configurado inteiramente por meio de um arquivo YAML no seu repositório.
O que é Integração Contínua?
Integração Contínua é a prática de mesclar alterações de código em uma branch compartilhada com frequência, com builds e testes automatizados executados a cada merge. O objetivo é detectar problemas de integração cedo, quando são baratos de corrigir, em vez de durante um ciclo de release quando múltiplas mudanças já se acumularam.
Os benefícios práticos: os bugs são detectados próximos ao momento em que são introduzidos, portanto o contexto ainda está fresco; falhas nos testes bloqueiam merges antes que código ruim chegue à branch principal; e as equipes ganham confiança de que a branch principal está sempre em um estado deployável.
GitLab CI
O GitLab CI é o serviço de CI/CD integrado ao GitLab. Ele lê um arquivo .gitlab-ci.yml na raiz do seu repositório e executa os jobs definidos ali a cada push. Você não precisa de um servidor Jenkins separado nem de um serviço de CI externo.
Razões para usá-lo: a configuração do pipeline fica junto ao seu código e evolui com ele, os runners compartilhados do GitLab cuidam do processamento para a maioria dos projetos, e o status do pipeline é visível diretamente nas merge requests.
Configurando o GitLab CI para um Projeto Node.js
Pré-requisitos
- Uma conta no GitLab.
- Um projeto Node.js em um repositório GitLab.
- Familiaridade básica com YAML.
Passo 1: Criar um Arquivo .gitlab-ci.yml
Na raiz do seu projeto, crie .gitlab-ci.yml:
image: node:14
stages:
- test
test_job:
stage: test
script:
- npm install
- npm test
A chave image especifica a imagem Docker em que o job é executado. A chave stages define os estágios do pipeline e sua ordem. Cada job especifica a qual estágio pertence e quais comandos executar.
Passo 2: Configurar o GitLab Runner (Opcional)
Os runners compartilhados do GitLab atendem a maioria dos projetos sem nenhuma configuração adicional. Se você precisar que os jobs sejam executados em sua própria infraestrutura, pode instalar e registrar um GitLab Runner auto-hospedado. Para a maioria dos projetos Node.js, os runners compartilhados são suficientes.
Passo 3: Commit e Push
git add .gitlab-ci.yml
git commit -m "Add GitLab CI configuration"
git push origin main
O GitLab detecta o arquivo e inicia o pipeline imediatamente.
Passo 4: Monitorar o Pipeline
Navegue até CI/CD > Pipelines no seu projeto GitLab. Você pode visualizar logs de jobs, baixar artefatos e ver o status do pipeline. Jobs com falha mostram o comando exato que falhou e sua saída.
Configuração Avançada
Cache de Dependências
Fazer cache do node_modules evita reinstalar pacotes a cada execução do pipeline:
cache:
paths:
- node_modules/
test_job:
stage: test
script:
- npm install
- npm test
Múltiplos Ambientes
Faça deploy para staging automaticamente a cada merge para a main:
stages:
- test
- deploy
deploy_staging:
stage: deploy
script:
- npm run build
- scp -r ./build user@staging-server:/var/www/app
only:
- main
Testes em Paralelo
Divida uma suite de testes lenta entre múltiplos runners:
test_job:
stage: test
script:
- npm install
- npm test
parallel: 4
Variáveis de Ambiente
Armazene segredos nas configurações do projeto GitLab em Settings > CI/CD > Variables e referencie-os no seu pipeline:
script:
- npm run deploy -- --api-key=$API_KEY
Nunca coloque segredos diretamente no .gitlab-ci.yml. Eles ficariam visíveis no histórico do repositório e para qualquer pessoa com acesso de leitura.
Boas Práticas para GitLab CI com Node.js
Fixe a versão do Node.js para evitar divergências de ambiente entre execuções do pipeline e o desenvolvimento local:
image: node:14.17.0
Adicione um passo de lint para que problemas de formatação e análise estática falhem o pipeline antes da execução dos testes:
script:
- npm run lint
- npm test
Restrinja jobs custosos às branches relevantes. Executar a suite de testes completa em cada commit de feature branch geralmente não é necessário:
only:
- merge_requests
- main
Declare artefatos de build para que possam ser baixados pela UI do pipeline ou passados entre estágios:
artifacts:
paths:
- build/
Resolução de Problemas Comuns
Se o pipeline falhar na instalação de dependências, verifique se todos os pacotes estão declarados no package.json e se não há conflitos de versão. O log do job mostra o erro exato.
Para erros de permissão ao executar scripts, adicione um passo de chmod:
script:
- chmod +x ./deploy.sh
- ./deploy.sh
Para variáveis de ambiente ausentes, verifique se estão definidas nas configurações de variáveis de CI/CD do GitLab e se o nome da variável no YAML corresponde exatamente.
Integrando Docker
Para deploys em containers, use Docker-in-Docker para construir e enviar imagens no CI:
image: docker:stable
services:
- docker:dind
variables:
DOCKER_DRIVER: overlay2
build_docker_image:
stage: build
script:
- docker build -t my-node-app .
- docker push my-node-app
only:
- main
O serviço docker:dind executa um daemon Docker dentro do container do pipeline, ao qual o script de build se conecta.
Conclusão
Um pipeline GitLab CI para um projeto Node.js leva menos de uma hora para configurar e melhora imediatamente o ciclo de feedback a cada merge. Falhas de lint e falhas de teste aparecem em minutos, em vez de durante a revisão de código ou após o deploy. Com o básico funcionando, adicione cache para acelerar as execuções, restrinja jobs às branches onde eles agregam valor e expanda o pipeline com estágios de deploy conforme o projeto amadurece.
Recursos Adicionais
Glossário
- Integração Contínua (CI): Uma prática em que os desenvolvedores integram alterações de código com frequência, com builds e testes automatizados.
- GitLab Runner: A aplicação que executa os jobs de CI definidos no
.gitlab-ci.yml. - Pipeline: Uma coleção de estágios e jobs executados em uma ordem definida a cada push.