
재부팅 한 번에 서비스가 전멸하는 이유 — 무재시작정책 함정
같은 사고를 두 번 겪었습니다. 둘 다 원인은 똑같았고, 둘 다 아무 에러 로그 없이 조용히 일어났습니다. 컨테이너의 restart 정책 누락 — 사소해 보이지만 24/7 서버에선 치명적입니다.
무슨 일이 일어나나
도커 컨테이너를 docker run이나 compose로 띄울 때 restart 정책을 명시하지 않으면 기본값은 no입니다. 평소엔 아무 문제 없습니다. 컨테이너는 잘 돌고, 죽어도 그냥 죽은 채로 있을 뿐.
문제는 재부팅이나 대량 stop 이벤트(호스트 업데이트, 데몬 재시작) 때 터집니다.
restart: always / unless-stopped인 컨테이너 → 재부팅 후 자동 기동 ✅- 정책 없는 컨테이너 → 안 올라옴 ❌ — 그대로 멈춰 있음
여기서 무서운 건, 일부만 자동 기동되고 일부는 죽어 있는 어중간한 상태가 된다는 점입니다. 핵심 서비스(예: 외부 노출을 담당하는 리버스 프록시·터널)가 정책 누락이면, 나머지가 멀쩡해도 바깥에서 전부 접속 불가가 됩니다.
두 번의 사고
1차 — 웹 서비스의 본체 컨테이너가 재부팅 후 안 올라와 502. 사이트 전체가 죽었는데, 정작 호스트는 멀쩡했습니다.
2차 — 미디어/셀프호스트 스택에서 외부 노출을 담당하던 터널·프록시 컨테이너가 대량 stop 후 자동 기동에 실패. 결과적으로 모든 서브도메인이 2일간 죽어 있었는데, 자동 탐지가 없어 한참 뒤에야 발견했습니다.
두 번 다 근본 원인은 같았습니다 — restart 정책 누락.
재발을 막은 세 가지
① 전 스택 unless-stopped 강제
compose 파일의 모든 서비스에 명시합니다. 일부만 거는 게 가장 위험합니다(어중간한 부분 기동).
services:
proxy:
restart: unless-stopped
app:
restart: unless-stopped
# ... 예외 없이 전부② 정책 감사 스크립트
주기적으로 정책이 빠진 컨테이너를 탐지합니다. 돌고 있는 컨테이너의 실제 정책을 점검:
docker inspect --format '{{.Name}} {{.HostConfig.RestartPolicy.Name}}' $(docker ps -q) \
| grep -v 'unless-stopped'
여기서 뭔가 걸리면 = 재발 위험 신호.
③ 외부에서의 탐지
가장 중요합니다. 서버 바깥에서 핵심 서비스의 외부 엔드포인트를 주기적으로 확인 → 죽으면 즉시 알림. 2차 사고에서 "2일간 몰랐던" 이유가 바로 외부 탐지가 없어서였습니다. 지금은 5분마다 외부에서 헬스를 찌릅니다.
교훈
restart 한 줄은 평소엔 아무 차이가 없어서 빠뜨리기 쉽습니다. 하지만 그 한 줄의 부재가 재부팅 한 번에 서비스를 전멸시킬 수 있습니다. 그리고 그게 조용히 일어나기 때문에, 외부 탐지가 없으면 며칠을 모를 수 있습니다.
체크: ① compose 전 서비스
unless-stopped② 정책 감사 ③ 외부 데드맨 — 셋 다 있어야 안심입니다.
같은 원인의 사고 두 건을 회고하며 정리했습니다.