본문 바로가기
개발/트러블슈팅

Docker Compose depends_on 사용법: healthcheck로 DB 준비 기다리기

by char_lie 2026. 9. 4.
반응형

Docker Compose depends_on과 healthcheck 사용법 썸네일

docker compose up을 실행했는데 API 컨테이너가 데이터베이스 연결 오류를 내고 재시작되는 경우가 있다. depends_on을 이미 적었는데도 문제가 생기면 컨테이너가 실행된 시점과 내부 서비스가 요청을 받을 준비를 마친 시점을 구분해야 한다.

Compose는 의존성 순서에 따라 컨테이너를 시작하지만, 짧은 문법의 depends_on만으로 데이터베이스 준비 완료까지 기다리지는 않는다. 이때 데이터베이스의 healthcheckcondition: service_healthy를 함께 사용하면 API를 시작할 조건을 명확하게 만들 수 있다.

데이터베이스 healthcheck 통과 후 API 컨테이너가 시작되는 흐름

depends_on만으로 부족한 이유

데이터베이스 컨테이너 프로세스가 시작돼도 초기화, 복구, 테이블 준비 때문에 실제 연결을 받기까지 시간이 더 필요할 수 있다. 따라서 다음 두 상태는 같지 않다.

상태 의미
컨테이너가 실행 중 컨테이너의 주 프로세스가 시작됨
서비스가 준비됨 애플리케이션 요청을 정상 처리할 수 있음

짧은 문법은 생성 순서를 정하는 데는 유용하지만 준비 상태를 검사하지 않는다.

services:
  api:
    image: my-api:latest
    depends_on:
      - db

  db:
    image: postgres:18

이 구성에서는 db 컨테이너가 먼저 시작된다. 하지만 PostgreSQL이 연결을 받을 수 있는지는 별도로 확인하지 않으므로 API가 너무 빨리 접속하면 첫 요청이 실패할 수 있다.

healthcheck와 service_healthy 구성

PostgreSQL의 준비 상태를 pg_isready로 검사하고, API가 그 결과를 기다리게 만들면 다음과 같이 구성할 수 있다.

services:
  db:
    image: postgres:18
    environment:
      POSTGRES_DB: app
      POSTGRES_USER: app
      POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U $${POSTGRES_USER} -d $${POSTGRES_DB}"]
      interval: 10s
      timeout: 5s
      retries: 5
      start_period: 20s

  api:
    image: my-api:latest
    depends_on:
      db:
        condition: service_healthy

${POSTGRES_PASSWORD}는 Compose를 실행하는 환경에서 전달하고 실제 비밀번호를 YAML에 직접 적지 않는다. healthcheck.test 안의 $${POSTGRES_USER}처럼 달러 기호를 두 번 쓴 부분은 호스트의 Compose 보간을 피하고 컨테이너 안에서 환경변수를 사용하기 위한 표현이다.

healthcheck 옵션은 어떻게 볼까?

각 값은 무조건 짧게 만드는 것보다 서비스가 실제로 준비되는 시간에 맞춰야 한다.

옵션 역할 확인할 점
test 준비 상태를 판정할 명령 성공 시 종료 코드 0을 반환하는지
interval 검사 사이의 간격 너무 짧아 불필요한 부하를 만들지 않는지
timeout 한 번의 검사 제한 시간 정상 응답 시간보다 지나치게 짧지 않은지
retries 연속 실패 허용 횟수 초기화 지연을 감당할 수 있는지
start_period 초기 준비 유예 시간 마이그레이션이나 복구 시간을 반영했는지

service_healthy는 healthcheck가 성공해야 의존 서비스의 생성·시작 단계로 넘어가게 한다. healthcheck 자체가 없으면 기다릴 기준도 없으므로 두 설정을 한 쌍으로 봐야 한다.

시작 순서와 재시작 정책은 다르다

여기서 자주 헷갈리는 부분은 depends_on이 애플리케이션의 모든 재연결 문제를 해결해 주는 것은 아니라는 점이다.

  • 시작 시점의 순서는 Compose가 관리한다.
  • 실행 중 데이터베이스 연결이 끊어졌을 때의 재시도는 애플리케이션이 처리해야 한다.
  • 컨테이너가 비정상 종료됐을 때 다시 실행할지는 서비스 수준의 restart 정책이 담당한다.
  • depends_on 아래의 restart: true는 명시적인 Compose 작업으로 의존 서비스를 갱신하거나 재시작할 때 종속 서비스도 다시 시작하도록 만드는 별도 동작이다.

따라서 API에는 연결 재시도와 적절한 타임아웃을 남겨 두는 편이 안전하다. healthcheck는 시작 조건을 개선하지만 운영 중 장애 복구 로직을 대신하지 않는다.

설정이 적용됐는지 확인하기

먼저 Compose 파일의 문법과 변수 보간 결과를 확인한다.

POSTGRES_PASSWORD=example docker compose config

실행한 뒤에는 서비스 상태를 확인한다.

docker compose up -d
docker compose ps

docker compose ps에서 데이터베이스 상태가 healthy로 바뀐 뒤 API가 실행되는지 확인한다. 상태가 계속 starting 또는 unhealthy라면 API보다 healthcheck 명령을 먼저 점검해야 한다.

docker inspect --format='{{json .State.Health}}' <db-container-name>

이 글의 Compose 예시는 Docker Compose v5.3.0에서 docker compose config 검사를 통과했다. 현재 환경에서는 Docker 데몬 접근이 제한돼 실제 컨테이너 시작 순서까지 재현하지 않았으므로, 적용할 때는 사용 중인 이미지의 healthcheck 명령과 준비 시간을 함께 확인해야 한다.

결국 핵심은 depends_on을 적는 것보다 무엇을 준비 완료로 볼지 정의하는 데 있다. 데이터베이스의 실제 응답을 healthcheck로 확인하고 API가 service_healthy를 기다리게 하면 시작 직후 발생하는 연결 오류를 줄일 수 있다. 이미지 빌드 단계까지 정리하려면 도커 이미지 크기 줄이기를 이어서 볼 수 있으며, 세부 조건은 Docker Compose 시작 순서 공식 문서에서 확인할 수 있다.

반응형

댓글