Docker container가 계속 재시작될 때: 먼저 확인할 것들
마지막 업데이트

Docker container가 계속 재시작될 때: 먼저 확인할 것들


Docker container가 계속 재시작될 때, 보이는 증상은 단순하지만 원인은 대개 단순하지 않습니다. 프로세스 crash, 잘못된 command, 누락된 environment, 의존성 startup 실패, health 기대치 불일치가 모두 restart loop를 만들 수 있습니다.

짧게 말하면, restart policy는 원인이 아니라 증상을 더 자주 보이게 하는 요소로 봐야 합니다. 먼저 main process가 왜 종료되는지, startup 초반의 첫 의미 있는 log가 무엇인지 확인하는 것이 핵심입니다.


먼저 process exit와 orchestration 동작을 구분하세요

아래 두 상황은 비슷해 보여도 다릅니다.

  • main process가 종료되어 Docker가 container를 계속 다시 시작하는 경우
  • container는 떠 있지만 외부 orchestration이나 운영 자동화가 unhealthy 판단으로 계속 다시 만드는 경우

main process가 죽는다면 log와 exit code가 우선입니다. container는 살아 있는데 바깥에서 계속 교체된다면 health, readiness, deployment 동작을 더 봐야 합니다.

restart loop의 흔한 원인

1. main process가 바로 종료됨

container command가 금방 끝나면 Docker는 container를 stopped 상태로 보고, restart policy가 있으면 loop가 만들어집니다.

이미지가 기대한 command와 실제 배포에서 쓰는 entrypoint가 다를 때 자주 생깁니다.

2. 필요한 environment나 secret이 빠져 있음

애플리케이션은 변수, config file, credential, mounted secret이 없으면 startup 단계에서 바로 실패하는 경우가 많습니다.

3. command나 working directory가 잘못됨

ENTRYPOINT, CMD, shell quoting, working directory가 조금만 어긋나도 앱이 충분한 로그를 남기기 전에 실패할 수 있습니다.

4. startup이 외부 의존성 가용성에 지나치게 묶여 있음

database, cache, network mount, remote API가 늦게 뜨거나 잠시 unavailable 이면 startup 전체가 실패할 수 있습니다.

로컬 Compose 환경과 첫 배포에서 특히 흔합니다.

5. health 기대치가 너무 빡빡함

애플리케이션은 결국 떠오를 수 있는데 주변 환경이 너무 빨리 healthy 상태를 기대해서 안정화 전에 반복 교체하는 경우도 있습니다.

실전 점검 순서

1. exit code와 restart 패턴을 먼저 보세요

기본 명령은 아래와 같습니다.

docker ps -a
docker logs <container>
docker inspect <container> --format '{{.State.ExitCode}}'

여기서 중요한 건 모든 로그를 읽는 것이 아니라 첫 fatal startup error와 exit pattern을 잡아내는 것입니다.

2. startup command, entrypoint, environment를 비교하세요

실행 구성이 image 기대와 맞는지 확인해야 합니다.

  • entrypoint와 command가 맞는가
  • working directory가 맞는가
  • 필요한 env var가 모두 있는가
  • mounted file이 예상 경로에 존재하는가

restart loop는 코드 버그보다 설정 불일치에서 시작되는 경우도 많습니다.

3. dependency timing 문제 없이 시작할 수 있는지 보세요

서비스가 database, cache, network mount, remote API를 기다리다가 실패하는지 확인해야 합니다.

startup 중 하드 실패를 내는 구조라면 잠깐의 의존성 지연도 계속된 restart로 이어질 수 있습니다.

4. app crash인지 startup budget mismatch인지 구분하세요

시간만 더 주면 healthy가 될 수 있는데 주변 환경이 먼저 죽여버리는 상황인지, 아니면 애초에 정상 상태에 가까워지지도 못하는 crash인지 구분해야 합니다.

5. restart policy는 원인이 보인 뒤에만 바꾸세요

디버깅 편의를 위해 잠시 조정할 수는 있지만, restart behavior를 바꾼다고 startup failure가 해결되지는 않습니다.

패턴을 찾은 뒤 어떻게 바꿀지

main process가 바로 종료되는 경우

container가 의도한 long-lived foreground process를 실제로 실행하도록 startup command를 고치세요.

environment나 mounted file이 빠진 경우

image보다 배포 설정을 먼저 수정해야 합니다. 변수 이름, 파일 경로, secret 이름, mount target을 다시 확인하세요.

dependency timing이 원인인 경우

startup을 더 관대하게 만들고, boot 단계의 강한 의존성을 줄이고, 필요하다면 dependency 준비 순서를 조정하세요.

health 기대치가 과한 경우

애플리케이션이 현실적으로 안정화될 시간을 고려해 health timing이나 startup behavior를 맞추는 편이 좋습니다.

image 변경 이후부터 restart가 시작된 경우

배포 체감도 같이 나빠졌다면 Docker image가 너무 클 때를, container는 뜨지만 networking 가정이 어긋난다면 Docker port가 이미 할당되었을 때를 함께 보세요.

빠른 체크리스트

container가 계속 재시작될 때는 아래 순서가 가장 실용적입니다.

  1. exit code와 restart count를 본다
  2. startup 초반 첫 fatal log를 읽는다
  3. entrypoint, command, env, mounted file을 확인한다
  4. dependency가 startup 중 unavailable 한지 본다
  5. crash loop와 health timing 문제를 구분한다
  6. restart policy는 원인을 이해한 뒤에만 바꾼다

FAQ

Q. restart policy가 핵심 원인인가요?

대개 아닙니다. 증상을 보이게 만들 뿐, 실제 원인은 process exit나 startup failure입니다.

Q. 가장 빠른 첫 단계는 무엇인가요?

exit code와 첫 fatal startup log를 보는 것입니다.

Q. 로컬에서는 잘 되는데 배포된 container만 재시작되는 이유는 뭔가요?

로컬과 배포 환경의 env, file, dependency timing, command가 다르기 때문인 경우가 많습니다.

Q. restart를 끄니까 container가 멈춰 있으니 해결된 건가요?

아닙니다. loop를 숨겼을 뿐 startup failure 경로가 그대로일 수 있습니다.

Sources:

먼저 읽어볼 가이드

검색 유입이 많은 핵심 글부터 이어서 보세요.