Docker Compose depends_on이 제대로 동작하지 않는 이유와 해결법
Docker Compose에서 depends_on을 설정했는데도 FastAPI 컨테이너가 PostgreSQL 연결에 실패했다.
분명히 postgres가 먼저 시작되도록 설정했는데 왜 이런 문제가 발생한 걸까? 로그를 보니 이런 오류가 찍혀 있었다.
could not connect to server: Connection refused
Is the server running on host "postgres" and accepting
TCP/IP connections on port 5432?UGREEN DXP4800PLUS NAS에서 쇼츠 자동화 시스템을 운영하면서 이 문제를 겪었다. depends_on을 추가해도 해결이 안 됐고, 결국 healthcheck까지 조합해야 완전히 해결됐다. 이 글에서는 원인과 해결 방법을 정리한다.
depends_on에 대한 오해
많은 사람이 depends_on을 이렇게 이해한다.
postgres 준비 완료
↓
api 시작실제 동작은 이렇다.
postgres 프로세스 시작
↓
api 시작depends_on은 컨테이너 시작 순서만 보장한다. 서비스가 실제로 사용 가능한 상태인지는 확인하지 않는다.
아래 설정이 바로 문제의 원인이다.
# 잘못된 구성 - 여전히 연결 실패 가능
services:
api:
depends_on:
- postgres
postgres:
image: postgres:15-alpinepostgres 컨테이너가 시작됐다고 해서 PostgreSQL이 접속 가능한 상태라는 의미가 아니다.
왜 이런 문제가 발생하는가
PostgreSQL은 컨테이너가 시작된 후 실제로 접속 가능한 상태가 되기까지 여러 단계를 거친다.
컨테이너 시작
↓
PostgreSQL 프로세스 시작
↓
데이터베이스 초기화
↓
WAL 복구 (재시작 시)
↓
접속 가능 상태이 과정이 수 초에서 수십 초까지 걸릴 수 있다. depends_on만 사용하면 이 대기 시간 없이 api가 바로 DB 연결을 시도한다.
실제로 발생하는 로그 패턴:
shorts-api | sqlalchemy.exc.OperationalError: could not connect to server
shorts-api | connection refused
shorts-postgres | database system is starting up
shorts-postgres | database system was shut down at ...
shorts-postgres | database system is ready to accept connectionsapi가 연결을 시도하는 시점에 postgres는 아직 초기화 중인 상태다.
해결 방법: healthcheck + condition
healthcheck를 사용하면 PostgreSQL이 실제로 접속 가능한 상태인지 확인할 수 있다.
services:
postgres:
image: postgres:15-alpine
container_name: shorts-postgres
environment:
POSTGRES_DB: shorts
POSTGRES_USER: shorts
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
restart: unless-stopped
healthcheck:
test: ["CMD-SHELL", "pg_isready -U shorts"]
interval: 5s
timeout: 5s
retries: 5
api:
image: python:3.11-slim
container_name: shorts-api
depends_on:
postgres:
condition: service_healthy
restart: unless-stopped핵심은 두 가지다.
postgres에 healthcheck 추가:
healthcheck:
test: ["CMD-SHELL", "pg_isready -U shorts"]
interval: 5s
timeout: 5s
retries: 5pg_isready는 PostgreSQL이 실제로 접속 가능한 상태인지 확인하는 명령어다. 5초마다 확인하고, 5번 실패하면 unhealthy 상태로 표시된다.
depends_on에 condition 추가:
depends_on:
postgres:
condition: service_healthyservice_healthy는 postgres의 healthcheck가 통과된 후에만 api를 시작하도록 한다. 단순히 컨테이너가 시작됐는지가 아니라 실제 서비스 상태를 확인한다.
참고: condition: service_healthy는 Docker Compose V2 기준으로 사용 가능하다. 구버전 Compose를 사용 중이라면 동작 방식이 다를 수 있으므로 버전을 먼저 확인하는 것이 좋다.
docker compose version
실제 적용 사례
쇼츠 자동화 시스템에서 postgres, redis, shorts-api 세 개 컨테이너를 운영하고 있었다.
처음에는 단순히 depends_on: - postgres만 설정했다. 시스템을 처음 올릴 때는 문제가 없었는데, NAS 재부팅 후 재시작할 때 간헐적으로 api가 DB 연결에 실패했다. 재시작할 때마다 직접 확인하고 수동으로 컨테이너를 다시 올려야 했다.
healthcheck와 condition: service_healthy를 적용한 후에는 NAS 재부팅 후에도 모든 컨테이너가 자동으로 정상 상태로 올라온다.
healthcheck 상태 확인
# 컨테이너 상태 확인 (healthy 표시 여부)
docker ps
# 특정 컨테이너 healthcheck 상세 확인
docker inspect shorts-postgres | grep -A 10 Healthdocker ps 결과에서 (healthy) 표시가 있으면 정상이다.
shorts-postgres Up 5 days (healthy) 5432/tcp추가 팁
depends_on만으로는 부족한 경우가 많다. 운영 환경에서는 세 가지를 함께 사용하는 것을 권장한다.
services:
api:
depends_on:
postgres:
condition: service_healthy
restart: unless-stopped # 실패 시 자동 재시작
# 애플리케이션 레벨 재시도 로직도 추가 권장restart: unless-stopped는 컨테이너가 비정상 종료될 때 자동으로 재시작한다. healthcheck와 함께 사용하면 대부분의 시작 순서 문제를 커버할 수 있다.
healthcheck를 적용해도 네트워크 지연이나 일시적인 문제는 발생할 수 있다. 운영 환경에서는 FastAPI 시작 시 데이터베이스 연결을 여러 번 재시도하도록 구현하는 것이 좋다.
healthcheck는 첫 번째 방어선, 애플리케이션 재시도 로직은 두 번째 방어선이다.
마무리
depends_on은 컨테이너 시작 순서만 보장한다. 서비스가 실제로 사용 가능한 상태인지 확인하려면 healthcheck와 condition: service_healthy를 함께 사용해야 한다.
depends_on만 사용
→ 컨테이너 시작 순서만 보장
→ 간헐적 연결 실패 발생
depends_on + healthcheck + condition: service_healthy
→ 실제 서비스 준비 상태 확인
→ 안정적인 시작 보장NAS 재부팅처럼 모든 컨테이너가 동시에 시작되는 환경에서 특히 중요하다.

댓글
댓글 쓰기