Como otimizar pipelines e governança com GitLab CI/CD em ambientes DevOps corporativos

Práticas de GitLab CI/CD para times DevOps B2B: runners, rules, SAST/DAST, ambientes protegidos e observabilidade para entregar mais rápido com governança.

O GitLab CI/CD é o componente central para entrega contínua em organizações que buscam automação e conformidade. Neste artigo, apresento práticas aplicáveis a times DevOps B2B para estruturar Pipelines resilientes, reduzir tempo de feedback e garantir governança sem comprometer velocidade. O fio condutor é simples: cada decisão de configuração precisa equilibrar três eixos — tempo de feedback, custo computacional e rastreabilidade. Quando um desses eixos é otimizado às cegas, os outros dois degradam. O trabalho de plataforma é manter os três sob controle simultaneamente.

Arquitetura, Runners e configuração de Pipelines no GitLab CI/CD

Projetar Pipelines eficientes começa por entender a arquitetura do GitLab CI/CD: Runners (compartilhados ou dedicados), Stages, Jobs e artefatos. Adote Runners etiquetados por capacidade (GPU, alta memória, docker-in-docker) e separe Jobs críticos em filas distintas para evitar contenção de recursos.

Utilize cache e artifacts com políticas claras de expiração para equilibrar velocidade e consumo de armazenamento. Defina a chave expire_in em cada Job que gere artefatos e revise periodicamente o consumo de storage do Project.

Implemente Pipelines de múltiplos fluxos — merge-request Pipelines, branch Pipelines e schedules — e favoreça testes incrementais: testes unitários em cada commit, testes de integração por MR e testes end-to-end em execuções nightly.

Runners compartilhados vs. dedicados: o trade-off

A escolha entre Runners compartilhados e dedicados não é dogmática; depende do perfil de carga e dos requisitos de isolamento. A tabela abaixo resume os critérios que costumo aplicar ao decidir.

Critério Runners compartilhados Runners dedicados
Custo de manutenção Baixo (gerenciado) Alto (você opera a frota)
Isolamento Menor Maior (tags e tenants)
Hardware especializado Limitado Sob medida (GPU, memória)
Filas previsíveis Sujeito a contenção Capacidade reservada
Compliance / dados sensíveis Restrito Adequado

Na prática, o desenho mais comum em ambientes corporativos é híbrido: Runners compartilhados para Jobs genéricos (lint, testes unitários) e Runners dedicados, etiquetados por tags, para Jobs que exigem hardware específico ou acesso a redes restritas. O direcionamento se faz no próprio Job:

build_gpu:
  stage: build
  tags:
    - gpu
    - alta-memoria
  script:
    - ./scripts/build-modelo.sh

Cache e artefatos: políticas que cabem no orçamento

Cache e artefatos resolvem problemas diferentes e são frequentemente confundidos. cache acelera execuções futuras reaproveitando dependências; artifacts transporta saídas entre Stages e as disponibiliza para download e relatórios. Use chaves de cache baseadas no arquivo de lock de dependências para invalidar o cache apenas quando ele realmente muda:

test:
  stage: test
  cache:
    key:
      files:
        - package-lock.json
    paths:
      - node_modules/
    policy: pull-push
  artifacts:
    paths:
      - coverage/
    expire_in: 1 week
    reports:
      junit: junit.xml
  script:
    - npm ci
    - npm test

Em Jobs que apenas consomem o cache (por exemplo, paralelos a um Job que já o populou), defina policy: pull para evitar reescritas desnecessárias e reduzir o tempo de upload.

Controle de execução: sintaxe legada vs. atual

Para executar apenas os Jobs necessários e reduzir custos computacionais, o GitLab oferece dois mecanismos de controle de execução:

Legado / Em desuso: as keywords only e except permitem filtrar Jobs por branch, tag ou evento. Embora ainda funcionem, o GitLab não recomenda seu uso em novos projetos.

