콘텐츠로 이동
Study Note온프렘 쿠버네티스

11. 백업과 복구

“백업이 있다”와 “복구해 봤다”는 다른 말이다 — 이 장의 마지막 절이 제일 중요하다

이 장에서 처음 나오는 말7개
RPORecovery Point Objective
"얼마나 최근까지 되살릴 수 있나" — 잃어도 되는 데이터의 시간 폭. 백업 주기가 이 값을 정한다.
RTORecovery Time Objective
"얼마나 빨리 되살릴 수 있나" — 복구에 허용되는 시간. 절차가 문서화·리허설돼 있느냐가 이 값을 정한다.
etcd 스냅샷
쿠버네티스의 모든 오브젝트가 들어 있는 데이터베이스를 통째로 뜬 파일. 클러스터의 기억 전체다.
Velero
쿠버네티스 리소스와 PV 데이터를 오브젝트 스토리지로 백업·복구하는 도구. 온프렘 클러스터 백업의 사실상 표준이다.
Kopia
Velero가 PV 파일을 복사할 때 쓰는 백업 엔진. CSI 스냅샷을 못 쓰는 스토리지에서도 파일 단위로 백업할 수 있게 해 준다.
실패 도메인Failure Domain
함께 죽는 범위. 백업을 백업 대상과 같은 실패 도메인에 두면 백업이 아니다.
DRDisaster Recovery, 재해 복구
사이트·클러스터 전체를 잃었을 때 다른 환경에서 서비스를 되살리는 계획과 절차. 백업 파일만이 아니라 복구 순서와 연습까지 포함한다.

“백업 돌고 있어요”라는 말은 대개 일부만 백업하고 있다는 뜻이다. 먼저 세어 본다.

잃을 수 있는 것잃으면무엇이 지키나
매니페스트·설정무엇이 있었는지 모른다Git (9장)
etcd (오브젝트 전체)클러스터의 기억이 통째로etcd 스냅샷
PV 데이터앱이 쌓아 둔 파일Velero (+ CSI 스냅샷)
데이터베이스업무 데이터CNPG 백업 + WAL (7장)
오브젝트 스토리지로그·트레이스·백업 자체복제 또는 오프사이트 (6장)
Sealed Secrets sealing key 세트Git의 모든 비밀을 영영 못 푼다별도 금고 (10장)
사내 CA 개인키발급한 인증서 체계를 다시 세워야별도 금고 (4장)
Keycloak realm 설정SSO를 처음부터 다시CNPG 백업 (DB가 원본)
매니페스트·etcd·PV·PostgreSQL·sealing key 다섯 백업 대상이 각각 Git 저장소·오브젝트 스토리지·금고로 가고, 오브젝트 스토리지는 다시 오프사이트로 복제되는 보관 구조
터미널 창
# 컨트롤 플레인 노드에서 (kubeadm 기준 경로)
sudo ETCDCTL_API=3 etcdctl snapshot save /var/backups/etcd-$(date +%F-%H%M).db \
--endpoints=https://127.0.0.1:2379 \
--cacert=/etc/kubernetes/pki/etcd/ca.crt \
--cert=/etc/kubernetes/pki/etcd/server.crt \
--key=/etc/kubernetes/pki/etcd/server.key
# 확인 (여기서 에러가 나면 그 스냅샷은 못 쓴다)
sudo etcdctl --write-out=table snapshot status /var/backups/etcd-*.db
# 노드 밖으로 즉시 옮긴다 — 노드에만 있으면 노드와 함께 죽는다
mc cp /var/backups/etcd-*.db store/cluster-backups/etcd/
  • 주기: 하루 1회 + 위험한 작업 직전(업그레이드, CRD 변경, 대량 삭제)
  • 보존: 최소 2주. 잘못된 삭제는 며칠 뒤에 발견되기도 한다
  • 암호화: 스냅샷 안에 Secret이 평문으로 들어 있다(저장 시 암호화를 안 켰다면). 스냅샷 파일 자체의 접근 통제가 클러스터 Secret 접근 통제와 같은 급이어야 한다
apiVersion: velero.io/v1
kind: Schedule
metadata:
name: daily
namespace: velero
spec:
schedule: "0 3 * * *"
template:
includedNamespaces: ["*"]
excludedNamespaces: [kube-system, observability] # 재생성 가능한 것은 뺀다
defaultVolumesToFsBackup: true # CSI 스냅샷을 못 쓰면 파일 단위(Kopia)로
ttl: 720h # 30일
storageLocation: default # 6장의 오브젝트 스토리지
방식어떻게언제
CSI 스냅샷스토리지가 순간 스냅샷을 뜬다. 빠르다벤더 CSI가 지원할 때
파일 백업(Kopia)볼륨 내용을 읽어 오브젝트 스토리지로스냅샷을 못 쓸 때. 느리지만 이식성이 좋다

지금까지의 백업은 전부 오브젝트 스토리지 하나에 모였다. 그 스토리지가 있는 랙이 타면 전부 사라진다.

