☁️ 🏗️

클라우드/인프라 엔지니어가 되는 과정을 기록합니다.

홈서버 구축 일지

[14] "컨테이너가 갑자기 죽어버리면...?" - 자동 복구 설정하기 🛠️

d4eh0 2026. 5. 19. 14:02
Keyword : healthcheck, Actuator, restart policy, container, docker-compose, log

 

현재 홈서버는 시스템 재시작 시 컨테이너가 자동으로 복구되지 않는 문제가 있다.

CI/CD와 파이프라인을 구축하기전에
먼저 서버가 기본적으로 운영 가능한 상태인지 점검하고 개선했다.

완성 아키텍처

 


문제 상황 - 시스템 재시작 시 컨테이너가 자동으로 안뜸

 

본격적인 홈서버 고도화 및 애플리케이션 운영을 위해

오랜만에 노트북을 켜고 docker ps -a를 실행했다.

CONTAINER ID   IMAGE                        STATUS
5233ec28cd4a   nginx:alpine                 Exited (0) 2 weeks ago
f9e4d2301194   cloud-termproject-frontend   Exited (0) 2 weeks ago
dc5557dacfec   cloud-termproject-backend3   Exited (143) 2 weeks ago
8e589c249995   cloud-termproject-backend2   Exited (143) 2 weeks ago
1a2c588b4ba5   cloud-termproject-backend1   Exited (143) 2 weeks ago
993b66763044   mysql:8                      Exited (0) 2 weeks ago
...

 

전부 Exited 상태... restart 정책을 확인해봤다.

docker inspect --format='{{.Name}} → {{.HostConfig.RestartPolicy.Name}}' $(docker ps -aq)

/cloud-termproject-nginx-1     → on-failure
/cloud-termproject-frontend-1  → no
/cloud-termproject-backend3-1  → no
/cloud-termproject-backend2-1  → no
/cloud-termproject-backend1-1  → no
/cloud-termproject-mysql-1     → no
...

 

현재 nginx 하나만 on-failure고 나머지는 전부 no(기본값)이다.

systemctl을 통해 Docker 데몬 자체는 부팅 시 자동시작이 설정돼 있었지만,

컨테이너 restart 정책이 no라서 아무것도 살아나지 않은 것이다.

 

결국 서버가 재부팅되면? 컨테이너가 죽으면?

아무것도 자동으로 대응이 안되고 있는게 현재 상태다.


Step1 . 컨테이너 restart 정책 변경 → "unless-stopped"

Docker의 restart 정책은 4가지다.

정책 동작
no 절대 재시작 안 함 (기본값)
on-failure 에러 코드로 종료됐을 때만 재시작
always 항상 재시작 (수동 stop 후에도)
unless-stopped 수동으로 stop하지 않는 한 항상 재시작

 

always는 내가 docker stop으로 의도적으로 껐어도 재시작해버리는 문제가 있다.

unless-stopped 정책이 운영에 맞다고 판단했다.

# docker-compose.yml 모든 서비스마다 적용

restart: unless-stopped

Step 2. healthcheck 체인과 depends_on 강화

# 기존 nginx depends_on
depends_on:
  backend1:
    condition: service_started   # 프로세스가 시작됐나만 확인

 

기존 depends_on인 service_started는 컨테이너 프로세스가 켜졌는지만 본다.

실상은 Spring Boot는 JVM이 뜨고 DB 연결을 맺고 완전히 준비시간을 고려하지 않고있다.

만약 그 사이에 nginx가 먼저 올라와서 아직 준비되지 않은 backend로 트래픽을 보내면 502 에러가 터진다.

 

service_started 대신 service_healthy를 쓰면

healthcheck가 통과할 때까지 다음 서비스가 기다린다.

 

MySQL healthcheck :: mysqladmin ping 활용

mysql:
  healthcheck:
    test: ["CMD", "mysqladmin", "ping", "-h", "localhost", "-u", "root", "-p${MYSQL_ROOT_PASSWORD}"]
    interval: 10s
    timeout: 5s
    retries: 5
    start_period: 30s

# mysqladmin ping으로 DB가 실제로 응답하는지 확인한다.

 

Backend healthcheck : Actuator 활용

backend1:
  healthcheck:
    test: ["CMD", "curl", "-f", "http://localhost:8080/actuator/health"]
    interval: 10s
    timeout: 5s
    retries: 5
    start_period: 60s

 

Spring Boot Actuator의 /actuator/health 엔드포인트를 활용한다.

Actuator는 Spring Boot 앱의 내부 상태를 외부에 HTTP로 노출시켜주는 도구다. 여러 엔드포인트를 제공한다.

엔드포인트 역할
/actuator/health 앱 생존 여부, DB 연결 상태 확인
/actuator/metrics CPU, 메모리, 요청 수 등 수치 데이터
/actuator/prometheus Prometheus가 읽을 수 있는 형식으로 메트릭 제공

 

기존에 Actuator를 설치하여 /actuator/prometheus

Prometheus가 메트릭을 긁어갈 수 있는 환경을 만들었었다.

 

이번엔 /actuator/health를 통해

Docker healthcheck 용도로 활용하는 것이다.

 

depends_on 체인 강화

# backend: mysql이 healthy할 때까지 대기
backend1:
  depends_on:
    mysql:
      condition: service_healthy

# frontend: backend 3개 모두 healthy할 때까지 대기
frontend:
  depends_on:
    backend1:
      condition: service_healthy
    backend2:
      condition: service_healthy
    backend3:
      condition: service_healthy

# nginx: frontend까지 healthy할 때까지 대기
nginx:
  depends_on:
    frontend:
      condition: service_healthy
    backend1:
      condition: service_healthy
    backend2:
      condition: service_healthy
    backend3:
      condition: service_healthy

Step 3.  로그 용량 제한

Docker는 기본적으로 /var/lib/docker/containers/ 아래에 컨테이너 로그를 무한정 쌓는다

즉, 서버를 오래 돌리면 디스크가 꽉 차서 서버가 죽는다.

# 모든 서비스에 적용
logging:
  driver: json-file
  options:
    max-size: "10m"   # 파일 하나당 최대 10MB
    max-file: "3"     # 최대 3개 파일 유지

 

이제 파일 하나가 10MB를 초과하면 자동으로 순환된다.

최대 30MB(10MB × 3개)까지만 유지된다.


결과 확인

 

확인결과 depends_on 체인이 순서대로 정확하게 동작했다.

mysql Healthy (6.9s)
  → backend1/2/3 Healthy (45.7s)
    → frontend Healthy (50.4s)
      → nginx Started (50.5s)

 


정리

항목 Before After
restart 정책 nginx만 on-failure, 나머지 no 전체 unless-stopped
healthcheck frontend만 존재 mysql/backend/frontend 전체
depends_on service_started service_healthy
로그 관리 무한 누적 최대 30MB 자동 순환

 

서버 운영의 기본기가 잡혔다.

다음은 Jenkins를 통한 CI/CD 파이프라인 구축을 다뤄보고자 한다.