컨테이너가 실행 중이라고 해서 서비스가 정상 동작한다는 보장은 없다. DB 프로세스는 떠 있지만 아직 연결을 받을 준비가 되지 않은 상황, 혹은 앱이 기동은 됐지만 내부 에러로 요청을 처리하지 못하는 상황이 모두 여기에 해당한다. Health Check를 설정하면 Compose가 컨테이너의 실제 상태를 주기적으로 확인하고, 의존 서비스가 준비됐을 때만 다음 컨테이너를 시작하도록 제어할 수 있다.
services:
app:
image: my-app:latest
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8080/health"]
interval: 10s
timeout: 5s
retries: 3
start_period: 20s
| 옵션 | 기본값 | 설명 |
|---|---|---|
test | — | 상태를 확인할 명령 |
interval | 30s | 검사 주기 |
timeout | 30s | 명령 타임아웃 |
retries | 3 | 실패 허용 횟수 |
start_period | 0s | 초기 유예 기간 |
start_period — 컨테이너 시작 직후 이 시간 동안 실패해도 retries 카운트에 포함되지 않는다. 앱 부팅 시간이 긴 경우 설정한다.
test 필드는 두 가지 형식을 지원한다.
# 셸 없이 직접 실행 (권장)
test: ["CMD", "pg_isready", "-U", "postgres"]
# 셸을 통해 실행
test: ["CMD-SHELL", "curl -f http://localhost/health || exit 1"]
CMD 형식은 셸 인터프리터를 거치지 않으므로 더 가볍고 예측 가능하다. 파이프(|)나 조건 연산자가 필요할 때만 CMD-SHELL을 사용한다.
컨테이너 시작
│
▼
[start_period 대기]
│
▼
test 실행 ──── 성공 ────► healthy
│
실패
│
retries 남음? ── Y ──► interval 후 재시도
│
N
▼
unhealthy
Health Check의 진짜 효과는 depends_on의 condition 옵션과 함께 쓸 때 나온다.
services:
db:
image: postgres:16
healthcheck:
test: ["CMD", "pg_isready", "-U", "postgres"]
interval: 5s
timeout: 3s
retries: 5
app:
image: my-app:latest
depends_on:
db:
condition: service_healthy
service_healthy — db 컨테이너의 health 상태가 healthy가 될 때까지 app 컨테이너 시작을 블로킹한다. service_started(기본값)는 프로세스 기동 여부만 본다.
condition: service_healthy를 지정하면 DB가 실제로 쿼리를 받을 수 있는 상태가 된 뒤에 앱이 뜨므로, 기동 시 DB 연결 실패로 인한 크래시를 방지할 수 있다.
# PostgreSQL
test: ["CMD", "pg_isready", "-U", "postgres", "-d", "mydb"]
# MySQL / MariaDB
test: ["CMD", "mysqladmin", "ping", "-h", "localhost", "--silent"]
# Redis
test: ["CMD", "redis-cli", "ping"]
# MongoDB
test: ["CMD", "mongosh", "--eval", "db.adminCommand('ping')"]
각 DB 이미지에는 연결 확인 전용 CLI가 포함돼 있으므로, curl보다 해당 도구를 우선 사용한다. 종료 코드 0이면 healthy, 그 외는 실패로 처리된다.