본문으로 건너뛰기

7.1 Backup

Backup은 실행 중인 PostgreSQL 클러스터의 데이터 디렉토리를 물리적으로 복사해 두는 작업입니다. CloudNativePG에서 backup은 in-place로 되돌리는 것이 아니라, 나중에 그 사본으로 새 클러스터를 부트스트랩하기 위한 재료입니다. 그래서 복구 절(7.3)과 짝을 이룹니다.

한 가지 원칙을 먼저 분명히 해 둡니다. 공식 문서는 "WAL archive만으로는 아무것도 못 합니다. 물리 base backup이 없으면 클러스터를 복원할 수 없다"고 명시합니다. 즉 base backup과 WAL archive(7.2)는 둘 다 있어야 의미가 있습니다.

백업 방식 두 가지​

CNPG는 base backup을 만드는 방식을 크게 둘로 나눕니다.

  • object store 백업: base backup을 S3·Azure Blob·GCS 같은 오브젝트 스토리지로 보냅니다. 1.30 기준 권장 경로는 Barman Cloud Plugin(CNPG-I)입니다.
  • volume snapshot 백업: Kubernetes CSI가 제공하는 볼륨 스냅샷으로 PVC를 통째로 뜹니다. 스토리지의 copy-on-write를 활용해 대용량 DB에서 특히 빠릅니다.

두 방식의 성격 차이는 뚜렷합니다. 아래 표로 정리합니다.

항목object storevolume snapshot
WAL archiving필수권장
hot backup(무중단)지원지원
cold backup(중단)미지원지원
증분·차등 복사미지원스토리지에 따라 지원
보존 정책지원미지원
PITR지원WAL archive 있으면 지원

정리하면, object store는 보존 정책과 연속 백업에 강하고, volume snapshot은 대용량(VLDB)에서 복구 속도에 강합니다. 아주 큰 데이터베이스라면 volume snapshot이 대체로 낫습니다.

노트

hot backup은 서버를 멈추지 않고 뜨는 물리 복사본이라, 복사 도중의 변경을 WAL로 메워야 일관성이 생깁니다. 그래서 hot backup 계열은 WAL archive가 반드시 필요합니다. 반면 cold backup(volume snapshot에서만 가능)은 인스턴스를 잠깐 멈추고 뜨므로 그 자체로 일관적입니다.

Barman Cloud Plugin으로 object store 붙이기​

1.30에서 object store 백업의 권장 방식은 Barman Cloud Plugin입니다. 이 플러그인이 Operator와 어떻게 대화하고 어디서 실행되는지는 2.5에 정리했습니다. 백업 대상 스토리지 설정을 ObjectStore라는 별도 리소스로 떼어 내고, Cluster는 그것을 이름으로 참조합니다. 백업 설정이 클러스터 정의에서 분리되어 재사용·관리가 쉬워집니다.

먼저 스토리지를 기술하는 ObjectStore를 만듭니다.

apiVersion: barmancloud.cnpg.io/v1
kind: ObjectStore
metadata:
name: minio-store
spec:
configuration:
destinationPath: s3://backups/
endpointURL: http://minio:9000
s3Credentials:
accessKeyId:
name: minio
key: ACCESS_KEY_ID
secretAccessKey:
name: minio
key: ACCESS_SECRET_KEY
wal:
compression: gzip

그리고 Cluster의 .spec.plugins에서 이 ObjectStore를 참조합니다. isWALArchiver: true가 이 플러그인을 WAL archiver로도 지정합니다(7.2).

apiVersion: postgresql.cnpg.io/v1
kind: Cluster
metadata:
name: cluster-example
spec:
instances: 3
plugins:
- name: barman-cloud.cloudnative-pg.io
isWALArchiver: true
parameters:
barmanObjectName: minio-store
storage:
size: 1Gi

이렇게 하면 WAL archiving과 데이터 디렉토리 백업이 함께 활성화됩니다. barmanObjectName은 앞서 만든 ObjectStore의 이름과 같아야 합니다.

경고

1.30에서 .spec.backup.barmanObjectStore 필드는 하위 호환을 위해 남아 있지만 v1.26부터 deprecated이며 이후 릴리스에서 제거될 예정입니다. 신규 구성은 위처럼 Barman Cloud Plugin을 씁니다.

온디맨드 백업​

지금 당장 한 번 백업하려면 Backup 리소스를 만듭니다. method로 방식을 고릅니다.

apiVersion: postgresql.cnpg.io/v1
kind: Backup
metadata:
name: backup-example
spec:
method: plugin
cluster:
name: cluster-example

진행 상황은 다음으로 확인합니다. status는 running을 거쳐 completed로 넘어가며, Backup ID·저장 경로 등의 메타데이터를 보여 줍니다.

kubectl describe backup backup-example
경고

온디맨드 백업에는 PostgreSQL superuser나 애플리케이션 사용자의 Kubernetes secret이 포함되지 않습니다. 복구 후 필요한 자격 증명은 별도로 관리해야 합니다.