# Exemplo legado (only/except) - NÃO recomendado para novos projetos
test_job:
  script: echo "Executando testes"
  only:
    - main
    - merge_requests

Atual / Recomendado: a keyword rules substitui only/except com maior flexibilidade. Com rules, é possível combinar condições lógicas, definir variáveis dinâmicas e controlar o comportamento do Job com when e allow_failure em cada regra individualmente.

# Exemplo atual (rules) - RECOMENDADO
test_job:
  script: echo "Executando testes"
  rules:
    - if: '$CI_PIPELINE_SOURCE == "merge_request_event"'
      when: always
    - if: '$CI_COMMIT_BRANCH == "main"'
      when: always
    - when: never

A principal vantagem de rules é a composição de condições: você pode avaliar variáveis de ambiente, caminhos alterados (changes) e origem do Pipeline em uma única estrutura declarativa, eliminando comportamentos ambíguos que ocorriam com only/except.

Por que rules substitui only/except

Vale entender o que se ganha na migração, porque a diferença vai além de sintaxe:

Aspecto only/except rules
Lógica condicional Implícita, difícil de auditar Explícita, avaliada de cima para baixo
Controle por regra Não when e allow_failure por regra
Variáveis dinâmicas Não Sim, via variables na regra
Filtragem por arquivos Limitada changes combinável com if
Recomendação oficial Em desuso Recomendada

Um detalhe operacional importante: as rules são avaliadas na ordem em que aparecem e a primeira correspondência vence. Por isso, a última regra costuma ser - when: never, funcionando como negação explícita para tudo que não casou com as condições anteriores. Sem essa cláusula final, o comportamento padrão pode incluir o Job em situações não previstas.

Segurança e compliance integrados ao Pipeline

Incorpore scanners SAST, DAST e análise de dependências diretamente no Pipeline. Use variáveis protegidas e ferramentas de gerenciamento de segredos (secrets managers), e limite a exposição de credenciais a Jobs executados em Runners confiáveis.

Configure MRs para exigir aprovação de segurança antes do merge e habilite os relatórios de vulnerabilidade nativos do GitLab. Essas práticas transformam o Pipeline em uma camada ativa de governança técnica.

Habilitando os scanners via templates

O GitLab distribui templates de segurança prontos que você inclui no Pipeline com poucas linhas. A abordagem include mantém a lógica de scanning centralizada e atualizável:

include:
  - template: Jobs/SAST.gitlab-ci.yml
  - template: Jobs/Dependency-Scanning.gitlab-ci.yml
  - template: Jobs/Secret-Detection.gitlab-ci.yml

stages:
  - test
  - security

Os relatórios gerados aparecem na visão de Security do MR, permitindo que o revisor avalie a vulnerabilidade no contexto exato da mudança — em vez de descobri-la semanas depois em uma varredura agendada.

Higiene de segredos no Pipeline

Nunca grave credenciais no .gitlab-ci.yml nem em variables em texto puro. As recomendações práticas:

  • Marque variáveis sensíveis como Protected e Masked em Settings > CI/CD > Variables, para que só fiquem disponíveis em branches/tags protegidas e não vazem nos logs.
  • Para credenciais de curta duração, prefira integração com um secrets manager externo, recuperando o segredo em tempo de execução do Job.
  • Restrinja Jobs que tocam segredos de produção a Runners dedicados e confiáveis, evitando que rodem em Runners compartilhados.

Observabilidade e otimização

Monitore duração de Jobs, taxa de sucesso de Pipelines e principais gargalos utilizando métricas do próprio GitLab e ferramentas externas de observabilidade. Defina SLIs e SLAs para Pipelines críticos e automatize alertas para regressões de performance.

A revisão periódica de tempos por Stage e a implementação de cache granular — com chaves baseadas em arquivos de dependência, por exemplo — frequentemente reduzem o tempo médio de entrega de forma significativa.

