Como reduzir tempo de build e evitar artefatos duplicados em CI para monólitos PHP grandes

Por · Publicado em · 6 min de leitura

Painel com terminais elétricos e cabos coloridos conectados em trilhos
Visual técnico que remete à infraestrutura e pipelines de CI Foto: Taken / Pixabay

Seu pipeline está lento? Veja como reduzir tempo de build e evitar artefatos duplicados em CI para monólitos PHP grandes. O caminho passa por cache eficiente do Composer, camadas Docker determinísticas e um artefato único para alimentar testes e deploy. Abaixo, um plano prático para diagnosticar gargalos e aplicar melhorias sem refazer tudo do zero.

Sintomas e causas comuns em builds de monólitos PHP

Monólitos PHP grandes sofrem com tempo de checkout, instalação de dependências e reconstrução repetida de artefatos. Em muitos pipelines, cada job recompila tudo, gerando artefatos idênticos várias vezes e desperdiçando cache.

Mapeie rapidamente o que mais consome tempo. Quase sempre é Composer, build de assets e download de camadas Docker. Corrigindo esses pontos, o ganho costuma ser imediato.

  • Instalações repetidas do Composer em jobs paralelos.
  • Cache inexistente ou inválido a cada commit.
  • Dockerfile que invalida camadas cedo demais.
  • Artefato produzido em mais de um job da pipeline.
  • Falta de concorrência controlada e cancelamento de builds antigos.
Sintoma Causa provável Medida prática
composer install demora em todo job cache do Composer não persistido ou chaveada errado persistir $COMPOSER_CACHE_DIR por chave do composer.lock
Docker rebuilda tudo a cada commit ordem de COPY inválida; sem BuildKit cache remoto reordenar Dockerfile e ativar cache-from/cache-to
artefatos em duplicidade “build” acontece em múltiplos stages criar artefato único e fazer fan-out
checkout pesado repositório gigante; histórico completo shallow/partial clone e limpeza de blobs de mídia

Diagnóstico orientado a dados do pipeline

Antes de mudar, meça. Anote durações por etapa e identifique o que varia entre commits. Foque nos 2 ou 3 maiores blocos de tempo e no que é repetido sem necessidade.

Verifique também I/O do runner. Discos lentos e armazenamento de cache em rede de alta latência sabotam pipelines mesmo bem configuradas.

  • Habilite logs detalhados do Composer para ver cache hits/misses.
  • Revise o tempo de “checkout” e habilite shallow clone.
  • Separe o tempo de build de imagens do tempo de testes.
  • Meça cache hit rate por chave (commit, composer.lock).

Composer rápido e determinístico (sem retrabalho)

O maior ganho vem de tratar dependências de forma determinística e cacheável. Use sempre o composer.lock e flags não interativas. Evite reinstalar vendor/ em vários jobs: produza-o uma vez e reutilize.

Persista o diretório de cache do Composer entre jobs. Chaveie o cache pelo hash do composer.lock para invalidar apenas quando dependências mudarem.

  • Use --prefer-dist, --no-interaction e autoloader otimizado.
  • Cacheie $COMPOSER_CACHE_DIR, não o vendor/ cru entre branches.
  • Gere o vendor/ uma única vez e empacote no artefato final.
  • Tokens de acesso para repositórios privados devem ficar em secrets.

Se você usa containers: BuildKit, camadas e cache remoto

Com Docker, organize o Dockerfile para maximizar cache: copie composer.json e composer.lock antes do código. Instale dependências primeiro. Só depois copie o restante. Ative BuildKit e cache remoto para compartilhar camadas entre runners.

Para detalhes práticos de cache remoto e otimizações com BuildKit, veja o guia específico abaixo.

  • Multi-stage para separar build e runtime.
  • COPY em ordem: arquivos de dependência antes do código.
  • --mount=type=cache no Composer dentro do build.
  • cache-to/cache-from para reusar camadas entre builds.

Artefato único: build once, fan-out para testes e deploy

Evite artefatos duplicados produzindo um único pacote versionado por commit (ex.: zip/tar com código, vendor/ e assets). Jobs seguintes apenas consomem esse artefato. Isso reduz variação entre ambientes e elimina retrabalho.

Nomeie o artefato com o SHA do commit e opcionalmente um content hash para permitir deduplicação no armazenamento.

  • Gere o artefato após lint + unit mais rápidos.
  • Teste integração e e2e usando o mesmo artefato.
  • Deploy consome exatamente o artefato testado.
  • Defina tempo de retenção e política de limpeza.

Estratégia de pipeline: ordem, matrizes e concorrência

Estruture a pipeline em estágios claros: checkout leve, build do artefato, fan-out de testes, publicação e deploy. Use matrizes para paralelizar testes, nunca o build do artefato.

Controle concorrência: cancele runs obsoletos do mesmo branch e limite builds simultâneos que disputam caches. Assim, você evita filas longas e duplicação desnecessária.

  • Gate: só crie artefato se checagens rápidas passarem.
  • Matrix só para testes; build do artefato é único.
  • Convergir para uma etapa de publicação/deploy.
  • Definir regras de cancelamento de runs antigos.

Higiene de cache, retenção e segurança

Cache acelera, mas sem higiene vira entulho. Limpe caches ao remover branches. Renove chaves quando composer.lock muda. Monitore o hit rate e ajuste o particionamento.

Tenha atenção a secrets e provedores privados de pacotes. Armazene tokens de forma segura e restrita ao escopo da pipeline.

  • Defina TTLs diferentes para branches e main.
  • Evite compartilhar vendor/ entre branches distintos.
  • Rotacione tokens periodicamente e isole permissões.
  • Audite quem acessa artefatos e logs sensíveis.

Perguntas frequentes

Como evitar reinstalar o vendor/ em cada job do CI?

Gere o vendor/ uma única vez na etapa de build e empacote no artefato final. Os demais jobs consomem esse artefato. Para velocidade adicional, persista o cache do Composer chaveado pelo hash do composer.lock.

BuildKit ajuda mesmo em projetos PHP sem muito C/C++?

Sim. Mesmo sem compilações pesadas, camadas determinísticas e cache remoto reduzem downloads e reinstalações. A ordem de COPY correta e o reuso de camadas do Composer costumam render ganhos consideráveis.

Qual é a melhor chave para cache do Composer no CI?

Use uma chave derivada do hash do composer.lock e do sistema operacional/versão do PHP. Assim, o cache só é invalidado quando as dependências realmente mudam, evitando quebras por plataforma diferente.

Como eliminar artefatos duplicados em pipelines paralelas?

Centralize o build do artefato em um único job por commit e use esse pacote em fan-out. Nomeie com SHA do commit e, se possível, um content hash para deduplicação no storage. Cancele execuções antigas do mesmo branch.

Devo cachear o diretório vendor/ diretamente?

Prefira cachear o diretório de cache do Composer e produzir o vendor/ no artefato único. Cachear vendor/ entre branches pode introduzir inconsistências difíceis de diagnosticar e piorar a depuração.

Quer apoio para desenhar seu pipeline?

Se você precisa revisar o CI do seu monólito PHP e implementar artefato único, cache eficiente e BuildKit, podemos conversar sobre o seu contexto e prioridades.

Falar sobre otimização de CI

Veja também