예약 백업(ScheduledBackup)​

정해진 주기로 백업을 반복하려면 ScheduledBackup을 씁니다. schedule은 초까지 포함하는 여섯 필드 cron 표현식입니다(표준 cron과 달리 맨 앞 필드가 초).

apiVersion: postgresql.cnpg.io/v1
kind: ScheduledBackup
metadata:
name: backup-example
spec:
schedule: "0 0 0 * * *" # 매일 자정
backupOwnerReference: self
cluster:
name: cluster-example

주요 옵션은 다음과 같습니다.

  • schedule: 여섯 필드 cron(초 포함).
  • immediate: true: 리소스를 만들 때 즉시 한 번 백업합니다.
  • suspend: true: 예약 백업을 잠시 멈춥니다.
  • backupOwnerReference: none·self·cluster 중 하나.
노트

spec.cluster 필드는 immutable입니다. 대상 클러스터를 바꾸려면 기존 리소스를 수정하지 말고 새 ScheduledBackup을 만듭니다.

백업 주기는 곧 복구 목표 시간(RTO)에 직결됩니다. 대부분의 경우 주 1회 base backup이면 충분하고, full backup을 하루 한 번보다 자주 수행하는 일은 드뭅니다. 나머지 간격은 WAL archive가 메웁니다.

standby에서 백업 뜨기​

CNPG는 primary 부하를 줄이려고 기본적으로 "가장 최신 상태의 replica"에서 백업을 뜹니다. 이 기본값이 spec.backup.target: prefer-standby입니다. 가장 동기화된 standby를 골라 그곳에서 백업을 실행하고, standby가 하나도 없으면 primary로 물러납니다. primary에서 강제로 뜨게 하려면 대상을 primary로 지정합니다. 같은 target 필드를 Backup이나 ScheduledBackup에 적으면 그 백업 한 번만 Cluster 기본값을 덮어씁니다.

apiVersion: postgresql.cnpg.io/v1
kind: Cluster
metadata:
name: cluster-example
spec:
backup:
target: "primary"
경고

primary를 cold volume snapshot과 함께 쓰면 스냅샷을 뜨는 동안 쓰기가 잠깐 중단됩니다. 운영 트래픽이 있는 primary에서는 신중히 결정합니다.

volume snapshot 백업 상세​

volume snapshot은 Kubernetes CSI 표준 리소스 세 가지 위에서 동작합니다. 스냅샷 요청인 VolumeSnapshot, 실제 스냅샷 데이터를 가리키는 VolumeSnapshotContent, 그리고 어떤 CSI 드라이버로 어떻게 뜰지를 정하는 VolumeSnapshotClass입니다. CNPG는 이 API만 호출하고 실제 스냅샷은 스토리지 드라이버가 만듭니다. 그래서 storage와 walStorage에 쓴 StorageClass가 스냅샷을 지원하는지는 DBA가 스토리지 벤더 문서로 직접 확인해야 합니다.

Cluster에는 backup.volumeSnapshot stanza로 기본 동작을 정합니다. className이 모든 볼륨에 쓰는 기본 VolumeSnapshotClass고, PGDATA와 WAL의 StorageClass가 다르면 walClassName으로 WAL 쪽만 따로 지정합니다(생략하면 className과 같습니다). 이 stanza는 base backup만 다루므로 WAL archive는 앞서 본 플러그인이 그대로 맡습니다. 둘을 한 매니페스트에 함께 두면 volume snapshot과 플러그인 base backup을 동시에 운용할 수도 있습니다.

apiVersion: postgresql.cnpg.io/v1
kind: Cluster
metadata:
name: snapshot-cluster
spec:
instances: 3
storage:
storageClass: <storage-class>
size: 10Gi
walStorage:
storageClass: <storage-class>
size: 10Gi
backup:
volumeSnapshot:
className: <volume-snapshot-class>
plugins:
- name: barman-cloud.cloudnative-pg.io
isWALArchiver: true
parameters:
barmanObjectName: minio-store

hot과 cold​

기본은 hot(online) 백업입니다. 인스턴스 매니저가 pg_backup_start로 백업 모드에 들어간 뒤 스냅샷을 뜨고 pg_backup_stop으로 닫습니다. 파일시스템 freeze 같은 별도 조치는 필요 없습니다. 이때 PostgreSQL low-level API의 기본값을 그대로 따릅니다. 시작 시 즉시 checkpoint를 요청하지 않고, 종료 시 마지막 WAL segment가 archive될 때까지 기다립니다. 백업 시작부터 끝까지 필요한 WAL은 임시 replication slot이 유지하므로 hot snapshot도 일관된 복구 재료가 됩니다. 단 스냅샷만으로 특정 시점(PITR)에 갈 수는 없습니다. 스냅샷은 base backup 역할이고 시점 이동은 WAL archive(7.2)가 맡습니다.

기본값을 바꾸는 필드는 셋입니다.

