Olá! Bem-vindo de volta.
Introdução
Na lição anterior, você aprendeu a desacoplar a configuração da sua aplicação usando variáveis de ambiente e arquivos .env. Isso nos permitiu criar serviços flexíveis. No entanto, em uma aplicação com múltiplos serviços, como uma API .NET e um banco de dados PostgreSQL, a ordem em que os serviços iniciam é crucial. Se a sua API iniciar e tentar se conectar ao banco de dados antes que ele esteja pronto para aceitar conexões, sua aplicação irá falhar.
Nesta lição, vamos resolver exatamente esse problema. Você aprenderá a controlar a ordem de inicialização e as dependências entre os serviços usando a propriedade depends_on no Docker Compose. Compreender isso é fundamental para construir aplicações multi-contêiner robustas e resilientes.
Ao final desta lição, você será capaz de orquestrar a inicialização dos seus serviços de forma que a sua API só inicie quando o banco de dados do qual ela depende estiver verdadeiramente pronto.
O Problema: Condições de Corrida na Inicialização
Quando você executa docker-compose up sem nenhuma diretiva de dependência, o Docker Compose inicia todos os serviços definidos no arquivo, mas não garante nenhuma ordem específica. Eles iniciam de forma mais ou menos simultânea.
Isso cria uma "condição de corrida" (race condition). Considere o seguinte cenário:
- Serviço
webapi: Uma API .NET que precisa de uma conexão com o banco de dados ao iniciar. - Serviço
db: Um contêiner PostgreSQL.
O contêiner do webapi pode iniciar e executar seu código de inicialização (por exemplo, em Program.cs) mais rápido do que o contêiner do db leva para inicializar o processo do PostgreSQL e começar a ouvir na porta 5432. O resultado? A API tenta se conectar, a conexão falha, e a aplicação provavelmente trava na inicialização.
A Solução Inicial: depends_on Básico
A primeira solução que o Docker Compose oferece é a propriedade depends_on. Na sua forma mais simples, ela diz ao Docker Compose para iniciar um contêiner antes de outro.

Vamos ver um exemplo com nossa API e o banco de dados:
version: '3.8'
services:
webapi:
image: my-dotnet-api
ports:
- "8080:80"
environment:
- ConnectionStrings__DefaultConnection=Host=db;... # string de conexão
depends_on:
- db # Diz ao Compose para iniciar 'db' antes de 'webapi'
db:
image: postgres:14
environment:
- POSTGRES_PASSWORD=mysecretpassword
Neste caso, depends_on: - db garante que o contêiner db será iniciado antes do contêiner webapi.
Docker Compose will BLOW your MIND!! (a tutorial)
Para ver uma demonstração prática do depends_on básico, assista a este segmento do vídeo do canal NetworkChuck. Ele mostra como usar a propriedade para garantir que um banco de dados MySQL seja criado antes de um site WordPress que depende dele.
Assista do timestamp 10:46 a 12:53. Preste atenção em como a seção depends_on é adicionada ao serviço WordPress para criar uma dependência no serviço mysql.
A Limitação Crucial do depends_on Básico
Embora o depends_on básico garanta a ordem de inicialização dos contêineres, ele não espera que a aplicação dentro do contêiner esteja pronta. Ele apenas espera o contêiner estar no estado "running". Para um banco de dados, o contêiner pode estar "running", mas o processo do PostgreSQL ainda pode estar realizando a inicialização, que pode levar vários segundos. A condição de corrida ainda existe, embora a janela de tempo seja menor.
How to Use Docker Compose depends_on with Health Checks
Para entender completamente essa limitação, leia a introdução deste artigo do blog OneUptime. Ele articula claramente por que o depends_on básico é insuficiente para dependências de serviço reais.
Leia a seção introdutória e a subseção "The Problem with Basic depends_on". O artigo explica de forma sucinta por que esperar que um contêiner inicie não é o mesmo que esperar que o serviço dentro dele esteja saudável e pronto.
A Solução Robusta: depends_on com Condições e Health Checks
Para resolver de vez o problema, as versões mais recentes do Docker Compose expandiram o depends_on para aceitar condições que estão ligadas a health checks (verificações de saúde).
Um healthcheck é um comando que o Docker executa periodicamente dentro de um contêiner para verificar se a aplicação está funcionando corretamente.

