Home Linux AWS Cloud Docker Python AI
클릭하여 터미널 활성화

Docker 인프라 백업 자동화 스크립트 구축 Shell + Cron으로 매일 자동 백업

// Backup · Shell Script · Cron · Docker · Rocky Linux · 자동화
Docker 인프라 환경의 설정 파일, Docker 볼륨, 시스템 보안 설정을 자동으로 백업하는 스크립트를 구축하고, cron으로 매일 새벽 3시에 자동 실행되도록 설정했다.
📋 이 글에서 다루는 것
Docker 설정 파일(docker-compose, nginx.conf, SSL 인증서 등)을 자동 백업하는 Shell 스크립트
Prometheus, Grafana, Loki의 Docker 볼륨 데이터를 Alpine 컨테이너로 백업하는 방법
SSH 보안 설정, Fail2ban 규칙, 방화벽 스냅샷 등 시스템 설정 백업
cron으로 매일 새벽 3시 자동 실행 + 7일 이상 된 백업 자동 삭제 정책
백업 파일로부터 전체/개별 복원하는 Recovery 절차
1. Overview — 왜 백업이 필요한가

지금까지 Docker + Nginx + Prometheus + Grafana + Loki + HTTPS까지 구축했다. 설정 파일이 10개가 넘고, Docker 볼륨에는 대시보드·메트릭 데이터·로그가 쌓여 있다. 이걸 다 날리면 처음부터 다시 해야 한다. 서버 디스크 장애, 잘못된 docker compose down -v(볼륨까지 삭제), 설정 파일 실수 — 어느 하나만 터져도 몇 시간짜리 복구 작업이 된다.

그래서 매일 새벽 3시에 자동으로 전체 백업을 돌리고, 7일치만 보관하고 나머지는 삭제하는 자동화 스크립트를 만든다.

#항목BeforeAfter
1백업 스크립트없음NEW /opt/backups/backup.sh
2자동 실행없음NEW cron 매일 03:00
3Docker 설정 백업미보호docker-lab + monitoring 설정 전체
4Docker 볼륨 백업미보호Prometheus, Grafana, Loki 데이터
5시스템 설정 백업미보호SSH, Fail2ban, 방화벽 규칙
6보존 정책없음NEW 7일 이상 자동 삭제
7백업 로깅없음NEW /opt/backups/backup.log

2. Backup Architecture

백업 스크립트는 크게 세 종류의 데이터를 수집한다: Docker 설정 파일, Docker 볼륨 데이터, 시스템 보안 설정. 이 세 가지를 하나의 tar.gz 파일로 압축하고, 7일 이상 된 파일은 자동 삭제한다.

[Cron — 매일 03:00][/opt/backups/backup.sh] │ ├── 1. Docker 설정 파일 복사 │ ├── /opt/docker-lab/ (docker-compose, nginx.conf, Dockerfile, app.py, ssl/) │ └── /opt/monitoring/ (docker-compose, prometheus.yml, loki-config, promtail-config) │ ├── 2. Docker 볼륨 백업 (Alpine 컨테이너 활용) │ ├── monitoring_prometheus_data │ ├── monitoring_grafana_data │ └── monitoring_loki_data │ ├── 3. 시스템 설정 백업 │ ├── /etc/ssh/sshd_config.d/99-security.conf │ ├── /etc/fail2ban/jail.local │ ├── /root/user_manage.sh │ └── firewall-rules.txt (현재 방화벽 규칙 덤프) │ ├── 4. tar.gz 압축 → /opt/backups/backup_날짜.tar.gz │ ├── 5. 7일 이상 된 백업 자동 삭제 │ └── 6. 로그 기록 → /opt/backups/backup.log

3. 백업 대상 상세
Docker 설정 파일

이 파일들은 인프라 전체를 정의하는 설계도다. 이게 없으면 컨테이너를 다시 띄울 수 없다. 이전 글들에서 하나하나 만들었던 파일들이 전부 여기 포함된다.