필드의미기본값
onlinehot(true) / cold(false)true
onlineConfiguration.immediateCheckpoint시작 시 즉시 checkpoint 요청(pg_backup_start의 fast)즉시 요청 안 함
onlineConfiguration.waitForArchive종료 시 마지막 segment archive 대기(pg_backup_stop의 wait_for_archive)true

cold 백업은 대상 인스턴스를 잠시 내리고 뜹니다. 정의상 그 자체로 일관적이라 WAL이 없어도 복원할 수 있고, 공식 문서는 스냅샷 복구 용도로는 cold를 권합니다. Cluster 기본값과 별개로 Backup이나 ScheduledBackup의 .spec.online으로 한 번만 cold를 요청하는 것도 됩니다.

apiVersion: postgresql.cnpg.io/v1
kind: Backup
metadata:
name: snapshot-cluster-cold
spec:
cluster:
name: snapshot-cluster
method: volumeSnapshot
online: false
경고

cold 스냅샷의 대상이 primary가 되면 그 인스턴스는 백업 동안 fence되어 클러스터가 읽기 전용으로 바뀝니다. target: primary를 명시했거나 단일 인스턴스 Cluster일 때 그렇습니다. 이미 fence된 인스턴스가 있는 Cluster에서는 cold 스냅샷 요청이 거부됩니다.

스냅샷 객체의 수명​

Backup을 지워도 VolumeSnapshot은 기본적으로 남습니다. 누가 이 객체를 소유할지는 snapshotOwnerReference가 정합니다.

값동작
none (기본)소유자 없음. Backup이나 Cluster를 지워도 VolumeSnapshot은 남는다
backupBackup이 소유. Backup 삭제 시 함께 삭제
clusterCluster가 소유. Cluster 삭제 시 함께 삭제

VolumeSnapshot이 지워질 때 실제 데이터를 가리키는 VolumeSnapshotContent가 어떻게 되는지는 CNPG가 아니라 VolumeSnapshotClass의 deletionPolicy(Retain 또는 Delete)가 정합니다. 즉 스냅샷의 수명은 CNPG 쪽 소유권과 Kubernetes 쪽 삭제 정책, 두 층에서 결정됩니다.

경고

VolumeSnapshotContent에는 VolumeSnapshot에 붙은 복원 메타데이터(annotation과 label)가 없습니다. VolumeSnapshotContent만 남은 상태에서 복원하는 일은 가능하더라도 번거롭습니다. 공식 문서는 VolumeSnapshot 정의 자체를 Kubernetes 수준의 데이터 보호 도구로 함께 백업해 두라고 권합니다.

스냅샷 오류 재시도​

CSI 드라이버는 스냅샷 오류를 자유 형식 문자열로 보고하기 때문에 일시적 오류와 영구 오류를 구분할 수 없습니다. 그래서 CNPG는 모든 스냅샷 오류를 10초 간격으로 같은 방식으로 재시도하고, 기한이 지나면 백업을 실패로 표시합니다. 기한은 Backup이나 ScheduledBackup의 backup.cnpg.io/volumeSnapshotDeadline annotation에 분 단위로 적으며 기본값은 10분입니다. ScheduledBackup에 붙이면 거기서 생성되는 Backup이 물려받습니다.

보존 정책​

오브젝트 스토리지에 백업이 무한정 쌓이지 않도록 보존 정책으로 오래된 백업과 WAL을 정리합니다. 단, 이 관리 주체가 1.30에서 바뀌었습니다.

Cluster의 .spec.backup.retentionPolicy 필드는 deprecated입니다. 대신 사용하는 백업 플러그인이 제공하는 보존 메커니즘에 맡기는 것이 1.30의 방침입니다. Barman Cloud Plugin을 쓰면 보존 정책은 ObjectStore의 .spec.retentionPolicy로 옮겨 정의합니다.

volume snapshot은 보존 정책을 지원하지 않는다는 점을 기억합니다. 스냅샷 수명 관리는 Kubernetes 쪽 스냅샷 관리나 별도 절차로 다뤄야 합니다.

정리​

base backup과 WAL archive는 어느 하나만으로는 복구가 성립하지 않습니다. 둘을 함께 갖춰야 특정 시점으로 되돌릴 수 있습니다. object store는 보존 정책과 연속 백업에, volume snapshot은 대용량 복구 속도에 강점이 있습니다.

  • 1.30 권장 경로는 Barman Cloud Plugin입니다. ObjectStore 리소스를 만들고 Cluster .spec.plugins에서 참조합니다.
  • 반복 백업은 ScheduledBackup(초 포함 여섯 필드 cron), 일회성은 Backup으로 실행합니다.
  • 보존 정책은 플러그인(ObjectStore) 쪽에서 관리합니다.
  • volume snapshot은 기본 hot이고 online: false로 cold를 고릅니다. 스냅샷 객체의 수명은 snapshotOwnerReference와 VolumeSnapshotClass의 deletionPolicy 두 층이 정합니다.