Rocky Linux 9 Docker 볼륨 Restic 백업 자동화 방법

·

, ,

서버를 오래 켜두다 보면 업데이트만큼 신경 쓰이는 것이 백업입니다. Oracle Cloud Free Tier ARM 인스턴스에 Rocky Linux 9.x를 올리고 Docker Compose v2로 서비스를 돌려보니, 컨테이너는 다시 만들 수 있어도 볼륨 안의 데이터는 한 번 잃으면 복구가 쉽지 않았습니다.

홈서버 백업 구성 참고 이미지

Docker 홈서버에서 백업할 것

Docker 기반 홈서버에서 지켜야 할 대상은 크게 컨테이너 볼륨, Compose 설정 파일, 데이터베이스 덤프 세 가지입니다.

컨테이너 이미지는 다시 받을 수 있고 컨테이너도 다시 생성할 수 있습니다. 하지만 /var/lib/docker/volumes 안의 앱 데이터나 직접 바인드 마운트한 ./data, ./config 폴더는 서버의 실제 상태에 가깝습니다.

특히 홈서버 서비스 중에는 SQLite, PostgreSQL, MariaDB처럼 데이터베이스를 함께 쓰는 경우가 많습니다. 이런 서비스는 폴더를 그대로 복사하기보다, 가능하면 백업 직전에 덤프 파일을 따로 만든 뒤 함께 백업하는 방식이 더 안전합니다.

Restic을 선택한 이유

Restic은 단일 바이너리로 동작하고, 암호화를 기본으로 지원합니다. S3 호환 저장소, 로컬 디스크, SFTP 같은 백엔드도 폭넓게 사용할 수 있습니다. 개인 홈서버에서는 설정이 과하게 무겁지 않고 복구 명령이 명확한 점이 장점이었습니다.

순위 도구 핵심 강점 총평 평점
1 Restic 암호화 기본, S3 호환 저장소 지원, 명령 구조 단순 홈서버 자동 백업용으로 균형이 좋음 4.7
2 BorgBackup 중복 제거와 압축 효율이 좋음 리눅스 서버 간 백업에는 강하지만 S3 연동은 별도 구성이 필요함 4.4
3 rsync 가볍고 직관적 암호화, 스냅샷, 보존 정책은 직접 설계해야 함 3.8

Rocky Linux 9.x 기준으로는 EPEL을 켜고 설치하는 흐름이 간단합니다.

bash

sudo dnf install -y epel-release
sudo dnf install -y restic
restic version

저장소 초기화와 암호 관리

Restic 저장소는 처음 한 번 초기화해야 합니다. 아래 예시는 로컬 백업 디스크 기준입니다. MinIO 같은 S3 호환 저장소를 쓰더라도 전체 흐름은 비슷합니다.

bash

sudo mkdir -p /backup/restic-repo
sudo chmod 700 /backup/restic-repo

비밀번호는 셸 히스토리에 남기지 않는 편이 좋습니다. 저는 전용 파일을 만들고 권한을 좁혀두는 방식을 씁니다.

bash

sudo mkdir -p /etc/restic
sudo nano /etc/restic/password
sudo chmod 600 /etc/restic/password

초기화는 다음처럼 진행합니다.

bash

sudo restic \
  -r /backup/restic-repo \
  --password-file /etc/restic/password \
  init

S3 호환 저장소를 쓴다면 환경 변수 파일을 따로 둡니다.

bash

sudo nano /etc/restic/env
sudo chmod 600 /etc/restic/env
bash

export AWS_ACCESS_KEY_ID="minio-access-key"
export AWS_SECRET_ACCESS_KEY="minio-secret-key"
export RESTIC_REPOSITORY="s3:http://minio.example.com:9000/restic/home-server"
export RESTIC_PASSWORD_FILE="/etc/restic/password"

이 경우 초기화는 아래처럼 실행합니다.

bash

sudo bash -c 'source /etc/restic/env && restic init'
서버 백업 저장소 구성 참고 이미지

백업 대상 디렉터리 정리

Compose 프로젝트를 /opt/stacks 아래에 모아두면 백업 범위를 잡기 쉽습니다.

bash

/opt/stacks/
  nginx-proxy/
  gitea/
  vaultwarden/
  postgres/

Restic 백업 대상은 처음부터 넓게 잡기보다 복구에 필요한 최소 단위로 정리하는 편이 좋았습니다.

bash

sudo mkdir -p /opt/backups/db

백업 스크립트는 /usr/local/sbin/restic-docker-backup.sh 같은 이름으로 두면 관리하기 편합니다.

bash

#!/usr/bin/env bash
set -euo pipefail

source /etc/restic/env

BACKUP_DATE="$(date +%F_%H-%M-%S)"
DB_BACKUP_DIR="/opt/backups/db"

mkdir -p "$DB_BACKUP_DIR"

docker exec postgres pg_dumpall -U postgres > "$DB_BACKUP_DIR/postgres-$BACKUP_DATE.sql"

restic backup \
  /opt/stacks \
  /opt/backups/db \
  /etc/restic \
  --exclude '/opt/stacks/**/cache' \
  --exclude '/opt/stacks/**/tmp'

restic forget \
  --keep-daily 7 \
  --keep-weekly 4 \
  --keep-monthly 6 \
  --prune

실행 권한을 부여합니다.

bash

sudo chmod 700 /usr/local/sbin/restic-docker-backup.sh