경로파일역할
/opt/docker-lab/docker-compose.yml웹 서비스 스택 정의 (Nginx + Backend)
/opt/docker-lab/nginx.confNginx HTTPS + 리버스 프록시 설정
/opt/docker-lab/DockerfilePython 백엔드 이미지 빌드 스크립트
/opt/docker-lab/app.pyPython API 서버 코드
/opt/docker-lab/index.html프론트엔드 페이지
/opt/docker-lab/ssl/server.crt, server.keySSL 인증서 + 개인키
/opt/monitoring/docker-compose.yml모니터링 스택 정의 (8개 서비스)
/opt/monitoring/prometheus.ymlPrometheus 스크래핑 설정
/opt/monitoring/loki-config.ymlLoki 로그 저장 설정
/opt/monitoring/promtail-config.ymlPromtail 로그 수집 설정
Docker 볼륨

Docker Named Volume은 컨테이너가 삭제돼도 데이터가 남는 영속 저장소다. 하지만 docker compose down -v를 실행하면 볼륨까지 같이 날아간다. Grafana에서 몇 시간 걸려 만든 대시보드, Prometheus에 쌓인 메트릭 데이터, Loki의 로그가 전부 사라진다. 그래서 볼륨 백업이 필요하다.

볼륨명서비스데이터 내용
monitoring_prometheus_dataPrometheus시계열 메트릭 데이터 (TSDB)
monitoring_grafana_dataGrafana대시보드, 데이터소스, 사용자 설정
monitoring_loki_dataLoki수집된 로그 데이터 + 인덱스
💡 왜 Alpine 컨테이너를 쓰나? — Docker 볼륨은 호스트에서 직접 접근하기 어렵다. 볼륨을 마운트한 임시 Alpine 컨테이너를 띄워서, 컨테이너 내부에서 tar로 압축하는 게 공식 권장 방식이다. Alpine은 5MB짜리 초경량 이미지라 부담이 없다.
시스템 설정

이전 글(Rocky Linux 서버 보안 설정)에서 구성한 SSH 보안, Fail2ban, 방화벽 규칙도 백업해야 한다. 서버를 재설치하면 이 설정들도 전부 날아가기 때문이다. 방화벽 규칙은 파일이 아니라 런타임 상태이므로 firewall-cmd --list-all로 텍스트 덤프를 뜬다.

파일역할
/etc/ssh/sshd_config.d/99-security.confSSH 보안 설정 (루트 로그인 차단, 비밀번호 인증 비활성화 등)
/etc/fail2ban/jail.local침입 방지 규칙 (SSH 브루트포스 차단)
/root/user_manage.sh사용자 관리 자동화 스크립트
firewall-rules.txt현재 방화벽 규칙 스냅샷 (런타임 덤프)

4. Backup Script — 전체 코드

이 스크립트가 /opt/backups/backup.sh이고, 실행 권한 755로 설정한다. 핵심 동작은 임시 디렉토리에 모든 파일을 모은 뒤 한 번에 tar.gz로 압축하는 것이다. 왜 임시 디렉토리를 쓰냐면, mktemp -d로 만들면 고유한 경로가 보장되어서 동시에 두 번 실행돼도 충돌하지 않고, 스크립트가 중간에 실패해도 임시 파일이 원래 디렉토리를 오염시키지 않는다.

/opt/backups/backup.sh
#!/bin/bash
# Rocky Linux Infrastructure Backup Script
# 매일 자동 실행 (cron)

BACKUP_DIR=/opt/backups
DATE=$(date '+%Y%m%d_%H%M%S')
BACKUP_FILE="backup_${DATE}.tar.gz"
LOG_FILE="${BACKUP_DIR}/backup.log"

log() {
    echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" >> "$LOG_FILE"
}

log "===== Backup Start ====="

# 1. Docker 설정 파일 백업
TEMP_DIR=$(mktemp -d)
mkdir -p "${TEMP_DIR}/docker-lab"
mkdir -p "${TEMP_DIR}/monitoring"

