Entrega · Containers
Pipeline verde, aplicação fora do ar
Build aprovado, testes aprovados, imagem publicada — e a nova revisão nunca ficava pronta. Uma divergência de porta entre um serviço NestJS e o Azure Container Apps, e o que ela me ensinou sobre o que um pipeline realmente prova.
Publicado em 3 min de leitura
Tudo no pipeline estava verde. O build passou, os testes passaram e a imagem do container foi publicada. Por qualquer sinal que o pipeline pudesse dar, a entrega estava concluída. Mas, no Azure Container Apps, a nova revisão do serviço NestJS nunca ficava pronta.
Não havia nada de errado no código. O problema estava no espaço entre a aplicação e a plataforma que a executa — um espaço que nenhuma etapa do pipeline observava.
O que “pronto” significa no Azure Container Apps
No Azure Container Apps, publicar uma nova imagem cria uma nova revisão da aplicação. Com o ingress habilitado, o tráfego vai para uma única porta de destino no container, e a plataforma verifica essa porta antes de considerar a revisão saudável. Se você não define seus próprios health probes, ela adiciona probes TCP padrão apontando para essa mesma porta.
Ou seja, “pronto” é um acordo em tempo de execução: o processo precisa estar ouvindo onde a plataforma espera. Se não estiver, a imagem pode estar perfeita e a revisão mesmo assim nunca fica pronta.
Seguindo as evidências
Quando um deploy falha, a tentação é desconfiar da mudança de código mais recente. O caminho mais rápido foi ler o que a própria plataforma estava dizendo: os logs do container e os eventos da revisão.
Juntos, eles contavam uma história clara. A aplicação tinha subido — o NestJS estava ouvindo na porta 3000. O ingress estava configurado para mandar tráfego para a porta 8080. A plataforma continuava verificando uma porta onde nada respondia, e por isso a revisão nunca ficava pronta. Duas configurações, cada uma razoável isoladamente, simplesmente discordavam.
Por que o pipeline não tinha como ver
Um pipeline responde às perguntas que você faz a ele. O código compila? Os testes passam? A imagem pode ser gerada e publicada? A resposta para tudo isso era sim.
Só que a porta não é uma propriedade só do código. É um contrato entre a aplicação e o ambiente que a executa, e ele é configurado em dois lugares: onde a aplicação decide em qual porta ouvir e onde a plataforma decide qual porta chamar. Nada no pipeline subia a imagem com as configurações da plataforma e pedia uma resposta na porta esperada — então a divergência ficou invisível até a plataforma tentar usá-la.
A correção, e a pergunta seguinte
Alinhei a configuração para que a aplicação e o ingress concordassem sobre a porta e, em seguida, validei que os health checks passavam e que os endpoints respondiam no ambiente publicado.
A correção em si foi pequena. A pergunta mais útil veio depois: se isso divergiu aqui, onde mais pode ter divergido? Revisei os outros ambientes em busca da mesma diferença, para que o próximo deploy não esbarrasse na mesma falha em outro lugar.
Proteções que valem a pena
Esse tipo de falha é barato de evitar. Algumas verificações fecham a distância entre “o build passou” e “o serviço está rodando”:
- Uma única fonte para a porta. Ouvir numa variável PORT em vez de um número fixo no código, definida junto com a porta de destino do ingress — uma decisão em vez de duas suposições.
- Health probes explícitos. Apontar os probes de inicialização e de prontidão para um endpoint de saúde de verdade, para que “pronto” signifique que a aplicação consegue atender requisições, e não só que existe uma porta aberta.
- Um smoke check depois de cada deploy. Chamar o endpoint de saúde pelo ingress real assim que a revisão subir, e reprovar a entrega se ele não responder.
- Configuração de ambiente como código. Manter portas, probes e configurações de ingress versionadas e revisadas, e compará-las entre ambientes em vez de corrigir cada um à mão.
// main.ts
const app = await NestFactory.create(AppModule);
// A plataforma decide a porta; a aplicação acompanha.
const port = Number(process.env.PORT ?? 3000);
await app.listen(port, "0.0.0.0");O que ficou
Um pipeline verde é evidência sobre o artefato: o código compila, os testes passam, a imagem existe. Ele não diz nada sobre a saúde do serviço onde ele roda. Um deploy termina quando o serviço em execução responde — não quando o último job fica verde.
AprendizadoUm pipeline bem-sucedido prova o build, não o serviço rodando.