Docker 서버 부팅 시 컨테이너 자동 실행 – 5가지 방법으로 완벽 정복

새벽 3시, 서버가 예기치 않게 재부팅되었습니다. 아침에 출근해보니 웹사이트가 다운되어 있고, 데이터베이스도 멈춰있습니다. 수동으로 모든 컨테이너를 하나씩 시작해야 하는 악몽 같은 상황… 이런 일은 다시 겪고 싶지 않으시죠? Docker 컨테이너 자동 실행 설정 한 번이면 이 모든 문제가 해결됩니다.


Table of Contents

왜 컨테이너 자동 실행이 필수일까?

실무 통계에 따르면, 서버 재부팅 후 수동 복구 시간은 평균 15-30분이 소요됩니다. 이는 곧 서비스 다운타임을 의미하죠. 연간 예상치 못한 재부팅은 평균 3-5회 발생하며, 자동 실행 설정이 없다면 매번 긴급 대응이 필요합니다.


Docker 기본 동작의 함정

많은 개발자가 놓치는 사실이 있습니다. Docker 컨테이너는 기본적으로 서버 재부팅 시 자동으로 시작되지 않습니다. 컨테이너 상태가 “Exited”로 남아있죠.

# 재부팅 후 컨테이너 상태 확인
docker ps -a

# 출력 예시
CONTAINER ID   STATUS                    NAMES
a1b2c3d4e5f6   Exited (0) 2 hours ago   web-server
b2c3d4e5f6g7   Exited (0) 2 hours ago   database

이 문제를 해결하는 5가지 방법을 알아보겠습니다.


방법 1: restart 정책으로 완벽한 자동화 (가장 권장)

Docker의 restart 정책은 컨테이너 재시작 동작을 제어하는 가장 강력한 도구입니다.

4가지 restart 정책 완전 분석

1) no (기본값)

docker run --restart=no --name test-app nginx

  • 어떤 경우에도 자동 재시작 안 함
  • 개발 환경이나 일회성 작업에 적합
  • 프로덕션에는 절대 사용 금지

2) on-failure

docker run --restart=on-failure:5 --name api-server node-app

  • 컨테이너가 오류로 종료될 때만 재시작
  • :5는 최대 5번까지만 재시도
  • 디버깅이 필요한 초기 배포 단계에 유용
  • 종료 코드가 0이 아닐 때만 작동

3) always

docker run --restart=always --name web-server -d -p 80:80 nginx

  • 서버 재부팅, 도커 재시작, 수동 중지 후에도 항상 재시작
  • 가장 강력하지만 주의 필요
  • 중지하려면 docker stopdocker update --restart=no 필수

4) unless-stopped (실무 최고 권장)

docker run --restart=unless-stopped --name prod-database -d postgres:14

  • always와 거의 동일하지만 수동 중지는 존중
  • 개발자가 의도적으로 멈춘 컨테이너는 재부팅 후에도 중지 상태 유지
  • 프로덕션 환경 베스트 프랙티스


실전 시나리오별 적용법

시나리오 1: 웹 서버 자동 실행

# Nginx 웹서버를 무조건 실행 상태로 유지
docker run -d \\
  --name production-webserver \\
  --restart=unless-stopped \\
  -p 80:80 \\
  -p 443:443 \\
  -v /etc/nginx/conf.d:/etc/nginx/conf.d \\
  nginx:latest

# 설정 확인
docker inspect production-webserver | grep -A 5 RestartPolicy

시나리오 2: 데이터베이스 클러스터

# PostgreSQL 데이터베이스 (데이터 보존 필수)
docker run -d \\
  --name postgres-primary \\
  --restart=unless-stopped \\
  -e POSTGRES_PASSWORD=secure_password \\
  -v postgres-data:/var/lib/postgresql/data \\
  -p 5432:5432 \\
  postgres:14

# 복제본도 동일하게 설정
docker run -d \\
  --name postgres-replica \\
  --restart=unless-stopped \\
  -e POSTGRES_PASSWORD=secure_password \\
  -v postgres-replica-data:/var/lib/postgresql/data \\
  -p 5433:5432 \\
  postgres:14

시나리오 3: 마이크로서비스 아키텍처

# API 게이트웨이
docker run -d --name api-gateway --restart=unless-stopped -p 3000:3000 gateway-app

# 인증 서비스
docker run -d --name auth-service --restart=unless-stopped -p 3001:3000 auth-app

# 결제 서비스
docker run -d --name payment-service --restart=unless-stopped -p 3002:3000 payment-app

# 알림 서비스
docker run -d --name notification-service --restart=unless-stopped -p 3003:3000 notification-app


방법 2: 기존 컨테이너에 정책 추가하기