# docker-lab 설정
cp /opt/docker-lab/docker-compose.yml "${TEMP_DIR}/docker-lab/"
cp /opt/docker-lab/nginx.conf "${TEMP_DIR}/docker-lab/"
cp /opt/docker-lab/Dockerfile "${TEMP_DIR}/docker-lab/"
cp /opt/docker-lab/app.py "${TEMP_DIR}/docker-lab/"
cp /opt/docker-lab/index.html "${TEMP_DIR}/docker-lab/"
cp -r /opt/docker-lab/ssl "${TEMP_DIR}/docker-lab/"

# monitoring 설정
cp /opt/monitoring/docker-compose.yml "${TEMP_DIR}/monitoring/"
cp /opt/monitoring/prometheus.yml "${TEMP_DIR}/monitoring/"
cp /opt/monitoring/loki-config.yml "${TEMP_DIR}/monitoring/"
cp /opt/monitoring/promtail-config.yml "${TEMP_DIR}/monitoring/"

log "Config files copied"

# 2. Docker 볼륨 백업
docker run --rm \
  -v monitoring_prometheus_data:/source/prometheus:ro \
  -v monitoring_grafana_data:/source/grafana:ro \
  -v monitoring_loki_data:/source/loki:ro \
  -v "${TEMP_DIR}:/backup" \
  alpine tar czf /backup/volumes.tar.gz -C /source .

log "Docker volumes backed up"

# 3. 시스템 설정 백업
mkdir -p "${TEMP_DIR}/system"
cp /etc/ssh/sshd_config.d/99-security.conf "${TEMP_DIR}/system/" 2>/dev/null
cp /etc/fail2ban/jail.local "${TEMP_DIR}/system/" 2>/dev/null
cp /root/user_manage.sh "${TEMP_DIR}/system/" 2>/dev/null
firewall-cmd --list-all > "${TEMP_DIR}/system/firewall-rules.txt" 2>/dev/null

log "System configs backed up"

# 4. 압축
tar czf "${BACKUP_DIR}/${BACKUP_FILE}" -C "${TEMP_DIR}" .
rm -rf "${TEMP_DIR}"

log "Archive created: ${BACKUP_FILE}"

# 5. 7일 이상 된 백업 삭제
find "${BACKUP_DIR}" -name "backup_*.tar.gz" -mtime +7 -delete
DELETED=$(find "${BACKUP_DIR}" -name "backup_*.tar.gz" -mtime +7 2>/dev/null | wc -l)
log "Old backups cleaned (deleted: ${DELETED})"

# 6. 백업 파일 크기 기록
SIZE=$(du -sh "${BACKUP_DIR}/${BACKUP_FILE}" | cut -f1)
log "Backup size: ${SIZE}"
log "===== Backup Complete ====="

echo "Backup complete: ${BACKUP_FILE} (${SIZE})"
스크립트 동작 순서
단계동작왜 필요한가
1임시 디렉토리 생성mktemp -d로 고유 경로 보장 — 동시 실행 충돌 방지
2설정 파일 복사docker-lab, monitoring 설정 파일을 한 곳에 수집
3Docker 볼륨 백업Alpine 컨테이너로 볼륨 데이터를 tar 압축 — 호스트에서 직접 접근 불가하므로
4시스템 설정 복사SSH, Fail2ban, 방화벽 규칙 — 서버 재설치 시 필요
5전체 압축수집한 모든 파일을 하나의 tar.gz로 묶어 관리 용이
6임시 디렉토리 삭제디스크 낭비 방지
7오래된 백업 삭제7일 초과 파일 자동 제거 — 디스크 가득 차는 것 방지
8로그 기록백업 성공/실패를 추적할 수 있도록
⚠️ 2>/dev/null 의미 — 시스템 설정 파일 복사 시 2>/dev/null을 붙인 이유는 해당 파일이 없을 수도 있기 때문이다. Fail2ban을 아직 설치 안 했거나, SSH 보안 설정을 안 했으면 에러가 나지만 스크립트가 중단되지 않고 넘어간다.

5. Cron Job 설정