방법내용
버킷 복제다른 사이트의 S3 호환 스토리지로 지속 복제
주기적 동기화mc mirror를 cron으로 — 단순하지만 확실하다
오프라인 매체규정상 필요하면. 랜섬웨어 대비로는 이쪽이 확실하다
터미널 창
# 최소한 이 정도는 — 백업 버킷만이라도 다른 곳으로
mc mirror --overwrite --remove store/cluster-backups dr/cluster-backups
mc mirror --overwrite store/pg-backups dr/pg-backups

“백업합니다”가 아니라 숫자로 적어야 계획이 된다. 아래는 출발점으로 쓸 만한 값이다.

대상백업 주기RPO복구 방법RTO 어림
매니페스트커밋마다0Argo CD 동기화분
etcd1일 + 작업 전24시간스냅샷 복구 (최후 수단)시간
PostgreSQL베이스 1일 + WAL 연속분 단위새 Cluster로 PITR1~수 시간 (데이터 크기)
PV 데이터1일24시간Velero restore시간
오브젝트 스토리지지속 복제분~시간복제본으로 전환데이터 크기에 비례
sealing key 세트·CA 키변경·갱신 시마다0금고에서 복원 (10장)분

복구 리허설 — 이 장에서 제일 중요한 절

섹션 제목: “복구 리허설 — 이 장에서 제일 중요한 절”

백업 성공 ≠ 복구 가능

백업 잡이 초록불이어도 파일이 손상됐거나, 빠진 리소스가 있거나, 복구 절차를 아무도 모르는 경우가 흔하다. 확인하는 방법은 하나 — 해 보는 것.

분기 1회 · 30분

전면 DR 훈련이 아니어도 된다. 새 네임스페이스에 DB 복구본 하나 띄우고 행 수를 세는 것만으로 대부분의 문제가 드러난다.

문서는 복구 중에 쓴다

평시에 쓴 절차서는 대체로 틀렸다. 리허설하면서 막힌 지점을 그대로 적은 것이 진짜 runbook이다.

사람 의존을 없앤다

“그건 ○○님만 압니다”가 있으면 그게 최대 위험이다. 리허설은 매번 다른 사람이 절차서만 보고 한다.

터미널 창
# ① DB — 백업에서 새 클러스터를 띄워 행 수를 센다 (7장의 복구 매니페스트)
kubectl apply -f drill/platform-pg-restored.yaml
kubectl cnpg status platform-pg-restored -n drill
kubectl -n drill exec -it platform-pg-restored-1 -- \
psql -U postgres -d appdb -c "SELECT count(*) FROM orders;"
# ② Velero — 네임스페이스 하나를 다른 이름으로 복구
velero restore create drill-$(date +%F) \
--from-backup daily-20260810030000 \
--include-namespaces prod --namespace-mappings prod:drill-prod
velero restore describe drill-$(date +%F) --details
# ③ 시크릿 — sealing key 세트로 실제 복호화가 되나 (백업본으로)
kubeseal --recovery-unseal --recovery-private-key sealed-secrets-keys.yaml \
< observability/loki/sealedsecret-s3.yaml | head
# ④ etcd 스냅샷 — 파일이 온전한가
etcdctl --write-out=table snapshot status /path/to/etcd-latest.db
# ⑤ 정리
kubectl delete ns drill drill-prod
리허설에서 자주 드러나는 것
WAL 보존이 짧아 원하는 시점으로 못 간다7장 retentionPolicy
복구본이 뜰 StorageClass·용량이 없다여유 용량을 미리 확보
sealing key 세트 백업이 3개월 전 것이다키 갱신 후 백업을 안 했다
Velero가 CRD를 복구하지 못한다포함 규칙과 순서 확인
절차서의 명령이 옛 버전 것이다리허설 중에 고친다
터미널 창
# 백업이 실제로 최근 것인가 — "성공 로그"가 아니라 산출물을 본다
velero backup get | head
mc ls store/pg-backups/platform-pg/base/ | tail -3
mc ls store/cluster-backups/etcd/ | tail -3
mc ls dr/cluster-backups/etcd/ | tail -3 # 오프사이트에도 갔나
증상흔한 원인
백업은 초록불인데 파일이 없다스토리지 위치 설정이 다른 버킷을 본다
PV가 백업 안 됨defaultVolumesToFsBackup 누락 · 노드 에이전트 미배포
복구했는데 앱이 안 뜬다Secret이 빠졌다 (시크릿을 별도 체계로 관리 중)
PITR이 원하는 시점 이전으로 안 간다WAL 보존 기간
복구가 너무 오래 걸린다파일 백업의 한계 — CSI 스냅샷 지원 확인
  • 백업 계획은 선언(Git) + 상태(etcd · PV · DB · 오브젝트) + 열쇠(sealing key 세트 · CA 키) 로 나눈다
  • GitOps는 절반만 백업한다 — “무엇이 깔려 있었나”는 복원돼도 데이터는 안 돌아온다
  • etcd 복구는 최후의 수단이다. GitOps가 있으면 새로 세우고 동기화하는 편이 대개 낫다
  • DB는 DB의 방식으로(CNPG PITR). Velero의 파일 복사로 대신하지 않는다
  • 백업이 전부 한 스토리지에 모인다 — 오프사이트 복제가 마지막 안전망
  • 분기 1회 30분 리허설. 백업 성공은 복구 가능을 뜻하지 않고, 진짜 runbook은 리허설 중에 쓰인다