A sintaxe longa e moderna se parece com isso:
version: '3.8'
services:
webapi:
image: my-dotnet-api
depends_on:
db: # Nome do serviço dependente
condition: service_healthy # A condição a ser esperada
db:
image: postgres:14
environment:
- POSTGRES_USER=myuser
- POSTGRES_PASSWORD=mysecretpassword
healthcheck:
# Comando para verificar se o Postgres está pronto para aceitar conexões
test: ["CMD-SHELL", "pg_isready -U myuser"]
interval: 5s
timeout: 5s
retries: 5
Agora, o serviço webapi só iniciará quando o comando do healthcheck do serviço db (pg_isready) retornar sucesso, indicando que o banco de dados está verdadeiramente pronto.
Existem três condições principais que você pode usar:
| Condição | Comportamento |
|---|---|
service_started |
Espera que o contêiner da dependência seja iniciado. (Comportamento padrão/antigo) |
service_healthy |
Espera que a dependência seja iniciada e passe no seu healthcheck. |
service_completed_successfully |
Espera que a dependência seja executada até o fim e saia com o código 0 (sucesso). |
Use Case: Migrações de Banco de Dados com service_completed_successfully
A condição service_completed_successfully é extremamente útil para tarefas pontuais que devem ser concluídas antes que a aplicação principal inicie. O exemplo mais comum para um desenvolvedor é a execução de migrações de banco de dados (por exemplo, com Entity Framework).
Veja como seria a orquestração:
- O serviço de banco de dados (
db) inicia. - O serviço de migração (
db-migrator) espera odbficar saudável (service_healthy). - O
db-migratorexecuta as migrações (ex:dotnet ef database update) e então termina com sucesso. - A aplicação principal (
webapi) espera odb-migratorterminar com sucesso (service_completed_successfully) antes de iniciar.
services:
webapi:
image: my-dotnet-api
depends_on:
db-migrator:
condition: service_completed_successfully
db-migrator:
image: my-dotnet-api # Usa a mesma imagem da API
command: ["dotnet", "ef", "database", "update"] # Sobrescreve o comando para rodar a migração
depends_on:
db:
condition: service_healthy
db:
image: postgres:14
healthcheck:
test: ["CMD-SHELL", "pg_isready -U myuser"]
# ... resto da configuração
How to Use Docker Compose depends_on with Health Checks
Para aprofundar seu conhecimento sobre as condições do depends_on e ver mais exemplos práticos, incluindo health checks para serviços comuns como Redis e PostgreSQL, consulte este artigo novamente.
Leia as seções "depends_on with Conditions" e "Common Service Health Checks". Preste atenção nos diferentes exemplos de condições e nos comandos de health check prontos para serviços como PostgreSQL e Redis. Isso lhe dará uma base sólida para a próxima lição, onde você implementará seus próprios health checks.
Teste seu entendimento!
Você tem a seguinte aplicação docker-compose.yml com três serviços:
api: a API principal.cache: um serviço de cache Redis.init-script: um script que precisa rodar uma única vez para popular alguns dados iniciais no cache.
O init-script deve ser executado somente depois que o cache (Redis) estiver pronto. A api só deve iniciar depois que o init-script for concluído com sucesso.
Como você configuraria as seções depends_on para os serviços api e init-script para garantir essa ordem de inicialização? Assuma que o serviço cache já tem um healthcheck definido.
version: '3.8'
services:
api:
image: my-api
# ...
# TODO: Adicionar a seção depends_on para a API
# ...
init-script:
image: my-init-script
# ...
# TODO: Adicionar a seção depends_on para o script de inicialização
# ...
cache:
image: redis:alpine
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 1s
timeout: 3s
retries: 30
Show answer
A configuração correta seria:
version: '3.8'
services:
api:
image: my-api
depends_on:
init-script:
condition: service_completed_successfully
init-script:
image: my-init-script
depends_on:
cache:
condition: service_healthy
cache:
image: redis:alpine
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 1s
timeout: 3s
retries: 30
Explicação:
- O
init-scriptdepende que o serviçocacheesteja saudável (service_healthy), garantindo que o Redis esteja pronto para aceitar comandos. - A
apidepende que oinit-scripttenha sido concluído com sucesso (service_completed_successfully), garantindo que os dados iniciais estejam no cache antes que a API comece a receber requisições.
Conclusão
Parabéns! Você agora entende como orquestrar a inicialização de serviços em uma aplicação multi-contêiner de forma confiável. Você aprendeu a ir além da simples ordem de inicialização e a garantir que os serviços estejam verdadeiramente prontos antes que outros que dependem deles iniciem.
Principais Pontos:
- Condições de Corrida: Iniciar serviços sem uma ordem definida pode fazer com que aplicações falhem se uma dependência não estiver pronta.
depends_onBásico: Garante a ordem de inicialização dos contêineres, mas não a prontidão da aplicação dentro deles. É um mecanismo insuficiente para a maioria dos casos de uso do mundo real.depends_oncom Condições: A abordagem moderna e robusta.condition: service_healthy: Espera que um serviço passe em sua verificação de saúde (healthcheck). É a escolha ideal para dependências de longa duração, como bancos de dados e outras APIs.condition: service_completed_successfully: Espera que um serviço execute sua tarefa e termine com sucesso. Perfeito para tarefas de inicialização, como migrações de banco de dados ou scripts de seeding.
Na próxima lição, vamos nos aprofundar no que torna tudo isso possível: implementar health checks em Docker Compose. Você aprenderá a escrever seus próprios healthchecks para seus serviços .NET, dando a você controle total sobre a definição de "pronto" para suas aplicações.