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가 계속 재시작될 때는 아래 순서가 가장 실용적입니다.
- exit code와 restart count를 본다
- startup 초반 첫 fatal log를 읽는다
- entrypoint, command, env, mounted file을 확인한다
- dependency가 startup 중 unavailable 한지 본다
- crash loop와 health timing 문제를 구분한다
- 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 경로가 그대로일 수 있습니다.
Read Next
- config나 mount 변경 뒤부터 실패했다면 Docker bind mount permission denied를 보세요.
- host networking 충돌이 의심되면 Docker port가 이미 할당되었을 때를 확인하세요.
- image가 무거워져 deploy 동작도 달라졌다면 Docker image가 너무 클 때를 같이 보세요.
- 더 넓은 인프라 글은 Infra 카테고리에서 볼 수 있습니다.
Related Posts
- Docker bind mount permission denied
- Docker port가 이미 할당되었을 때
- Docker image가 너무 클 때
- Docker no space left on device
Sources:
- https://docs.docker.com/engine/containers/start-containers-automatically/
- https://docs.docker.com/reference/cli/docker/container/run/
- https://docs.docker.com/reference/cli/docker/container/restart/
심사 대기 중에는 광고 대신 관련 가이드를 먼저 보여줍니다.
먼저 읽어볼 가이드
검색 유입이 많은 핵심 글부터 이어서 보세요.
- 미들웨어 트러블슈팅 가이드: Redis vs RabbitMQ vs Kafka 개발자를 위한 미들웨어 트러블슈팅 허브 글입니다. Redis, RabbitMQ, Kafka 중 어떤 증상부터 먼저 봐야 하는지와 어떤 문제 패턴이 각 시스템에 가까운지 정리합니다.
- Kubernetes CrashLoopBackOff: 먼저 볼 것들 startup failure, probe, config, resource limit 관점에서 CrashLoopBackOff를 어떻게 나눠서 봐야 하는지 정리한 가이드입니다.
- Kafka consumer lag가 계속 늘 때: 트러블슈팅 가이드 Kafka consumer lag가 계속 늘어날 때 무엇부터 봐야 하는지 정리합니다. poll 주기, 처리 속도, rebalance, consumer 설정까지 실전 기준으로 다룹니다.
- Kafka Rebalancing Too Often 가이드 Kafka consumer group에서 rebalance가 너무 자주 일어날 때 membership flapping, poll timing, protocol, assignment churn을 어떤 순서로 봐야 하는지 설명하는 실전 가이드입니다.
심사 대기 중에는 광고 대신 관련 가이드를 먼저 보여줍니다.