여기서 /etc/restic까지 백업 대상에 넣을지는 선택이 필요합니다. 저장소 비밀번호 파일까지 같이 백업하면 편하지만, 그만큼 관리 포인트도 늘어납니다. 저는 비밀번호는 별도 관리 저장소에 두고, 서버 백업에서는 제외하는 쪽을 더 선호합니다.

컨테이너를 멈춰야 하는 경우

모든 Docker 볼륨을 같은 방식으로 백업하면 복구 시점에 차이가 생깁니다. 파일만 저장하는 서비스는 대체로 무중단 백업이 가능하지만, 데이터베이스가 계속 쓰고 있는 파일은 일관성 문제가 생길 수 있습니다.

순위 방식 핵심 강점 총평 평점
1 DB 덤프 후 무중단 백업 서비스 중단이 거의 없음 PostgreSQL, MariaDB 운영에 가장 현실적인 방식 4.8
2 컨테이너 일시 중지 후 볼륨 백업 파일 상태를 단순하게 맞출 수 있음 개인 서비스라면 새벽 시간대에 적용하기 좋음 4.2
3 실행 중인 볼륨 그대로 백업 구성이 가장 간단함 캐시나 첨부파일 위주 서비스에는 가능하지만 DB에는 주의가 필요함 3.3

예를 들어 Vaultwarden처럼 SQLite를 쓰는 서비스는 백업 시점에 쓰기 작업이 겹칠 수 있습니다. 사용량이 적은 개인 서버라면 잠깐 멈추고 백업하는 편이 더 낫습니다.

bash

cd /opt/stacks/vaultwarden
docker compose stop
sudo bash -c 'source /etc/restic/env && restic backup /opt/stacks/vaultwarden'
docker compose start

반대로 사진, 문서, 설정 파일 중심의 서비스는 Restic으로 디렉터리를 그대로 묶어도 충분한 경우가 많습니다. 다만 데이터베이스는 덤프 파일을 남긴 뒤 백업한다는 기준은 정해두는 편이 좋습니다.

Docker 볼륨 백업 흐름 참고 이미지

systemd timer로 자동 실행하기

Rocky Linux 9.x에서는 cron도 쓸 수 있지만, 로그 확인과 실행 상태 관리까지 생각하면 systemd timer가 더 깔끔합니다.

서비스 파일을 만듭니다.

bash

sudo nano /etc/systemd/system/restic-docker-backup.service
ini

[Unit]
Description=Restic Docker volume backup

[Service]
Type=oneshot
ExecStart=/usr/local/sbin/restic-docker-backup.sh

타이머 파일도 추가합니다.

bash

sudo nano /etc/systemd/system/restic-docker-backup.timer
ini

[Unit]
Description=Run Restic Docker backup every day

[Timer]
OnCalendar=*-*-* 03:30:00
Persistent=true
Unit=restic-docker-backup.service

[Install]
WantedBy=timers.target

활성화는 아래처럼 합니다.

bash

sudo systemctl daemon-reload
sudo systemctl enable --now restic-docker-backup.timer
systemctl list-timers restic-docker-backup.timer

로그는 이 명령으로 확인합니다.

bash

journalctl -u restic-docker-backup.service -n 100 --no-pager

cron으로 단순하게 처리하고 싶다면 아래 방식도 가능합니다.

bash

sudo crontab -e
cron

30 3 * * * /usr/local/sbin/restic-docker-backup.sh >> /var/log/restic-docker-backup.log 2>&1

cron은 단순하지만 실패 원인을 좁혀볼 때 systemd보다 손이 더 갑니다. 그래서 저는 홈서버 백업 자동화는 systemd timer 쪽이 관리하기 편하다고 느꼈습니다.

복구 테스트까지 확인하기

백업 명령이 성공했다고 끝내면 불안합니다. 실제로는 스냅샷 목록을 보고, 일부 파일을 임시 경로에 복원해보는 과정까지 확인해야 합니다.

bash

sudo bash -c 'source /etc/restic/env && restic snapshots'

최신 스냅샷의 내용을 확인합니다.

bash

sudo bash -c 'source /etc/restic/env && restic ls latest'

임시 디렉터리에 복구합니다.

bash

sudo mkdir -p /tmp/restic-restore-test
sudo bash -c 'source /etc/restic/env && restic restore latest --target /tmp/restic-restore-test'

DB 덤프 파일이 들어왔는지도 확인합니다.

bash

ls -lh /tmp/restic-restore-test/opt/backups/db

복구 테스트가 끝나면 임시 파일을 정리합니다.

bash

sudo rm -rf /tmp/restic-restore-test
백업 복구 테스트 참고 이미지

운영 기준 정리

Oracle Cloud Free Tier ARM에 Rocky Linux 9.x, Docker Compose v2 조합이라면 백업 자동화 자체는 크게 복잡하지 않습니다. 중요한 것은 도구보다 기준이었습니다. 무엇을 백업할지, 언제 멈출지, 실제로 복구되는지를 정해두면 Restic은 그 흐름을 안정적으로 받쳐줍니다.

저는 Compose 파일과 볼륨 데이터, DB 덤프를 함께 묶고 systemd timer로 매일 새벽 실행합니다. 그리고 가끔 restic restore로 직접 꺼내봅니다. 홈서버는 결국 혼자 관리하는 작은 운영 환경이라서, 나중의 제가 다시 봐도 이해할 수 있는 단순한 구성이 가장 오래 갑니다.

코멘트

답글 남기기

이메일 주소는 공개되지 않습니다. 필수 필드는 *로 표시됩니다