← 아티클 목록

Docker Compose healthcheck로 기동 순서·대기 처리하기

2027-10-11#docker#compose#운영

docker compose up을 하면 앱 컨테이너가 DB보다 먼저 떠서 connection refused로 죽는 경우가 있습니다. depends_on만 적으면 컨테이너 "시작 순서"는 지켜지지만, DB 프로세스가 연결을 받을 준비가 됐는지는 보장하지 않습니다. 컨테이너가 떴다고 안의 서비스가 준비된 것은 아니기 때문입니다. 이걸 해결하는 게 healthcheck입니다.

핵심 — "시작"과 "준비"는 다르다

depends_on: [db]는 db 컨테이너가 시작되면 곧바로 앱을 띄웁니다. 하지만 PostgreSQL은 컨테이너 시작 후에도 수 초간 초기화를 합니다. 그 사이 앱이 붙으면 실패합니다. 해법은 db에 헬스체크를 달고, 앱이 "db가 healthy일 때까지" 기다리게 하는 것입니다.

1단계 — DB에 healthcheck 추가

YAML
services:
  db:
    image: postgres:16
    environment:
      POSTGRES_PASSWORD: secret
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U postgres"]
      interval: 5s
      timeout: 3s
      retries: 5
      start_period: 10s

pg_isready는 PostgreSQL이 연결을 받을 준비가 됐을 때만 종료 코드 0을 돌려줍니다. start_period는 기동 유예 구간으로, 이 시간 안의 실패는 재시도 횟수에 포함되지 않습니다.

2단계 — depends_on에 condition 걸기

YAML
  app:
    image: myapp:latest
    depends_on:
      db:
        condition: service_healthy

service_healthy를 명시하면 Compose는 db가 healthy가 될 때까지 app을 띄우지 않습니다. 이것이 빠진 depends_on: [db]와의 결정적 차이입니다.

3단계 — 상태 확인

Docker
docker compose up -d
docker compose ps          # STATUS에 (healthy) 표시
docker inspect --format '{{.State.Health.Status}}' <container>

docker compose ps의 STATUS가 Up 12 seconds (healthy)로 바뀌면 헬스체크가 동작하는 것입니다. (health: starting)은 아직 start_period 안이라는 뜻입니다.

자주 만나는 함정

테스트 명령이 컨테이너 안에 없으면 헬스체크가 항상 실패합니다.

OUTPUT
container is unhealthy
dependency failed to start: container app-db-1 is unhealthy

curl로 헬스체크를 짰는데 이미지에 curl이 없으면 이 에러가 납니다. 해당 이미지에 실제 존재하는 도구(pg_isready, wget, nc)를 쓰거나 CMD-SHELL로 셸 내장 기능을 활용하세요. 또 retriesinterval을 너무 짧게 잡으면 느린 DB가 영원히 unhealthy로 남을 수 있으니 start_period를 넉넉히 줍니다.

적용 체크리스트

Docker
docker compose config       # condition·healthcheck 문법 검증
docker compose ps           # (healthy) 표시 확인
docker compose logs db      # 헬스체크 실패 시 원인 추적

healthcheck + service_healthy 조합 하나로 "DB 먼저, 앱 나중" 기동 순서 문제의 대부분이 사라집니다.


Compose 헬스체크를 직접 짜고 일부러 실패시켜 (unhealthy)를 관찰하는 실습은 도커 트랙에서 무료로 해볼 수 있습니다.