백업은 존재할 때만 복구된다: rsync/cron으로 무중단 증분 백업(로컬·원격·보안·검증 루틴)
“백업은 있는데 복구가 안 된다”는 말, 현업에선 흔합니다. 정기성·무중단·검증 세 가지가 빠지면
백업은 착시일 뿐입니다. 이 글은 Ubuntu 24.04 기준으로 rsync와 cron만으로
증분 스냅샷을 만들고, 원격지에 암호화 백업까지 자동화하는 루틴을 제시합니다.
복붙 가능한 스크립트와 복구 리허설, 삭제/랜섬웨어 대응 팁까지 포함합니다.
1) 전략 결정: 무엇을, 얼마나 자주, 어디에
- 무엇: 애플리케이션 설정(
/etc/<app>), 사용자 데이터(/srv/data), DB 덤프 파일. - 주기: 변경 빈도에 따라 일일 증분 + 주간 전체 조합이 현실적.
- 어디: 같은 서버(로컬 스냅샷) + 다른 디스크/서버(원격)로 2중화.
- 검증: 백업 완료 후 무결성/복구 리허설 자동 체크.
2) rsync 설치와 핵심 옵션
sudo apt update
sudo apt install -y rsync
rsync --version
핵심 옵션 요약:
-a: archive(권한/소유자/타임스탬프 유지, 재귀)-A/-X: ACL/확장속성(필요 시)--delete: 소스에서 삭제된 파일을 대상에서도 삭제(주의)--link-dest: 하드링크로 증분 스냅샷(변경 없는 파일은 이전 스냅샷과 링크 공유)-z: 전송 중 압축(원격 전송 시)-e ssh: SSH로 전송
3) 로컬 스냅샷(일자별 폴더) 만들기
하드링크 기반 스냅샷은 공간 효율이 매우 뛰어납니다. 변경 파일만 추가 저장되고, 변경 없는 파일은 이전 스냅샷과 inode를 공유합니다.
# 예시: /srv/data 를 /backup에 일자별 스냅샷 생성
sudo mkdir -p /backup/snapshots
sudo chown -R root:root /backup
sudo chmod -R 750 /backup
# /usr/local/sbin/backup_local.sh
#!/usr/bin/env bash
set -euo pipefail
SRC="/srv/data"
DST="/backup/snapshots"
TODAY=$(date +%F)
LATEST=$(ls -1 $DST | tail -n 1 || true)
mkdir -p "$DST/$TODAY"
if [[ -n "$LATEST" && -d "$DST/$LATEST" ]]; then
rsync -aAX --delete \
--link-dest="$DST/$LATEST" \
"$SRC/" "$DST/$TODAY/"
else
rsync -aAX --delete "$SRC/" "$DST/$TODAY/"
fi
# 오래된 스냅샷 정리(예: 30일 보관)
find "$DST" -maxdepth 1 -mindepth 1 -type d -mtime +30 -print -exec rm -rf {} \;
sudo chmod +x /usr/local/sbin/backup_local.sh
sudo /usr/local/sbin/backup_local.sh
검증:
ls -l /backup/snapshots | tail
du -sh /backup/snapshots/*
4) 원격 서버로 암호화 백업(SSH+gpg)
원격지 전송은 가로채임/유출에 대비해 전송 암호화(SSH)와 저장 암호화(gpg)를 함께 고려합니다. 여기서는 단순하고 강력한 tar + gpg + rsync 조합을 씁니다.
# GPG 수신자 키(원격 보관용) 준비 - 운영팀 키를 사용
# 로컬 서버에 공개키만 배치(개인키 없음)
gpg --list-keys
# /usr/local/sbin/backup_remote.sh
#!/usr/bin/env bash
set -euo pipefail
SRC_DIRS="/etc /srv/data"
TMP="/tmp/backup.$(date +%s)"
ARCHIVE="$TMP/archive.tar"
ENC="$TMP/archive.tar.gpg"
REMOTE_USER="backup"
REMOTE_HOST="backup.example.com"
REMOTE_DIR="/vault/$(hostname -s)"
GPG_RECIPIENT="ops@company.com"
mkdir -p "$TMP"
tar -cf "$ARCHIVE" $SRC_DIRS
gpg --yes --batch -r "$GPG_RECIPIENT" -o "$ENC" -e "$ARCHIVE"
# 원격 디렉터리 준비 후 전송(증분 대신 일자 파일명 권장)
DATE=$(date +%F)
ssh -o StrictHostKeyChecking=accept-new ${REMOTE_USER}@${REMOTE_HOST} "mkdir -p ${REMOTE_DIR}"
rsync -az -e ssh "$ENC" ${REMOTE_USER}@${REMOTE_HOST}:${REMOTE_DIR}/backup_${DATE}.tar.gpg
rm -rf "$TMP"
sudo chmod +x /usr/local/sbin/backup_remote.sh
sudo /usr/local/sbin/backup_remote.sh
대안: restic, borg 같은 전용 백업 도구는 중복제거/암호화/색인/복구가 더 편리합니다. 기본기는 rsync로, 요구가 커지면 전용툴로 전환하세요.
5) DB는 파일 복사 말고 “덤프”
운영 DB는 pg_dump(PostgreSQL)나 mysqldump(MySQL/MariaDB)로
논리 백업을 만든 후 파일 백업에 포함해야 복구가 쉬워집니다.
# PostgreSQL 예시(컨테이너 내부 or 호스트)
PG_DB=appdb
PG_USER=app
DUMP_DIR=/backup/db
mkdir -p $DUMP_DIR
pg_dump -U $PG_USER -d $PG_DB | gzip > $DUMP_DIR/${PG_DB}_$(date +%F).sql.gz
# MySQL/MariaDB 예시
mysqldump -u root -p --databases appdb | gzip > $DUMP_DIR/appdb_$(date +%F).sql.gz
덤프 파일은 원격 암호화 백업에도 포함하세요.
6) cron으로 스케줄링(충돌 방지 포함)
중복 실행을 막기 위해 잠금 파일을 사용하는 것이 안전합니다.
# /usr/local/sbin/backup_daily.sh
#!/usr/bin/env bash
set -euo pipefail
LOCK="/var/lock/backup_daily.lock"
exec 9> "$LOCK" || exit 1
if ! flock -n 9; then
echo "Another backup is running."; exit 0
fi
# 1) DB 덤프
/usr/local/sbin/db_dump.sh
# 2) 로컬 스냅샷
/usr/local/sbin/backup_local.sh
# 3) 원격 전송
/usr/local/sbin/backup_remote.sh
sudo chmod +x /usr/local/sbin/backup_daily.sh
# 매일 새벽 3시(부하 적은 시간) 실행
echo "0 3 * * * root /usr/local/sbin/backup_daily.sh >> /var/log/backup.log 2>&1" | \
sudo tee /etc/cron.d/backup-daily
7) 삭제/랜섬웨어 대응: 버전 보관과 쓰기 경로 분리
- --delete는 양날의 검. 실수/랜섬웨어 삭제가 백업에도 전파됩니다. 스냅샷 방식으로 과거 버전을 보존하세요.
- 원격 보관소는 쓰기 권한 최소화. 운영 서버에서 읽을 수 없어야 이상적(단방향 푸시).
- 클라우드 스토리지 사용 시 객체 잠금(Object Lock)·버전관리 옵션을 고려.
8) 복구 리허설 스크립트(정기 실행 권장)
백업은 복구 테스트를 해야 진짜입니다. 샌드박스 디렉터리로 복구 연습을 자동화하세요.
# /usr/local/sbin/restore_rehearsal.sh
#!/usr/bin/env bash
set -euo pipefail
SRC_SNAPSHOT=$(ls -1 /backup/snapshots | tail -n 1)
TEST_DIR="/tmp/restore_test.$(date +%s)"
mkdir -p "$TEST_DIR"
rsync -a "/backup/snapshots/${SRC_SNAPSHOT}/" "$TEST_DIR/"
# DB 복구 리허설(논리 검사만, 실제 DB에 적용하지 않음)
if ls /backup/db/*.sql.gz >/dev/null 2>&1; then
gunzip -c /backup/db/$(ls -1 /backup/db | tail -n 1) | head -n 50 > "$TEST_DIR/db_head.sql"
# 간단 문법 체크(예: PostgreSQL 구문) - 실제 환경에 맞게 조정
fi
echo "OK: restored to $TEST_DIR"
sudo chmod +x /usr/local/sbin/restore_rehearsal.sh
# 매주 일요일 새벽 4시
echo "0 4 * * 0 root /usr/local/sbin/restore_rehearsal.sh >> /var/log/backup.log 2>&1" | \
sudo tee /etc/cron.d/backup-verify
9) 모니터링/알림(실패를 알아차리기)
- 로그:
/var/log/backup.log를 중앙 수집(filebeat/Promtail) 또는 메일 알림에 연동. - 종료코드: 스크립트는
set -euo pipefail로 실패 시 즉시 종료 → cron 메일로 실패 알림. - 메트릭화: 백업 크기/기간/성공 여부를 Prometheus node_exporter textfile로 노출.
# /var/lib/node_exporter/textfile_collector/backup.prom (예시)
backup_last_success_timestamp_seconds $(date +%s)
backup_last_size_bytes $(du -sb /backup/snapshots | awk '{print $1}')
10) 자주 겪는 문제와 해결
- 권한 오류:
-aAX사용 시 root 권한 필요. 백업 대상에 특수 권한/ACL이 있으면-A -X포함. - 대상 경로 오타로 대량 삭제: 항상
--dry-run으로 예행연습 후 적용.--delete는 신중. - 원격 전송 느림:
-z압축,--partial·--inplace검토. 병목은 네트워크/디스크 IO 분석. - 용량 폭증: 스냅샷 보관 일수 줄이기, 대용량 로그/캐시 제외(
--exclude목록 관리).
# 예: 제외 목록 사용
cat > /etc/backup.exclude <<'EX'
/srv/data/cache/
/srv/data/tmp/
/srv/data/logs/*.old
EX
# rsync 호출시
rsync -aAX --delete --exclude-from=/etc/backup.exclude ...
11) 최종 체크리스트
- 로컬 하드링크 스냅샷(일자별) 정상 생성, 30일 보관 정책 동작
- DB 논리 백업 포함(일자 파일명), 원격지 암호화 보관
- cron 스케줄 + 잠금 파일로 중복 실행 방지
- 복구 리허설 주간 자동화, 로그/알림 연결
- 삭제/랜섬웨어 대비:
--delete신중, 버전 보관/쓰기 최소화
여기까지면 “돌아가는 백업”이 아니라 복구 가능한 백업을 갖추게 됩니다. 다음 글에서는 logrotate로 로그 보존·용량 관리를 자동화하고, systemd와의 연동으로 애플리케이션 로그를 안정적으로 다루는 방법을 이어서 다룹니다.
'서버 인프라 실무' 카테고리의 다른 글
| Nginx 리버스 프록시 + Spring Boot 실전 운영: CORS, 타임아웃, 업로드 제한, 보안 헤더 한 번에 정리 (0) | 2025.10.24 |
|---|---|
| 로그 보존 자동화: logrotate + systemd-journald로 용량·보존·압축 완전 정복(Ubuntu 24.04) (0) | 2025.10.24 |
| 시스템 모니터링 첫걸음: top/htop/journalctl/ss로 원인 추적(근거 있는 장애 대응 루틴) (0) | 2025.10.23 |
| 시계가 틀리면 장애난다: chrony로 시간 동기화 정확히 잡기(Ubuntu 24.04, NTP 실무) (0) | 2025.10.22 |
| 사용자·그룹·sudoers 운영 표준: 최소 권한과 감사 로그(Ubuntu 24.04) (0) | 2025.10.22 |