Antes de otimizar, meça. Os indicadores que valem acompanhar de perto:

  • Duração por Stage e por Job — identifica onde o tempo é gasto e qual Stage é o gargalo real.
  • Taxa de falha por Job — expõe Jobs instáveis (flaky), que minam a confiança no sinal verde.
  • Fila vs. execução — separar tempo de espera por Runner do tempo de processamento mostra se o problema é capacidade ou código.
  • Frequência de cache hit — um cache que quase nunca acerta está custando upload sem entregar ganho.

Uma armadilha comum é otimizar a duração agregada do Pipeline ignorando a distribuição. Dois Jobs com a mesma média podem ter caudas completamente diferentes; é a cauda (os piores casos) que trava merges e gera reclamação. Correlacione picos com mudanças recentes nas Pipelines antes de remediar.

Estratégias para monorepos e microservices

Em monorepos, adote estratégias de filtragem por caminhos (changesets) para acionar apenas os Jobs relevantes. Utilize a keyword changes dentro de rules para restringir a execução com base nos arquivos alterados no commit.

test_servico_a:
  stage: test
  rules:
    - if: '$CI_PIPELINE_SOURCE == "merge_request_event"'
      changes:
        - servicos/servico-a/**/*
  script:
    - ./scripts/test.sh servico-a

Para microservices, padronize templates de Pipeline reutilizáveis e mantenha bibliotecas de CI compartilhadas. O GitLab CI/CD suporta include com referências remotas, permitindo centralizar lógica comum e reduzir duplicação entre Projects.

include:
  - project: 'plataforma/ci-templates'
    ref: main
    file: '/templates/build-padrao.yml'

Centralizar a lógica em um Project de templates traz um benefício de governança que vai além da redução de duplicação: uma mudança de política (por exemplo, exigir um novo scanner) é aplicada a todos os Projects que consomem o template, em vez de depender de dezenas de merge requests manuais. O custo é o acoplamento — versione os templates com ref fixo em Projects sensíveis para evitar que uma alteração no template quebre Pipelines em produção sem aviso.

Automação de releases e compliance

Automatize versionamento com semver, geração de artefatos e criação de tags a partir de Pipelines controlados. Implemente gates manuais para produção — utilizando when: manual — apenas quando controles de qualidade e segurança estiverem verificados.

deploy_prod:
  stage: deploy
  environment:
    name: production
  rules:
    - if: '$CI_COMMIT_TAG'
      when: manual
  script:
    - ./scripts/deploy.sh production

Use ambientes protegidos (Settings > CI/CD > Protected environments) e políticas de deploy para impor aprovadores e trilhas de auditoria.

Checklist de governança do Pipeline

Uma lista objetiva para auditar maturidade de governança em Pipelines corporativos:

  • rules no lugar de only/except em todos os Jobs novos, com - when: never como cláusula final.
  • Scanners SAST, DAST e de dependências habilitados e com relatórios visíveis no MR.
  • Variáveis sensíveis marcadas como Protected e Masked.
  • Ambientes de produção configurados como Protected environments com aprovadores definidos.
  • Gates manuais (when: manual) nos deploys de produção.
  • expire_in definido em todos os Jobs que geram artefatos.
  • Templates de CI centralizados em Project versionado, consumidos via include.
  • SLIs e SLAs definidos para Pipelines críticos, com alertas de regressão.

Para referência técnica detalhada sobre sintaxe e recursos, consulte a documentação oficial do GitLab CI/CD.

Integrações com ferramentas de observabilidade, sistemas de artefatos (como registries de containers) e plataformas de gerenciamento de segredos aumentam a maturidade do Pipeline. Documente dependências e políticas em Projects específicos de CI para facilitar auditorias e transferência de conhecimento entre equipes.

Otimização é um processo contínuo. Realize revisões trimestrais dos Pipelines, mantenha Runners atualizados e padronize templates. Essas práticas trarão previsibilidade e eficiência ao ciclo de entrega com GitLab CI/CD em ambientes corporativos.

Quer estruturar (ou afinar) seus Pipelines GitLab CI/CD com governança de ponta a ponta? Vamos conversar.