Velero FSB 백업이 4시간 걸린다고?
defaultVolumesToFsBackup: true의 함정과 opt-in 방식으로 백업 시간 99% 단축하기
들어가며
“백업이 4시간이나 걸려요. 그런데 PartiallyFailed예요.”
홈클러스터에서 Velero File-System Backup(FSB)을 운영하다가 발견한 문제다. 매일 새벽 3시에 시작된 백업이 오전 7시가 되어도 끝나지 않았고, 완료되더라도 상태는 PartiallyFailed였다.
이전 글에서 FSB를 적용하고 130개 PodVolumeBackup이 성공한 걸 확인했다. 그때는 “전부 백업됐다”고 넘어갔지만, 실제 PVC는 44개뿐이었다. 나머지는 뭘 백업하고 있었을까?
문제 상황
환경
- Kubernetes: 홈클러스터 (kubespray)
- 스토리지: Longhorn
- 백업: Velero + kopia (File-System Backup)
- 백업 대상: GitLab, Langfuse, ClearML, Grafana 등 10개 서비스
증상
$ velero backup describe daily-backup-20260204
Phase: PartiallyFailed
Errors: Velero: <none> Cluster: <none> Namespaces: langfuse: error running kopia backup... context canceled
Started: 2026-02-05 03:00:33 +0900 KSTCompleted: 2026-02-05 07:07:54 +0900 KSTDuration: 4h7m21s4시간이 걸렸는데 실패한 볼륨도 있다. 백업이 이렇게 오래 걸리면 안 된다.
FSB 목록 확인
$ velero backup describe daily-backup-20260204 --details | grep "^ " | wc -l132132개의 볼륨을 FSB로 백업하고 있었다. 목록을 보니 문제가 바로 보였다.
gitlab/gitlab-gitaly-0[repo-data]gitlab/gitlab-gitaly-0[etc-ssl-certs] # ?gitlab/gitlab-gitaly-0[gitaly-config] # ?gitlab/gitlab-gitaly-0[init-gitaly-0] # ?langfuse/langfuse-xxx[tmp] # ?observability/prometheus-xxx[web-config] # ?...repo-data, data 같은 실제 데이터 볼륨 외에 etc-ssl-certs, tmp, gitaly-config 같은 볼륨들이 전부 백업되고 있었다.
원인 분석
defaultVolumesToFsBackup: true
Velero Helm Chart의 기본 설정을 확인해보니:
# velero values.yamlconfiguration: defaultVolumesToFsBackup: true이 설정이 true면 모든 Pod의 모든 볼륨이 FSB 대상이 된다. ConfigMap 마운트, Secret 마운트, emptyDir까지 전부.
132개 볼륨의 정체
| 분류 | 개수 | 설명 |
|---|---|---|
| 실제 데이터 (PVC) | ~40 | postgresql, redis, gitaly 등 |
| ConfigMap/Secret | ~30 | ssl-certs, config 등 |
| emptyDir | ~30 | tmp, shm, cache 등 |
| 기타 | ~30 | init containers, sidecar 등 |
PVC 44개를 백업하려다 132개를 백업하고 있었다.
PartiallyFailed 원인
ClickHouse 백업이 context canceled로 실패했다.
해결 방안: opt-in vs opt-out
Velero FSB는 두 가지 방식을 지원한다.
opt-out (기본값)
# 전역 설정defaultVolumesToFsBackup: true
# 제외할 볼륨 지정podAnnotations: backup.velero.io/backup-volumes-excludes: "tmp,ssl-certs,config"모든 볼륨을 백업하고, 불필요한 것만 제외한다.
opt-in
# 전역 설정defaultVolumesToFsBackup: false
# 백업할 볼륨 지정podAnnotations: backup.velero.io/backup-volumes: "data"아무것도 백업하지 않고, 필요한 것만 지정한다.
어떤 방식이 좋을까?
| 기준 | opt-out | opt-in |
|---|---|---|
| 새 볼륨 추가 시 | 자동 백업됨 (안전) | 수동 추가 필요 |
| 불필요한 백업 | 발생 가능 | 없음 |
| 설정 관리 | 제외 목록 관리 | 포함 목록 관리 |
| 명확성 | 뭐가 백업되는지 불명확 | 백업 대상이 명확 |
132개 중 90개를 exclude하는 것보다 40개를 include하는 게 훨씬 명확하다. opt-in 방식을 선택했다.
적용
Velero 설정 변경
configuration: defaultVolumesToFsBackup: false # opt-in으로 변경
# schedule.yamlspec: schedule: "0 18 * * *" template: snapshotVolumes: false defaultVolumesToFsBackup: false ttl: 72h # 3일 보관서비스별 annotation 추가
각 서비스의 Helm values에 백업 대상 볼륨을 명시적으로 지정했다.
gitlab: gitaly: podAnnotations: backup.velero.io/backup-volumes: "repo-data"postgresql: primary: podAnnotations: backup.velero.io/backup-volumes: "data"postgresql: primary: podAnnotations: backup.velero.io/backup-volumes: "data"백업 대상 목록
최종적으로 12개 볼륨만 백업하도록 설정했다.
| 서비스 | 백업 볼륨 | 이유 |
|---|---|---|
| GitLab Gitaly | repo-data | Git 저장소 |
| GitLab PostgreSQL | data | 메타데이터 |
| Langfuse PostgreSQL | data | 트레이스 데이터 |
| ClearML Elasticsearch | clearml-elastic-master | 실험 데이터 |
| DefectDojo PostgreSQL | data | 취약점 데이터 |
| SonarQube PostgreSQL | data | 코드 분석 결과 |
| Trivy | data | 취약점 DB |
| Airflow Scheduler | logs | 실행 로그 |
| Airflow MinIO | export | 내부 스토리지 |
| Garage | meta, data | 오브젝트 스토리지 |
| Grafana | storage | 대시보드 |
Prometheus와 Redis는 제외했다. Prometheus는 30일 retention으로 17.5GB나 차지하는데 메트릭은 재생성된다. Redis(Valkey 포함)는 세션/캐시 용도라 손실되어도 자동 재빌드된다.
결과
Before vs After
| 항목 | Before | After | 개선 |
|---|---|---|---|
| FSB 볼륨 수 | 132 | 12 | -91% |
| 백업 시간 | 4시간 | 3분 | -99% |
| 백업 크기 | ~11GB | 4.4GB | -60% |
| 상태 | PartiallyFailed | Completed | 정상화 |
$ velero backup describe daily-backup-20260205
Phase: Completed
Started: 2026-02-06 03:00:28 +0900 KSTCompleted: 2026-02-06 03:03:41 +0900 KSTDuration: 3m13s4시간에서 3분으로. 백업이 정상화되었다.
스토리지 절약
Before: 11GB/일 × 7일 = 77GBAfter: 4.4GB/일 × 3일 = 13.2GB기존 기본 TTL 7일에서 3일로 줄여서 스토리지 사용량이 83% 감소했다.
정리
defaultVolumesToFsBackup: true는 “일단 다 백업하자”는 안전한 선택처럼 보이지만, 실제로는 emptyDir, ConfigMap 마운트, init 볼륨까지 전부 포함시킨다. 132개 중 실제 PVC 기반은 40개뿐이었고, 나머지 90개가 시간과 스토리지를 낭비하고 있었다.
opt-in으로 전환하고 나니 백업 대상이 명확해졌다. 각 서비스의 Helm values에 annotation이 선언되어 있으니, 어떤 볼륨이 백업되는지 코드만 보면 알 수 있다. 새 서비스를 추가할 때도 annotation을 넣을지 말지 의식적으로 판단하게 된다.
참고 자료
관련 콘텐츠
Velero로 Kubernetes 백업 시스템 구축하기
Homelab K8s 클러스터에 Velero + MinIO 백업 시스템을 구축하고, CSI 스냅샷 실패를 FSB로 해결한 뒤 복원까지 검증한 과정
KubernetesVelero 백업, 같은 클러스터에 저장하면 DR이 아니다
Velero 백업이 같은 클러스터의 MinIO에 저장되어 있었다. 클러스터가 죽으면 백업도 같이 사라진다. OCI에 Garage를 배포하고 CronJob으로 DR 복제를 구성한 뒤, DB Hook으로 백업 데이터의 일관성까지 확보한 과정.
KubernetesKubernetes StatefulSet 노드 이동 시 다운타임, 어떻게 줄일까?
관리형 Kubernetes에서 Block Storage + StatefulSet 조합의 구조적 한계와 해결 방안