스크립트를 만들었으면 매일 자동으로 실행되게 해야 한다. /etc/cron.d/ 디렉토리에 파일을 만드는 방식이 crontab -e보다 관리하기 좋다 — 파일 단위로 관리하면 어떤 cron이 설정되어 있는지 한눈에 보이고, 버전 관리(Git)도 가능하다.

설정 파일

/etc/cron.d/infrastructure-backup — 이 파일 이름은 자유지만, 무슨 작업인지 알 수 있는 이름이 좋다.

/etc/cron.d/infrastructure-backup
0 3 * * * root /opt/backups/backup.sh
스케줄 해석
필드의미
0정각
3새벽 3시
*매일
*매월
요일*모든 요일
사용자rootroot 권한으로 실행 (Docker + 시스템 파일 접근 필요)
💡 왜 새벽 3시인가? — 서버 사용량이 가장 적은 시간대에 백업을 돌린다. Docker 볼륨 백업 시 Alpine 컨테이너가 볼륨을 :ro(읽기 전용)로 마운트하기 때문에 서비스에 영향을 주지 않지만, I/O 부하를 최소화하기 위해 비피크 시간을 선택하는 게 좋다.

6. Setup — 설치 명령어
설치
# 1. 백업 디렉토리 생성
$ sudo mkdir -p /opt/backups

# 2. 백업 스크립트 생성 (위 코드 작성)
$ sudo vi /opt/backups/backup.sh

# 3. 실행 권한 부여
$ sudo chmod 755 /opt/backups/backup.sh

# 4. cron 작업 등록
$ echo '0 3 * * * root /opt/backups/backup.sh' | sudo tee /etc/cron.d/infrastructure-backup

# 5. 테스트 실행
$ sudo /opt/backups/backup.sh
💡 chmod 755의 의미 — 소유자는 읽기+쓰기+실행, 그룹과 기타 사용자는 읽기+실행. cron이 root로 실행하므로 소유자 실행 권한이 필수다. 644로 설정하면 실행 권한이 없어서 cron이 동작하지 않는다.

7. Verification — 테스트 실행
실행 결과
테스트
$ sudo /opt/backups/backup.sh
Backup complete: backup_20260308_201445.tar.gz (22M)
백업 파일 확인
확인
$ ls -lah /opt/backups/backup_*.tar.gz
-rw-r--r--. 1 root root 22M Mar  8 20:14 /opt/backups/backup_20260308_201445.tar.gz
백업 로그
backup.log
[2026-03-08 20:14:50] ===== Backup Start =====
[2026-03-08 20:14:50] Config files copied
[2026-03-08 20:14:57] Docker volumes backed up
[2026-03-08 20:14:57] System configs backed up
[2026-03-08 20:14:57] Archive created: backup_20260308_201445.tar.gz
[2026-03-08 20:14:57] Old backups cleaned (deleted: 0)
[2026-03-08 20:14:57] Backup size: 22M
[2026-03-08 20:14:57] ===== Backup Complete =====
✓ 전체 백업 완료 — 설정 파일 복사, Docker 볼륨 백업, 시스템 설정 백업, 압축, 클린업까지 7초 만에 완료. 백업 파일 크기 22MB.
백업 파일 내부 구조
tar tzf backup_20260308_201445.tar.gz
backup_20260308_201445.tar.gz
├── docker-lab/
│   ├── docker-compose.yml
│   ├── nginx.conf
│   ├── Dockerfile
│   ├── app.py
│   ├── index.html
│   └── ssl/
│       ├── server.crt
│       └── server.key
├── monitoring/
│   ├── docker-compose.yml
│   ├── prometheus.yml
│   ├── loki-config.yml
│   └── promtail-config.yml
├── system/
│   ├── 99-security.conf
│   ├── jail.local
│   ├── user_manage.sh
│   └── firewall-rules.txt
└── volumes.tar.gz
    ├── prometheus/  (Prometheus TSDB 데이터)
    ├── grafana/     (대시보드, 설정)
    └── loki/        (로그 데이터)

8. Retention Policy — 보존 정책