이미 실행 중인 컨테이너도 재생성 없이 정책을 변경할 수 있습니다.

docker update 명령어 활용

# 단일 컨테이너 정책 변경
docker update --restart=unless-stopped my-container

# 여러 컨테이너 한 번에 변경
docker update --restart=unless-stopped web-server db-server cache-server

# 모든 실행 중인 컨테이너에 적용
docker update --restart=unless-stopped $(docker ps -q)

변경 사항 즉시 확인

# 상세 정보 확인
docker inspect --format='{{.Name}}: {{.HostConfig.RestartPolicy.Name}}' $(docker ps -aq)

# 출력 예시
/web-server: unless-stopped
/database: unless-stopped
/redis: always

정책 제거하기

개발 중 자동 재시작이 방해될 때:

# 자동 재시작 비활성화
docker update --restart=no dev-container

# 컨테이너 중지 (재부팅 후에도 중지 상태 유지)
docker stop dev-container


방법 3: Docker Compose로 체계적 관리 (대규모 환경 필수)

여러 컨테이너를 운영한다면 Docker Compose가 최선의 선택입니다.

완벽한 docker-compose.yml 구성

version: '3.8'

services:
  # 웹 서버 (프론트엔드)
  nginx:
    image: nginx:latest
    container_name: production-nginx
    restart: unless-stopped
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ./nginx.conf:/etc/nginx/nginx.conf
      - ./ssl:/etc/nginx/ssl
    depends_on:
      - api
    networks:
      - app-network
    healthcheck:
      test: ["CMD", "curl", "-f", "<http://localhost/health>"]
      interval: 30s
      timeout: 10s
      retries: 3

  # API 서버 (백엔드)
  api:
    image: node:18
    container_name: production-api
    restart: unless-stopped
    ports:
      - "3000:3000"
    environment:
      - NODE_ENV=production
      - DATABASE_URL=postgresql://postgres:password@postgres:5432/app
    depends_on:
      postgres:
        condition: service_healthy
    volumes:
      - ./api:/app
    working_dir: /app
    command: npm start
    networks:
      - app-network

  # 데이터베이스
  postgres:
    image: postgres:14
    container_name: production-postgres
    restart: unless-stopped
    environment:
      - POSTGRES_USER=postgres
      - POSTGRES_PASSWORD=secure_password_here
      - POSTGRES_DB=app
    volumes:
      - postgres-data:/var/lib/postgresql/data
      - ./init.sql:/docker-entrypoint-initdb.d/init.sql
    ports:
      - "5432:5432"
    networks:
      - app-network
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U postgres"]
      interval: 10s
      timeout: 5s
      retries: 5

  # Redis 캐시
  redis:
    image: redis:7-alpine
    container_name: production-redis
    restart: unless-stopped
    ports:
      - "6379:6379"
    volumes:
      - redis-data:/data
    command: redis-server --appendonly yes
    networks:
      - app-network
    healthcheck:
      test: ["CMD", "redis-cli", "ping"]
      interval: 10s
      timeout: 3s
      retries: 3

  # 모니터링 (Prometheus)
  prometheus:
    image: prom/prometheus
    container_name: monitoring-prometheus
    restart: unless-stopped
    ports:
      - "9090:9090"
    volumes:
      - ./prometheus.yml:/etc/prometheus/prometheus.yml
      - prometheus-data:/prometheus
    command:
      - '--config.file=/etc/prometheus/prometheus.yml'
      - '--storage.tsdb.path=/prometheus'
    networks:
      - app-network

volumes:
  postgres-data:
    driver: local
  redis-data:
    driver: local
  prometheus-data:
    driver: local

networks:
  app-network:
    driver: bridge


Docker Compose 실행 및 관리

# 백그라운드에서 모든 서비스 시작
docker-compose up -d

# 특정 서비스만 재시작
docker-compose restart nginx

# 로그 실시간 확인
docker-compose logs -f api

# 서비스 상태 확인
docker-compose ps

# 모든 서비스 중지 (데이터 보존)
docker-compose stop

# 완전히 제거 (컨테이너 + 네트워크, 볼륨은 보존)
docker-compose down

# 볼륨까지 삭제
docker-compose down -v


restart 정책 테스트하기

# 1. 서비스 시작
docker-compose up -d

# 2. 컨테이너 강제 종료
docker kill production-api

# 3. 자동 재시작 확인 (수초 내 재시작됨)
docker-compose ps

# 4. 서버 재부팅 시뮬레이션
sudo systemctl restart docker

# 5. 모든 컨테이너가 자동으로 시작되는지 확인
docker-compose ps


방법 4: 시스템 서비스로 Docker 관리

Docker 데몬 자체가 부팅 시 시작되도록 시스템 레벨에서 설정합니다.


Docker 서비스 상태 확인 및 활성화

