볼륨·네트워크·컴포즈 · 헬스체크와 재시작 정책 · 이론
컨테이너는 살아 있는데 서비스는 죽어 있다
한 줄 요약
프로세스가 살아 있다는 것과 요청을 처리할 수 있다는 것은 다른 사실입니다.
헬스체크는 그 둘 사이의 간격을 메우고, 재시작 정책은 실패했을 때
무엇을 할지 정합니다.
왜 이게 필요했나
docker ps 에 Up 3 hours 라고 나옵니다. 그런데 사용자는 500 을 받고
있습니다. 프로세스는 살아 있지만 DB 커넥션 풀이 고갈됐거나, 스레드가
데드락이거나, 디스크가 차서 쓰기를 못 하는 상태입니다.
도커가 아는 것은 PID 1 이 아직 안 죽었다는 사실 하나뿐입니다. 그것만으로
"서비스 중"이라고 판단하면 장애를 몇 시간씩 놓칩니다.
어떻게 동작하나
HEALTHCHECK --interval=30s --timeout=3s --start-period=40s --retries=3 \ CMD curl -fsS http://localhost:8080/healthz || exit 1| 옵션 | 뜻 | 잘못 잡으면 |
| --- | --- | --- |
| interval | 검사 주기 | 너무 짧으면 부하, 길면 감지가 늦다 |
| timeout | 한 번의 검사 제한 시간 | 너무 짧으면 정상인데 실패 판정 |
| start-period | 기동 유예 — 이 구간의 실패는 재시도로 안 침 | 없으면 느리게 뜨는 앱이 계속 죽는다 |
| retries | 연속 실패 허용 횟수 | 1이면 순간적인 지연에도 unhealthy |
상태는 starting → healthy / unhealthy 로 움직입니다.docker inspect --format '{{.State.Health.Status}}' 로 볼 수 있습니다.
중요한 함정: 도커 단독으로는 unhealthy 가 되어도 **컨테이너를 재시작하지
않습니다.** 상태를 표시할 뿐입니다. 재시작은 오케스트레이터(Compose 의depends_on: condition: service_healthy, 스웜, 쿠버네티스의 liveness probe)가
합니다. 헬스체크를 넣었으니 알아서 살아나겠지 — 라고 믿으면 안 됩니다.
헬스체크 엔드포인트를 어떻게 쓸 것인가
/healthz 가 무조건 200 OK 만 돌려주면 아무것도 검사하지 않는 것과
같습니다. 반대로 DB·캐시·외부 API 를 전부 확인하면, 외부 API 하나가
흔들릴 때 우리 서비스가 통째로 unhealthy 가 됩니다.
경계는 이렇게 잡습니다.
- liveness(살아 있나) — 프로세스 자체가 회복 불가 상태인가. 재시작이 답인 것만.
- readiness(받을 준비가 됐나) — 지금 트래픽을 받아도 되나. DB 커넥션 등 포함.
이 구분을 안 하면 "DB 가 잠깐 느려졌다 → liveness 실패 → 재시작 → 커넥션 다시
맺느라 더 느려짐 → 또 실패" 라는 되먹임에 빠집니다. 실제로 자주 일어납니다.
재시작 정책
| 정책 | 동작 |
| --- | --- |
| no (기본) | 죽으면 그대로 둔다 |
| on-failure[:N] | 0 이 아닌 종료코드일 때만, 최대 N 번 |
| always | 항상 재시작. 데몬 재시작 시에도 다시 뜬다 |
| unless-stopped | always 와 같되, 사람이 stop 한 것은 그대로 둔다 |
always 는 무한 재시작 루프를 만들 수 있습니다. 설정 오류로 즉시 죽는
컨테이너가 초당 몇 번씩 재시작하며 로그를 채우는 상황이 대표적입니다.
도커는 재시작 간격을 점점 늘려(백오프) 완화하지만, 근본 해결은 아닙니다.
depends_on 은 순서만 보장한다
services: app: depends_on: [db] # db 컨테이너가 '시작'된 뒤 app 을 시작할 뿐db 가 요청을 받을 준비가 됐는지는 보지 않습니다. PostgreSQL 은 프로세스가
뜨고 나서도 초기화에 몇 초가 더 걸립니다. 그 사이 앱이 접속하면 실패합니다.condition: service_healthy 로 헬스체크와 묶어야 의미가 생깁니다.
현장에서 만나는 모습
- "재시작하니 되던데요" 가 반복된다 → liveness 는 통과하는데 실제로는 못 쓰는 상태.
- 배포 직후에만 실패한다 →
start-period가 없어 기동 중 검사에 걸린다. - 로그가 재시작 메시지로 가득하다 →
always+ 즉시 실패 조합.
다음 확인에서 볼 것
이어지는 퀴즈에서는 실행 중(running)과 정상(healthy)을 구분하고,start-period·재시작 정책·Compose 의 헬스 조건을 어떤 장애에 적용해야 하는지
판단합니다. 앞 실습에서 만든 컨테이너의 상태 전이와 종료코드를 근거로 답해 보세요.