ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [Docker][unhealthy 오류] healthcheck가 실패해도 컨테이너가 재시작되지 않는 이유
    기타개발지식/풀스택개발 2026. 9. 6. 20:05

    IT 리서치 노트

    [Docker][unhealthy 오류] healthcheck가 실패해도 컨테이너가 재시작되지 않는 이유

    Docker 컨테이너가 unhealthy인데 restart: always를 넣어도 재시작되지 않는다면 설정이 무시된 것이 아니다. 2026년 9월 6일 KST 기준 Docker 공식 문서의 경계를 보면 healthcheck는 상태를 보고하고 restart policy는 컨테이너 종료에 반응한다. 프로세스가 계속 실행 중이면 두 기능 사이에 자동 연결이 없다.

    1. 개요

    unhealthy는 exited가 아니다. healthcheck 실패만으로 Docker가 main process를 종료하지 않으므로 restart policy도 실행되지 않는다. 먼저 Health.Log에서 실패 원인을 확인한 뒤, 앱 종료·오케스트레이터 교체·외부 감시·수동 대응 중 서비스 특성에 맞는 복구 주체를 정해야 한다.

    시작 순서가 의심되면 depends_on과 service_healthy 설정, 검사 시간값이 의심되면 healthcheck 시간 필드 비교, 종료 뒤 복구 규칙은 Docker 재시작 정책 선택 기준에서 먼저 경계를 확인할 수 있다.

    2. 어디서 실제로 막히는가

    흔한 증상은 ps에 Up (unhealthy)가 계속 보이고 RestartCount는 0인 상태다. 검사 endpoint는 500을 반환하지만 PID 1은 살아 있다. 이때 restart 값을 always에서 unless-stopped로 바꿔도 결과는 같다. 두 정책 모두 종료 뒤 동작을 정할 뿐 health 실패를 종료로 바꾸지 않기 때문이다.

    • healthcheck를 liveness와 readiness 모두로 사용한다.
    • 외부 DB의 짧은 지연 때문에 컨테이너를 반복 종료한다.
    • 검사 도구 누락을 애플리케이션 장애로 오해한다.
    • 자동 kill로 Health.Log의 원인을 잃는다.

    먼저 검사 명령을 컨테이너 안에서 직접 실행하고 exit code와 출력을 본다. 애플리케이션이 요청을 처리할 수 없는지, 검사 명령 자체가 없는지, 외부 의존성만 느린지를 분리해야 한다.

    재현 기록에는 사용한 이미지 태그와 Compose 프로젝트 이름, 실행 명령, 관찰 시각을 함께 남긴다. 같은 파일이라도 이미지가 바뀌거나 다른 override가 적용되면 결과가 달라진다. 정상 사례 하나와 실패 사례 하나를 같은 순서로 수집해야 관찰 기준이 충분히 민감한지도 확인할 수 있다.

    수정할 때는 파일 여러 곳을 한 번에 바꾸지 않는다. 현재 출력과 설정을 저장하고 첫 불일치 한 항목만 고친 뒤 같은 입력으로 다시 실행한다. 그래야 우연한 재시작이나 캐시 효과를 해결로 잘못 기록하지 않는다.

    3. 실무에서 적용하는 순서

    확인 순서는 Running, Health.Status, Health.Log, RestartCount, RestartPolicy다. Running=true이고 unhealthy라면 예상 동작이다. 복구가 꼭 필요하면 앱이 복구 불가능 상태에서 정상적으로 종료하도록 만들거나, readiness와 liveness를 분리할 수 있는 오케스트레이터를 사용한다.

    1. Health.Log의 최근 exit code와 출력을 확인한다.
    2. 검사 명령을 같은 컨테이너에서 직접 실행한다.
    3. 일시 의존성 장애와 내부 교착을 구분한다.
    4. 복구 책임과 backoff, 최대 반복 횟수를 정한다.
    5. 의도적인 실패로 알림과 복구 후 readiness를 함께 검증한다.
    # 검사 실패 자체와 main process 상태를 따로 확인한다.
    docker compose exec api sh -lc 'curl -fsS http://localhost:8080/ready; echo exit=$?'
    docker inspect --format '{{json .HostConfig.RestartPolicy}}' example-api-1

    성공 기준은 단순 재시작이 아니다. 재시작 전 요청 중단, 종료 유예, 재기동 뒤 데이터 일관성, 반복 상한과 알림까지 확인해야 복구 루프가 새 장애를 만들지 않는다.

    변경 뒤에는 깨끗한 시작과 기존 상태를 유지한 재시작을 모두 확인한다. 결과 표에는 기대 상태, 실제 상태, 첫 실패 시각, 마지막 성공 시각을 분리해 적는다. 이 네 값이 있어야 다음 배포에서도 같은 기준으로 회귀 여부를 판정할 수 있다.

    4. 공식 문서와 예시 화면으로 확인하기

    첫 자료에서는 연속 실패가 컨테이너 상태를 unhealthy로 바꾼다는 동작을 확인한다. 화면의 강조된 문장이나 옵션을 현재 설정과 같은 이름의 필드로 대조한다.

    healthcheck는 상태를 보고하지만 프로세스를 종료시키는 규칙은 아니다.
    healthcheck는 상태를 보고하지만 프로세스를 종료시키는 규칙은 아니다.

    따라서 main process가 살아 있으면 restart policy가 반응할 종료 사건도 없다. 이 값을 변경 전 기록에 남기고 다음 단계의 성공 신호와 연결한다.

    두 번째 자료에서는 restart policy가 컨테이너 종료에 반응하는 기능임을 확인한다. 화면의 강조된 문장이나 옵션을 현재 설정과 같은 이름의 필드로 대조한다.

    재시작 정책과 health 상태 전환은 서로 다른 경계다.
    재시작 정책과 health 상태 전환은 서로 다른 경계다.

    unhealthy를 자동 복구하려면 애플리케이션 종료, 오케스트레이터, 외부 감시 중 하나를 설계해야 한다. 이 값을 변경 전 기록에 남기고 다음 단계의 성공 신호와 연결한다.

    실행 상태와 health 상태를 두 축으로 놓으면 오해가 사라진다. 화면의 강조된 문장이나 옵션을 현재 설정과 같은 이름의 필드로 대조한다.

    running·exited와 healthy·unhealthy 조합별 반응표다.
    running·exited와 healthy·unhealthy 조합별 반응표다.

    restart 정책은 exited 사건을 기준으로 판단한다. 이 값을 변경 전 기록에 남기고 다음 단계의 성공 신호와 연결한다.

    Health.Log의 최근 검사 결과와 프로세스 상태를 같이 봐야 한다. 화면의 강조된 문장이나 옵션을 현재 설정과 같은 이름의 필드로 대조한다.

    unhealthy 원인과 재시작 횟수를 나란히 조회한다.
    unhealthy 원인과 재시작 횟수를 나란히 조회한다.

    ExitCode가 아직 없고 Running=true라면 재시작이 없는 것이 예상 동작이다. 이 값을 변경 전 기록에 남기고 다음 단계의 성공 신호와 연결한다.

    복구 방식은 장애 의미와 데이터 안전성을 보고 고른다. 화면의 강조된 문장이나 옵션을 현재 설정과 같은 이름의 필드로 대조한다.

    unhealthy 복구 선택지를 책임 주체별로 비교한다.
    unhealthy 복구 선택지를 책임 주체별로 비교한다.

    무조건 kill하는 감시 스크립트는 일시 장애와 영구 장애를 구분하지 못한다. 이 값을 변경 전 기록에 남기고 다음 단계의 성공 신호와 연결한다.

    5. 주의사항과 리스크

    unhealthy마다 즉시 컨테이너를 죽이면 외부 서비스의 짧은 장애가 전체 재시작 폭주로 번질 수 있다. 상태 저장 서비스는 강제 종료 전에 flush와 복구 절차가 필요하다. 검사 endpoint에 모든 외부 의존성을 묶는 것도 연쇄 장애를 키우므로 요청 가능 여부와 교체 필요 여부를 나눠 설계한다.

    6. 결론

    healthcheck는 관측 신호이고 restart policy는 종료 대응 규칙이다. 두 기능을 자동 복구 하나로 보지 말고, 왜 unhealthy인지 확인한 뒤 종료와 교체를 누가 결정할지 명시해야 예측 가능한 복구가 된다.

    7. 참고 링크

    1. https://docs.docker.com/reference/dockerfile/#healthcheck
    2. https://docs.docker.com/engine/containers/start-containers-automatically/
    3. https://docs.docker.com/reference/cli/docker/inspect/
Designed by Tistory.