# Docker 서비스 상태 확인
systemctl status docker

# 부팅 시 자동 시작 설정 확인
systemctl is-enabled docker

# 활성화되지 않았다면 활성화
sudo systemctl enable docker

# containerd도 함께 활성화 (Docker의 런타임)
sudo systemctl enable containerd

# 즉시 시작
sudo systemctl start docker
sudo systemctl start containerd


서비스 설정 파일 커스터마이징

고급 사용자를 위한 systemd 설정:

# Docker 서비스 설정 편집
sudo systemctl edit docker

# 다음 내용 추가
[Service]
ExecStartPost=/usr/bin/sleep 10
# Docker가 완전히 시작된 후 10초 대기

# 설정 리로드
sudo systemctl daemon-reload

# Docker 재시작
sudo systemctl restart docker


부팅 순서 관리

데이터베이스가 웹서버보다 먼저 시작되어야 하는 경우:

# docker-compose.yml에서
services:
  web:
    depends_on:
      db:
        condition: service_healthy

  db:
    healthcheck:
      test: ["CMD", "pg_isready"]
      interval: 5s
      timeout: 3s
      retries: 5


방법 5: 커스텀 스크립트로 고급 제어

특별한 요구사항이 있다면 부팅 스크립트를 직접 작성할 수 있습니다.

systemd 서비스 파일 생성

# 서비스 파일 생성
sudo nano /etc/systemd/system/docker-containers.service

# 다음 내용 입력
[Unit]
Description=Docker Containers Auto Start
Requires=docker.service
After=docker.service

[Service]
Type=oneshot
RemainAfterExit=yes
ExecStart=/usr/local/bin/start-containers.sh
ExecStop=/usr/local/bin/stop-containers.sh

[Install]
WantedBy=multi-user.target


시작 스크립트 작성

# 스크립트 파일 생성
sudo nano /usr/local/bin/start-containers.sh

# 스크립트 내용
#!/bin/bash

# Docker가 완전히 시작될 때까지 대기
sleep 10

# 로그 파일 설정
LOG_FILE="/var/log/docker-autostart.log"
echo "$(date): Starting containers..." >> $LOG_FILE

# 프로덕션 컨테이너 시작
CONTAINERS=(
    "production-nginx"
    "production-api"
    "production-postgres"
    "production-redis"
)

for container in "${CONTAINERS[@]}"; do
    if docker ps -a | grep -q "$container"; then
        docker start "$container"
        echo "$(date): Started $container" >> $LOG_FILE
    else
        echo "$(date): Container $container not found" >> $LOG_FILE
    fi
done

# Docker Compose 프로젝트 시작 (필요시)
cd /opt/myapp && docker-compose up -d >> $LOG_FILE 2>&1

echo "$(date): All containers started" >> $LOG_FILE


실행 권한 부여 및 활성화

# 스크립트 실행 권한
sudo chmod +x /usr/local/bin/start-containers.sh

# 서비스 활성화
sudo systemctl enable docker-containers.service

# 테스트
sudo systemctl start docker-containers.service

# 로그 확인
cat /var/log/docker-autostart.log


실전 문제 해결 가이드

컨테이너가 자동으로 시작되지 않는 경우

1단계: restart 정책 확인

docker inspect --format='{{.HostConfig.RestartPolicy.Name}}' container-name

2단계: Docker 데몬 상태 확인

sudo systemctl status docker
sudo journalctl -u docker -n 50

3단계: 컨테이너 로그 분석

docker logs container-name --tail 100

4단계: 헬스체크 확인

docker inspect --format='{{json .State.Health}}' container-name | jq


의존성 문제 해결

데이터베이스가 준비되기 전에 애플리케이션이 시작되는 문제:

# docker-compose.yml
services:
  app:
    depends_on:
      db:
        condition: service_healthy
    restart: unless-stopped

  db:
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U postgres"]
      interval: 5s
      timeout: 5s
      retries: 10
    restart: unless-stopped


부팅 순서 충돌

# Docker 시작 지연 설정
sudo systemctl edit docker

# 추가
[Service]
ExecStartPost=/bin/sleep 15


리소스 부족으로 시작 실패

# 메모리 제한 설정
docker update --memory="2g" --memory-swap="3g" container-name

# CPU 제한
docker update --cpus="1.5" container-name


보안과 안정성 체크리스트

컨테이너 자동 실행 설정 전 반드시 확인하세요.


필수 보안 점검

  • ✅ 민감한 정보는 환경 변수나 시크릿으로 관리하나요?
  • ✅ 컨테이너가 root 권한으로 실행되지 않나요?
  • ✅ 불필요한 포트가 외부에 노출되지 않았나요?
  • ✅ 볼륨 권한이 적절히 설정되었나요?
  • ✅ 헬스체크가 구성되어 있나요?
  • ✅ 리소스 제한이 설정되었나요?


