본문으로 건너뛰기

백업 및 복구

데이터 보호는 운영의 가장 중요한 책임입니다. PlantPulse 는 plantpulse-backup 모듈을 통해 PostgreSQL / Cassandra / 파일 / 컨테이너 볼륨을 통합 백업합니다.

백업 명령은 데이터레이크 컨테이너 «안에서» 실행합니다

plantpulse-backupplantpulse-datalake 이미지 안에 들어 있습니다. 데이터베이스가 전부 그 컨테이너에서 돌기 때문입니다.

cd /opt/kopens/plantpulse-platform-docker/bin
./shell.sh # 데이터레이크 진입
cd /opt/kopens/plantpulse-platform/plantpulse-backup/bin

Docker 볼륨 백업만 호스트에서 합니다(아래 §3).

보호 대상 한눈에 보기

백업 도구 매트릭스

도구대상방식압축중복 제거
pgBackRestPostgreSQLFull / Differential / Incrementalgzip / zstd
MedusaCassandraFull / Differential (스냅샷)gzip-
Restic파일 / 디렉토리증분zstd
mc mirrorMinIO증분 동기화--
backup-volume.shDocker 볼륨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-diffPostgreSQL Differential
plantpulse-backup-postgres-fullPostgreSQL Full
plantpulse-backup-cassandra-diffCassandra Differential
plantpulse-backup-cassandra-fullCassandra Full
plantpulse-backup-purge보관 정책 정리

기본 스케줄

작업OnCalendar시간
PostgreSQL Diff*-*-* 01:30:00매일 01:30
PostgreSQL FullSun *-*-* 01:00:00매주 일요일 01:00
Cassandra Diff*-*-* 01:20:00매일 01:20
Cassandra FullSun *-*-* 00:10:00매주 일요일 00:10
PurgeSun *-*-* 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.jsonlresult="skipped" 로 기록합니다 — okfail 도 아닙니다. 그래서 «껐다» 와 «돌았다» 를 나중에 구분할 수 있습니다.

유닛 파일을 직접 고쳐서 끄지 마세요. 다음 이미지 빌드가 원본을 다시 실으면 조용히 되살아납니다.

스위치는 사이드카에 적어야 합니다

export PP_BACKUP_SCHEDULE_ENABLED=falsebin/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_VER18PostgreSQL 버전
PG_DATA/data1/pp-data/postgres/dataPG 데이터 디렉토리
CASS_BASE/opt/kopens/plantpulse-platform/plantpulse-storage/db/cassandraCassandra 설치 경로
CQL_USER${PP_CASSANDRA_USER}CQL 사용자
CQL_PASS${PP_CASSANDRA_PASSWORD}CQL 비밀번호
PG_RETENTION_FULL2PG Full 보존
CASS_PURGE_KEEP_DAYS10Medusa 보존 일수

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