← 아티클 목록

Docker Compose depends_on과 기동 순서 함정

2027-08-23#docker#compose#트러블슈팅

docker compose up을 했더니 앱 컨테이너가 "DB 연결 실패"로 죽는 경험, 한 번쯤 있을 겁니다. depends_on으로 DB를 먼저 적었는데도 말이죠. 핵심 오해는 여기 있습니다. depends_on은 "시작 순서"만 정할 뿐, 의존 서비스가 "준비 완료"되기를 기다리지 않습니다. DB 컨테이너가 시작되자마자 앱이 뜨는데, 그 시점에 PostgreSQL은 아직 초기화 중이라 접속을 못 받습니다.

기본 depends_on의 한계

YAML
services:
  app:
    build: .
    depends_on:
      - db
  db:
    image: postgres:16

이 설정은 "db 컨테이너를 app보다 먼저 띄워라"까지만 합니다. db 안의 Postgres 프로세스가 접속을 받을 준비가 됐는지는 보지 않습니다. 그래서 앱이 너무 빨리 떠서 다음 에러를 만납니다.

OUTPUT
could not connect to server: Connection refused
Is the server running on host "db" (172.18.0.2) and accepting
TCP connections on port 5432?

해결 — healthcheck + condition

준비 완료를 기다리게 하려면 의존 서비스에 healthcheck를 달고, depends_on에서 condition: service_healthy를 요구합니다.

YAML
services:
  app:
    build: .
    depends_on:
      db:
        condition: service_healthy
  db:
    image: postgres:16
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U postgres"]
      interval: 5s
      timeout: 3s
      retries: 5

이제 pg_isready가 성공해 db가 healthy로 바뀐 뒤에야 app이 시작됩니다.

condition 종류

condition의미
service_started컨테이너가 시작되면 (기본값, 준비 보장 안 함)
service_healthyhealthcheck가 통과하면
service_completed_successfully의존 서비스가 정상 종료하면 (마이그레이션 등)

그래도 앱 쪽 재시도는 필요하다

healthcheck를 걸어도 운영 중 DB가 잠깐 끊기면 앱은 다시 실패합니다. compose의 기동 순서는 "첫 부팅"만 다뤄주므로, 앱 코드에 접속 재시도 로직을 넣는 게 정석입니다. 컨테이너 자체를 다시 살리려면 restart: on-failure도 함께 둡니다.

체크리스트

Docker
docker compose config        # depends_on·condition 파싱 확인
docker compose ps            # STATUS의 (healthy) 표시 확인
docker inspect <컨테이너> --format '{{.State.Health.Status}}'
docker compose logs db       # pg_isready 통과 시점 확인

docker compose ps에서 db가 Up (healthy)로 보이면 condition이 제대로 동작하는 것입니다.


healthcheck와 의존 순서를 직접 만들어 앱이 DB를 기다리게 하는 실습은 도커 트랙에서 무료로 할 수 있습니다.