Índice do diárioDockup / nota de campo
Note / build-fails-with-no-logs

Build com falha e sem logs: como obter a saída

Quando um build falha sem logs, isso significa que a falha aconteceu antes de o seu build começar. Saiba quais são os quatro estágios em que isso pode ocorrer, como diferenciá-los e como obter a saída de cada um.

"Build failed." Nenhum stack trace, nenhum erro do compilador, nenhuma saída. Um build que falhou sem logs é a mensagem menos útil que uma plataforma pode produzir, e geralmente indica algo específico que vale a pena entender: a falha aconteceu antes de o processo que gera os logs ser iniciado.

Um build não é uma única etapa. São quatro, e cada uma falha de uma forma diferente.

Os quatro estágios

1. Buscando o código-fonte. A plataforma clona o repositório em uma ref. 2. Preparando o build. Ela determina como fazer o build — Dockerfile, buildpack ou framework detectado. 3. Executando o build. Os seus comandos são executados. Este é o único estágio que produz a saída que você espera. 4. Empacotando. O resultado é transformado em uma imagem executável.

Se você não tem log algum, a falha ocorreu no estágio 1 ou 2. O seu build nunca foi executado, portanto não poderia ter exibido nada.

Estágio 1: o seu código nunca foi obtido

Os sintomas são silêncio total e uma falha rápida — geralmente em menos de quinze segundos.

Causas comuns, em ordem:

  • A branch não existe. Um serviço configurado para fazer deploy de master em um repositório que foi renomeado para main. Isso falha instantaneamente e informa quase nada.
  • O acesso foi revogado. O token ou a instalação do app que funcionava no mês passado foi removido, ou o repositório foi movido para uma organização onde a permissão não se aplica mais.
  • O repositório é privado e a conexão expirou. O comportamento é o mesmo descrito acima; a plataforma recebe um 404 em vez de um 403, porque é isso que os provedores de Git retornam para repositórios privados que você não pode visualizar.
  • Não foi possível obter um submodule. O repositório principal é clonado, mas um submodule que usa uma URL SSH falha porque o ambiente de build não tem uma chave para acessá-lo.

A verificação rápida: a plataforma exibe um hash de commit para o deploy que falhou? Se não exibe, o código nunca foi obtido, e nada no seu Dockerfile é relevante.

Estágio 2: a plataforma não sabe como fazer o build

Também é silencioso, porque nenhum comando de build foi escolhido ainda.

  • Não há um Dockerfile no local indicado pela configuração. Um dockerfilePath aponta para um caminho que foi alterado.
  • Um monorepo sem raiz configurada. A plataforma está analisando a raiz do repositório, mas o seu serviço está em apps/api.
  • A detecção não encontrou nada. Não há nenhum manifest reconhecido, então nenhum buildpack foi associado.
  • Um Dockerfile que não pode ser analisado. Um erro de sintaxe na linha 1 causa uma falha antes que qualquer layer seja executada.

Estágio 3: é aqui que os logs existem

Se você está vendo uma saída parcial que é interrompida abruptamente, está no estágio 3, e as duas causas mais comuns estão relacionadas a recursos, não ao código:

Falta de memória. Um build encerrado pelo OOM reaper não consegue exibir nenhuma informação sobre o ocorrido. O log simplesmente para no meio da etapa. Builds de TypeScript, webpack e Vite em codebases grandes atingem esse limite com frequência, e o indício é que o mesmo commit funciona no seu laptop, que tem mais memória do que o builder.

Timeout. Um build que ultrapassa o limite da plataforma é encerrado. O sintoma é o mesmo: a saída para, em vez de ser concluída.

Ambos parecem "sem logs" se a falha acontecer cedo o suficiente.

Estágio 4: o build foi concluído, mas não pode ser empacotado

É raro e específico: o build foi concluído com sucesso, mas o artefato está incorreto. Pode ser uma imagem sem CMD ou ENTRYPOINT, uma incompatibilidade de arquitetura ou uma imagem grande demais para o limite da plataforma.

A ordem do diagnóstico

# Is there a commit hash? If not, stage 1.
dockup deployments my-project/my-api --json

# Build logs of the latest deployment, streamed as it goes
dockup logs my-project/my-api --build --follow

# The full record, including which stage took how long
dockup status my-project/my-api --json

stageTimings nessa última saída é a forma mais rápida de localizar a falha. Um deploy que levou 0,4 segundo no clone e terminou com falha no estágio 1. Um que passou noventa segundos fazendo build e depois parou é um problema do estágio 3, provavelmente relacionado à memória.

Obtendo saída quando não há nenhuma

Três técnicas, em ordem crescente de esforço:

Reproduza a restrição localmente. Não é uma questão de "funciona na minha máquina" — faça o build com a mesma quantidade de memória disponível no builder:

docker build --memory=2g --memory-swap=2g -t test .

Se isso reproduzir a falha, você a encontrou: é um problema de memória, não algo misterioso.

Torne o seu build mais detalhado. A maioria das ferramentas de build é silenciosa por padrão sobre aquilo que está prestes a encerrá-las.

# Print progress so a truncated log still shows where it stopped
RUN npm ci --loglevel verbose
RUN NODE_OPTIONS="--max-old-space-size=3072" npm run build

Vale a pena tentar essa linha com NODE_OPTIONS sozinha — um build do Node que morre silenciosamente geralmente está esbarrando no limite do heap, e aumentá-lo corrige builds que não produziram nenhum diagnóstico.

Faça um bisect do Dockerfile. Comente tudo depois da etapa que falha e adicione marcadores RUN echo "reached step N". É uma abordagem rudimentar, mas funciona quando nada mais funciona.

O que reduz esse tipo de problema

Duas coisas importam mais do que qualquer técnica de debugging.

Logs em streaming, em vez de logs resumidos. Se a saída só aparece depois que o build termina, um build encerrado não produz nada, porque o resumo é gravado no final. O streaming garante que o log disponível quando o processo morre contenha tudo até o momento da falha.

dockup logs my-project/my-api --build --follow

Estágios nomeados e cronometrados. "Build failed" é uma única informação. "Clone: 0.4s, build: failed after 94s" é suficiente para descartar três das quatro causas acima sem ler mais nada.

Perguntas frequentes

Por que o meu build não produz log algum? Porque ele falhou antes que os seus comandos de build fossem executados — geralmente ao buscar o código-fonte ou determinar como fazer o build. Nenhum desses estágios produz a saída do build.

Por que o build funciona localmente, mas não na plataforma? Na maioria das vezes, por causa da memória. A sua máquina tem mais memória do que o builder. Reproduza com docker build --memory=2g para confirmar antes de investigar qualquer outra coisa.

O que significa um log que para no meio de uma etapa? O processo foi encerrado em vez de terminar normalmente. Falta de memória ou timeout do build são as duas possibilidades, e o OOM killer não dá ao processo a chance de explicar o que aconteceu.

Preciso de um Dockerfile? Não necessariamente — as plataformas podem detectar tipos comuns de projeto e fazer o build sem um. Mas uma falha na detecção também é uma falha silenciosa e sem logs, portanto um Dockerfile explícito elimina toda uma categoria de ambiguidades.