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
masterem um repositório que foi renomeado paramain. 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
dockerfilePathaponta 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.