안정성 점검

# 1. 모든 컨테이너의 restart 정책 확인
docker ps --format "table {{.Names}}\\t{{.Status}}\\t{{json .HostConfig.RestartPolicy}}"

# 2. 시스템 리소스 모니터링
docker stats --no-stream

# 3. 디스크 공간 확인
docker system df

# 4. 로그 크기 제한 (무한 증가 방지)
docker run -d \\
  --log-driver json-file \\
  --log-opt max-size=10m \\
  --log-opt max-file=3 \\
  --name app nginx


모니터링과 알림 설정

자동 실행이 제대로 작동하는지 모니터링하는 방법입니다.


간단한 헬스체크 스크립트

#!/bin/bash
# /usr/local/bin/check-containers.sh

EXPECTED_CONTAINERS=(
    "production-nginx"
    "production-api"
    "production-postgres"
)

for container in "${EXPECTED_CONTAINERS[@]}"; do
    if ! docker ps | grep -q "$container"; then
        echo "WARNING: $container is not running!"
        # Slack 알림 또는 이메일 발송
        curl -X POST -H 'Content-type: application/json' \\
            --data "{\\"text\\":\\"Container $container is down!\\"}" \\
            YOUR_SLACK_WEBHOOK_URL
    fi
done


Cron으로 주기적 점검

# crontab 편집
crontab -e

# 5분마다 컨테이너 상태 확인
*/5 * * * * /usr/local/bin/check-containers.sh


프로덕션 환경 베스트 프랙티스 7가지

실무에서 검증된 설정 패턴입니다.

1. 환경별 분리 전략

# production.yml
services:
  app:
    restart: unless-stopped

# development.yml
services:
  app:
    restart: "no"  # 개발 중에는 자동 재시작 비활성화

2. 그레이스풀 셧다운 설정

services:
  app:
    restart: unless-stopped
    stop_grace_period: 30s  # 종료 신호 후 30초 대기
    stop_signal: SIGTERM    # 정상 종료 신호

3. 롤링 업데이트 전략

# 무중단 배포
docker-compose pull
docker-compose up -d --no-deps --build app

4. 백업 자동화

# 매일 자정 데이터베이스 백업
0 0 * * * docker exec postgres-db pg_dump -U postgres mydb > /backups/db_$(date +\\%Y\\%m\\%d).sql

5. 리소스 제한 강제

services:
  app:
    restart: unless-stopped
    deploy:
      resources:
        limits:
          cpus: '1.5'
          memory: 2G
        reservations:
          memory: 512M

6. 네트워크 격리

services:
  frontend:
    networks:
      - public
  backend:
    networks:
      - internal
  database:
    networks:
      - internal  # 외부 접근 차단

7. 로그 로테이션

services:
  app:
    logging:
      driver: "json-file"
      options:
        max-size: "10m"
        max-file: "5"


재부팅 테스트 시나리오

설정이 완료되었다면 반드시 테스트하세요.

완전한 테스트 프로세스

# 1. 현재 상태 기록
docker ps > /tmp/before-reboot.txt

# 2. 서버 재부팅
sudo reboot

# 3. 재부팅 후 로그인하여 확인
docker ps > /tmp/after-reboot.txt

# 4. 차이 비교
diff /tmp/before-reboot.txt /tmp/after-reboot.txt

# 5. 애플리케이션 동작 확인
curl <http://localhost>
curl <http://localhost:3000/health>

# 6. 로그 확인
docker-compose logs --tail=50


시뮬레이션 테스트

# Docker 데몬만 재시작 (서버 재부팅과 유사한 효과)
sudo systemctl restart docker

# 10초 대기
sleep 10

# 컨테이너 상태 확인
docker ps


마무리: 안정적인 운영을 위한 체크리스트

이제 서버 부팅 시 컨테이너 자동 실행을 완벽하게 구성했습니다. 최종 점검:

  • ✅ 모든 프로덕션 컨테이너에 unless-stopped 정책 적용
  • ✅ Docker Compose 파일에 restart 정책 명시
  • ✅ Docker 데몬이 부팅 시 자동 시작되도록 설정
  • ✅ 헬스체크와 의존성 관리 구성
  • ✅ 모니터링과 알림 시스템 구축
  • ✅ 재부팅 테스트 완료
  • ✅ 백업 자동화 설정

더 이상 새벽에 긴급 호출을 받을 일은 없을 겁니다. Docker가 모든 것을 자동으로 처리해주니까요!

궁금한 점이나 특수한 상황이 있다면 댓글로 공유해주세요. 함께 해결해나가요!


참고 자료:

댓글 남기기