find -mtime +7 -delete는 "수정 시간이 7일을 초과한 파일을 삭제"하는 명령이다. 백업 파일이 매일 22MB씩 쌓이면 7일 기준 약 154MB만 차지한다. 보존 기간을 늘리고 싶으면 +7+30으로 바꾸면 된다.

항목설정
보존 기간7일
삭제 방식find -mtime +7 -delete
실행 시점백업 완료 후 자동 실행
예상 디스크 사용량약 22MB x 7일 = ~154MB

9. Recovery Procedure — 복원 절차

백업은 복원할 수 있어야 의미가 있다. 전체 복원과 개별 파일 복원 두 가지 시나리오를 정리한다.

전체 복원
전체 복원 절차
# 백업 파일 압축 해제
$ cd /tmp
$ tar xzf /opt/backups/backup_YYYYMMDD_HHMMSS.tar.gz

# 1. Docker 설정 파일 복원
$ sudo cp -r docker-lab/* /opt/docker-lab/
$ sudo cp -r monitoring/* /opt/monitoring/

# 2. 시스템 설정 복원
$ sudo cp system/99-security.conf /etc/ssh/sshd_config.d/
$ sudo cp system/jail.local /etc/fail2ban/
$ sudo cp system/user_manage.sh /root/
$ sudo systemctl restart sshd fail2ban

# 3. Docker 볼륨 복원
# ⚠️ 주의: 기존 볼륨 데이터가 삭제됨
$ cd /opt/monitoring && docker compose down
$ docker volume rm monitoring_prometheus_data monitoring_grafana_data monitoring_loki_data

# 볼륨 재생성 및 데이터 복원
$ docker volume create monitoring_prometheus_data
$ docker volume create monitoring_grafana_data
$ docker volume create monitoring_loki_data

$ docker run --rm \
  -v monitoring_prometheus_data:/target/prometheus \
  -v monitoring_grafana_data:/target/grafana \
  -v monitoring_loki_data:/target/loki \
  -v /tmp:/backup:ro \
  alpine sh -c "tar xzf /backup/volumes.tar.gz -C /target"

# 4. 서비스 재시작
$ cd /opt/docker-lab && docker compose up -d
$ cd /opt/monitoring && docker compose up -d
❌ 주의docker volume rm은 기존 볼륨 데이터를 완전히 삭제한다. 복원 전에 현재 데이터가 정말 필요 없는지 확인하고 실행해야 한다.
개별 파일 복원

전체 복원이 아니라 특정 파일 하나만 꺼내고 싶을 때는 tar에 경로를 지정하면 된다.

개별 복원
# nginx.conf만 추출
$ tar xzf /opt/backups/backup_YYYYMMDD_HHMMSS.tar.gz docker-lab/nginx.conf

# prometheus.yml만 추출
$ tar xzf /opt/backups/backup_YYYYMMDD_HHMMSS.tar.gz monitoring/prometheus.yml

10. File Structure
백업 관련 파일
/opt/backups/
├── backup.sh                          # 백업 스크립트 (755)
├── backup.log                         # 백업 실행 로그
└── backup_20260308_201445.tar.gz      # 백업 파일 (22MB)

/etc/cron.d/
└── infrastructure-backup              # cron 작업 정의

11. Management Commands
관리 명령어 모음
# 수동 백업 실행
$ sudo /opt/backups/backup.sh

# 백업 로그 확인
$ cat /opt/backups/backup.log

# 백업 파일 목록 확인
$ ls -lah /opt/backups/backup_*.tar.gz

# 백업 파일 내용 확인 (압축 해제 없이)
$ tar tzf /opt/backups/backup_YYYYMMDD_HHMMSS.tar.gz

# cron 작업 확인
$ cat /etc/cron.d/infrastructure-backup

# 디스크 사용량 확인
$ du -sh /opt/backups/

12. 프로덕션 권장 사항

현재 구성은 단일 서버 로컬 백업이다. 서버 자체가 날아가면 백업도 같이 날아간다. 프로덕션 환경에서는 아래 사항을 추가로 적용해야 한다.

항목권장 사항왜 필요한가
원격 백업rsync/scp로 외부 서버에 백업 복사서버 장애 시 로컬 백업도 유실되므로
백업 암호화gpg 또는 openssl로 백업 파일 암호화SSL 개인키 등 민감 정보 포함
백업 무결성sha256sum 체크섬 파일 생성전송 중 파일 손상 감지
알림백업 실패 시 텔레그램/이메일 알림실패를 모르고 지나치면 의미 없음
증분 백업전체 백업 + 증분 백업 조합볼륨 데이터가 커지면 디스크/시간 절약
복원 테스트정기적 복원 테스트복원이 안 되는 백업은 백업이 아님
모니터링Prometheus에서 백업 디스크 사용량 추적디스크 가득 차기 전에 감지
⚠️ 핵심 — "백업은 했는데 복원을 안 해봤다" = 백업이 없는 것과 같다. 정기적으로 백업 파일에서 실제로 복원해보는 테스트가 반드시 필요하다.

13. 자주 묻는 질문 (FAQ)
Q. 백업 중에 서비스가 중단되나?
아니다. Docker 볼륨 백업 시 Alpine 컨테이너가 볼륨을 :ro(읽기 전용)로 마운트하기 때문에 기존 서비스 컨테이너는 정상 동작한다. 다만 볼륨 데이터의 쓰기가 진행 중인 시점의 스냅샷이므로, 극히 일부 데이터가 불완전할 수 있다. 이를 방지하려면 서비스를 잠시 중지하고 백업하는 "콜드 백업" 방식을 써야 한다.
Q. 볼륨 데이터가 커지면 백업 시간이 오래 걸리지 않나?
현재 22MB 기준 7초면 끝난다. 하지만 Prometheus에 메트릭이 수개월 쌓이거나, Loki에 로그가 대량으로 쌓이면 수 GB까지 커질 수 있다. 이 경우 증분 백업(rsync --link-dest)이나 볼륨별 스냅샷을 고려해야 한다.
Q. cron이 제대로 동작하는지 어떻게 확인하나?
cat /opt/backups/backup.log에서 매일 03:00에 로그가 찍히는지 확인한다. 또는 grep CRON /var/log/cron으로 cron 데몬의 실행 기록을 확인할 수 있다. cron 파일 권한이 잘못되면(너무 넓은 퍼미션) cron이 무시하므로, /etc/cron.d/ 파일은 644로 설정하고 소유자는 root여야 한다.
Q. 서버가 완전히 날아갔을 때 백업만으로 복구할 수 있나?
OS 설치와 Docker 설치는 직접 해야 하지만, 그 이후는 백업 파일만으로 전체 인프라를 복원할 수 있다. 설정 파일을 복사하고, 볼륨을 복원하고, docker compose up -d를 실행하면 된다. 단, 현재 구성은 로컬 백업이라 서버 디스크가 날아가면 백업도 함께 유실되므로, 반드시 원격 백업을 추가해야 한다.
Q. 백업 파일에 SSL 개인키가 포함되는데 보안 문제는 없나?
server.key(SSL 개인키)가 백업에 포함된다. 백업 파일이 유출되면 SSL 암호화가 무력화될 수 있다. 프로덕션에서는 gpg -c backup_날짜.tar.gz로 백업 파일 자체를 암호화하거나, 원격 전송 시 반드시 암호화된 채널(scp, rsync over SSH)을 사용해야 한다.

📌 이 글 핵심 요약
Shell 스크립트로 Docker 설정 파일 + 볼륨 데이터 + 시스템 보안 설정을 한 번에 백업한다
Docker 볼륨은 Alpine 컨테이너를 활용해 :ro 마운트 후 tar 압축하는 공식 권장 방식을 사용한다
cron으로 매일 새벽 3시 자동 실행, 7일 이상 된 백업은 자동 삭제하여 디스크 관리
복원은 tar로 압축 해제 후 파일 복사 + 볼륨 재생성 + docker compose up으로 완료
프로덕션에서는 원격 백업, 암호화, 정기 복원 테스트를 반드시 추가해야 한다