백업 및 복구
데이터 보호는 운영의 가장 중요한 책임입니다. PlantPulse 는 plantpulse-backup 모듈을 통해 PostgreSQL / Cassandra / 파일 / 컨테이너 볼륨을 통합 백업합니다.
plantpulse-backup 은 plantpulse-datalake 이미지 안에 들어 있습니다. 데이터베이스가 전부 그 컨테이너에서 돌기 때문입니다.
cd /opt/kopens/plantpulse-platform-docker/bin
./shell.sh # 데이터레이크 진입
cd /opt/kopens/plantpulse-platform/plantpulse-backup/bin
Docker 볼륨 백업만 호스트에서 합니다(아래 §3).
보호 대상 한눈에 보기
백업 도구 매트릭스
| 도구 | 대상 | 방식 | 압축 | 중복 제거 |
|---|---|---|---|---|
| pgBackRest | PostgreSQL | Full / Differential / Incremental | gzip / zstd | ✓ |
| Medusa | Cassandra | Full / Differential (스냅샷) | gzip | - |
| Restic | 파일 / 디렉토리 | 증분 | zstd | ✓ |
| mc mirror | MinIO | 증분 동기화 | - | - |
| backup-volume.sh | Docker 볼륨 | tar.gz 스냅샷 | gzip | - |
RPO / RTO 권장 목표
| 데이터 | RPO (복구 시점) | RTO (복구 시간) | 권장 백업 빈도 |
|---|---|---|---|
| PostgreSQL 메타 | 1시간 | 30분 | 일 1회 Full + 시간별 WAL |
| Cassandra 시계열 | 24시간 | 2시간 | 일 1회 Diff + 주 1회 Full |
| MinIO 오브젝트 | 24시간 | 4시간 | 외부 S3 미러 + 일 1회 |
| 설정 / 인증서 | 변경 시 | 15분 | 변경 시 즉시 + 월 1회 |
운영 등급 데이터센터: 위 목표는 단일 사이트 단순 운영 기준입니다. Multi-AZ / Geo-redundant 가 필요하면 외부 사이트 복제 (rsync, mc mirror, Kafka MirrorMaker) 를 함께 설계해 주세요.
백업 저장 구조
/data1/pp-backup/
├── pgbackrest/postgres/ # PostgreSQL 백업 (pgBackRest)
│ ├── archive/ # WAL archive
│ └── backup/ # Full / Diff / Incr
├── medusa/ # Cassandra 백업 (Medusa)
│ └── <hostname>/<backup-name>/
├── restic/ # 파일 백업 (Restic)
│ ├── data/
│ ├── index/
│ └── snapshots/
└── docker-volume/ # Docker 볼륨 (tar.gz)
├── pp-data-YYYYMMDD.tar.gz
├── pp-security-YYYYMMDD.tar.gz
└── ...
1. plantpulse-backup 통합 명령
plantpulse-backup 모듈이 모든 백업 도구를 wrapping 합니다.
초기 설치 (최초 1회)
cd /opt/kopens/plantpulse-platform/plantpulse-backup/bin
./backup.sh --install
자동 수행:
- pgBackRest 설정 (
/etc/pgbackrest/pgbackrest.conf) - Medusa 설정 (
/etc/medusa/medusa.ini) - 디렉토리 / 권한 생성
- pgBackRest stanza 생성
PostgreSQL 백업
cd /opt/kopens/plantpulse-platform/plantpulse-backup/bin
./backup.sh --postgres # Differential (기본, 빠름)
./backup.sh --postgres full # Full (전체)
./backup.sh --postgres incr # Incremental (가장 빠름)
Cassandra 백업
./backup.sh --cassandra # Differential
./backup.sh --cassandra full # Full
파일 백업 (Restic)
/opt/kopens/plantpulse-platform/plantpulse-backup/etc/run_restic.sh
/data1/pp-data증분 백업- 보존 정책: 최근 7일 + 월별 1개
- 자동 무결성 검사
백업 정리
./backup.sh --purge
- pgBackRest:
repo1-retention-full(기본 2 세트) - Medusa:
CASS_PURGE_KEEP_DAYS(기본 10 일) - Restic: 정책에 따라 자동
2. 자동 백업 — 이미 켜져 있습니다
자동 백업은 이미지에 systemd 타이머 다섯 개로 구워져 있고, 기본으로 활성화되어 있습니다. --cron-install 을 실행할 필요가 없습니다.
| 타이머 | 하는 일 |
|---|---|
plantpulse-backup-postgres-diff | PostgreSQL Differential |
plantpulse-backup-postgres-full | PostgreSQL Full |
plantpulse-backup-cassandra-diff | Cassandra Differential |
plantpulse-backup-cassandra-full | Cassandra Full |
plantpulse-backup-purge | 보관 정책 정리 |
기본 스케줄
| 작업 | OnCalendar | 시간 |
|---|---|---|
| PostgreSQL Diff | *-*-* 01:30:00 | 매일 01:30 |
| PostgreSQL Full | Sun *-*-* 01:00:00 | 매주 일요일 01:00 |
| Cassandra Diff | *-*-* 01:20:00 | 매일 01:20 |
| Cassandra Full | Sun *-*-* 00:10:00 | 매주 일요일 00:10 |
| Purge | Sun *-*-* 03:00:00 | 매주 일요일 03:00 |
끄고 켜기
호스트의 시크릿 사이드카에 스위치를 적고 재시작합니다.
# 호스트에서
sudo vi /etc/kopens/plantpulse-platform.env
# export PP_BACKUP_SCHEDULE_ENABLED=false
cd /opt/kopens/plantpulse-platform-docker/bin
./restart.sh
타이머 자체는 언제나 발화하고, 래퍼 스크립트가 스위치를 읽어 판단합니다. 꺼져 있으면 백업을 건너뛰면서 저널과 history.jsonl 에 result="skipped" 로 기록합니다 — ok 도 fail 도 아닙니다. 그래서 «껐다» 와 «돌았다» 를 나중에 구분할 수 있습니다.
유닛 파일을 직접 고쳐서 끄지 마세요. 다음 이미지 빌드가 원본을 다시 실으면 조용히 되살아납니다.
export PP_BACKUP_SCHEDULE_ENABLED=false 를 bin/env.sh 에만 적으면 컨테이너에 닿지 않습니다. compose 가 이 이름을 컨테이너로 넘기는 줄이 스위치의 전부이고, 그 값은 사이드카(또는 셸 export)에서 옵니다. 잘못 적으면 «꺼짐으로 보이는데 계속 도는» 상태가 됩니다.
3. Docker 볼륨 백업 (컨테이너 환경)
원라인 설치 / Docker 설치에서는 볼륨 단위 백업이 추가로 가능합니다.
호스트에서 실행합니다.
cd /opt/kopens/plantpulse-platform-docker/bin
# 기본 세트를 한 번에 (pp-data · pp-security)
./backup.sh
# 볼륨 하나만
./tools/backup-volume.sh pp-data 7 /data1/pp-backup/docker-volume
./tools/backup-volume.sh pp-security 30 /data1/pp-backup/docker-volume
기본 세트에서 둘이 빠져 있는 것은 잊어서가 아닙니다 — pp-backup 은 백업의 목적지라서(자기 안에 자기를 넣으면 매번 두 배가 됩니다), pp-temp 는 복구에 쓸모가 없어서입니다. 필요하면 인자로 지정해 백업할 수 있습니다.
설정 템플릿은 호스트 디렉토리 /etc/kopens/conf 를 바인드 마운트한 것이라 도커 볼륨 백업 대상이 아닙니다. 호스트 파일로 함께 백업해 주세요. 시크릿 사이드카 /etc/kopens/plantpulse-platform.env 도 마찬가지입니다.
| 인자 | 설명 | 기본 |
|---|---|---|
| 1 | 볼륨 이름 | (필수) |
| 2 | 보관 일수 | 7 |
| 3 | 저장 경로 | /data1/pp-backup/docker-volume |
4. 환경 변수 (backup.sh)
| 변수 | 기본 | 설명 |
|---|---|---|
BACKUP_ROOT | /data1/pp-backup | 백업 루트 |
PG_VER | 18 | PostgreSQL 버전 |
PG_DATA | /data1/pp-data/postgres/data | PG 데이터 디렉토리 |
CASS_BASE | /opt/kopens/plantpulse-platform/plantpulse-storage/db/cassandra | Cassandra 설치 경로 |
CQL_USER | ${PP_CASSANDRA_USER} | CQL 사용자 |
CQL_PASS | ${PP_CASSANDRA_PASSWORD} | CQL 비밀번호 |
PG_RETENTION_FULL | 2 | PG Full 보존 |
CASS_PURGE_KEEP_DAYS | 10 | Medusa 보존 일수 |
5. 외부 사이트 복제 (Off-site)
로컬 백업만으로는 데이터센터 장애에 취약합니다. 권장 패턴:
# 매일 새벽 4시 — 외부 S3 로 복제
0 4 * * * rclone sync /data1/pp-backup/ s3:kopens-pp-backup/$(hostname)/ \
--bwlimit 50M --log-file /var/log/pp-backup-sync.log
# MinIO 객체는 mc 로 별도 미러
0 5 * * * mc mirror --overwrite local/ s3-offsite/
6. 복구
6.1 PostgreSQL 복구
# 1. plantpulse 중지 (PG 의존 모듈 + PG)
cd /opt/kopens/plantpulse-platform/plantpulse-datalake-cli/bin
./stop.sh
# 2. 백업 정보 확인
sudo -u postgres pgbackrest --stanza=pg18 info
# 3. 최신 복구
sudo -u postgres pgbackrest --stanza=pg18 restore
# 3-2. 시점 복구 (PITR)
sudo -u postgres pgbackrest --stanza=pg18 --type=time \
--target="2026-05-30 12:00:00" restore
# 4. 재시작
./start-daemon.sh
./status.sh
6.2 Cassandra 복구
# 백업 목록
medusa list-backups
# 단일 노드 복구
medusa restore-node --backup-name full_20260530_0010
# 클러스터 전체 복구 (마스터에서)
medusa restore-cluster --backup-name full_20260530_0010
주의:
restore-cluster는 모든 노드의 데이터를 덮어씁니다. 실행 전 반드시 stage 환경에서 검증해 주세요.
6.3 파일 복구 (Restic)
# 스냅샷 목록
restic -r /data1/pp-backup/restic snapshots
# 최신 스냅샷 → 임시 위치 복구
restic -r /data1/pp-backup/restic restore latest --target /data1/pp-data-restored
# 특정 파일만 복구
restic -r /data1/pp-backup/restic restore latest --target / --include /data1/pp-data/cassandra/data/pp/tm_tag_point
6.4 부분 시계열 복구 (plantpulse-recovery)
특정 에셋의 특정 기간 데이터만 재처리하려면:
cd /opt/kopens/plantpulse-platform/plantpulse-recovery/bin
./recovery.sh ASSET_01032 20260501 20260530
6.5 부분 시계열 추출 (plantpulse-exporter)
CSV 로 추출하거나 dsbulk 로 벌크 처리:
cd /opt/kopens/plantpulse-platform/plantpulse-exporter/bin
# 에셋 단위 CSV
./export.sh ASSET_01032 20260101 20260530 /tmp
# 테이블 벌크 언로드 → gz
./bulk-unload.sh pp tm_tag_point
# /data1/pp-backup/cassandra/bulk/tm_tag_point.gz
# 다시 로드
./bulk-load.sh pp tm_tag_point
7. 재해 복구 (DR) 시나리오
시나리오 A: 서버 하드웨어 장애 (Cold DR)
예상 RTO: 4~8시간 (데이터 용량에 따라 다름)
시나리오 B: 데이터 손상 (PITR)
# 1. 손상 시점 직전으로 시점 복구
./stop.sh
sudo -u postgres pgbackrest --stanza=pg18 --type=time \
--target="2026-05-30 14:30:00" restore
# 2. Cassandra 도 동일 시점 가까운 백업으로
medusa restore-cluster --backup-name diff_20260530_0120
# 3. 재시작
./start-daemon.sh
./status.sh
시나리오 C: 외부 사이트 페일오버 (Hot DR)
외부 사이트에 standby 클러스터를 유지하는 경우. 사전 설계 필요:
- PostgreSQL: streaming replication 또는 pgBackRest 비동기 복제
- Cassandra: multi-DC 클러스터 + 자동 hinted handoff
- Kafka: MirrorMaker 2 양방향 복제
- MinIO: site replication 또는
mc mirror --watch
8. 복구 후 검증 체크리스트
cd /opt/kopens/plantpulse-platform/plantpulse-datalake-cli/bin
# 1. 전체 모듈 상태
./status.sh
# 2. 헬스 체크
./ops-check.sh
# 3. Cassandra 클러스터 정상
./pd node status
# 4. PostgreSQL 연결
./pd node psql -c "SELECT count(*) FROM site;"
# 5. Kafka 토픽 / Consumer Group
./pd node topic
브라우저:
- 웹 콘솔 접속 (
http://[HOST]/) - 관리자 로그인 (
admin / admin123!) - 대시보드 로드
- 알람 목록 표시
- OPC 연결 상태 CONNECTED
- 시계열 트렌드에서 최근 데이터 표시
- CEP 룰 실행 확인
9. 백업 운영 모범 사례
- 3-2-1 규칙: 데이터 3 카피, 2 매체, 1 오프사이트
- 월 1회 복구 훈련: stage 환경에서 실제 복구 시도
- 백업 무결성 검증:
restic check,pgbackrest verify,medusa verify - 백업 모니터링: 백업 실패 시 알림 (Slack, email)
- 암호화: 외부 사이트 전송 시 TLS, 저장 시 LUKS/SSE-S3
- 권한 분리: 백업 디스크는 별도 마운트 + read-only 마운트 옵션
- 문서화: 복구 절차를 운영팀이 공유 wiki 에 기록
관련 문서
기술 지원
백업 / 복구 관련 문의: webmaster@kopens.com