제 의견은 “GitOps를 1차 복구 수단으로 두고, Velero는 Git으로 재생성되지 않는 런타임 상태만 선별 백업”하는 구조가 가장 좋습니다. 즉, Velero를 “클러스터 전체 덤프 도구”로 쓰기보다 namespace/app 단위 운영 백업 + PV 일부 백업 + DR 검증 도구로 쓰는 게 맞습니다.
| 계층 | 목적 | 주 백업 수단 | 백업 대상 |
|---|---|---|---|
| 1. Source of Truth | 재설치/재배포 기준 | Git, Helm repo, OCI registry, Nexus/Harbor 백업 | ArgoCD Application, Helm values, Kustomize, Cilium/Ingress/StorageClass/정책 YAML |
| 2. Control Plane DR | control-plane/etcd 장애 복구 | etcd snapshot | Kubernetes 전체 API 상태 |
| 3. Runtime State | Git에 없는 K8s 상태 복구 | Velero | 동적 namespace, runtime Secret, cert Secret, 일부 CR, PVC metadata |
| 4. Workload Data | 실제 업무 데이터 복구 | 앱 네이티브 백업, CSI snapshot, DB dump, Velero FSB/CSI Data Mover | DB, 사용자 홈, Airflow metadata DB, Jupyter PVC, Longhorn/OpenEBS PVC 등 |
Kubernetes의 모든 API 객체는 etcd에 저장되므로, control-plane 전체 장애나 전체 클러스터 롤백 시나리오에는 etcd snapshot이 별도로 필요합니다. Kubernetes 공식 문서도 control-plane 노드 전체 손실 같은 재난 상황을 대비해 etcd snapshot을 주기적으로 백업하고, snapshot 파일에는 민감한 정보가 포함되므로 암호화하라고 설명합니다. (Kubernetes) Velero는 Kubernetes 리소스와 Persistent Volume을 백업/복구/마이그레이션하는 도구이므로, etcd 전체 복구와는 목적이 다릅니다. (Velero)
Git에 있는 리소스를 Velero로도 복구하면, 복구 후 ArgoCD가 다시 sync하면서 중복 생성, prune 충돌, 버전 불일치, Helm release metadata 꼬임이 생길 수 있습니다. 그래서 아래처럼 나누는 게 좋습니다.
Git에서 복구할 것
| 영역 | 예시 |
|---|---|
| 플랫폼 설치 선언 | Cilium, Ingress Controller, cert-manager, external-secrets, ArgoCD, Longhorn/OpenEBS, monitoring stack |
| 클러스터 공통 정책 | Namespace 기본 템플릿, ResourceQuota, LimitRange, RBAC, NetworkPolicy, PodSecurity, OPA/Gatekeeper/Kyverno 정책 |
| 애플리케이션 선언 | Helm values, ArgoCD Application/AppProject, Kustomize overlays |
| StorageClass/IngressClass | StorageClass, VolumeSnapshotClass, IngressClass, GatewayClass |
| 운영 표준 | SOP, 작업계획서, 장애대응 절차, bootstrap 절차 |
Git 외부에서 반드시 별도 보호할 것
| 영역 | 이유 |
|---|---|
| Git 서버 자체 | Git이 죽으면 GitOps 복구 기준이 사라짐 |
| Helm chart repo / OCI registry / Nexus / Harbor | manifest는 있어도 image/chart가 없으면 배포 불가 |
| private CA, root/intermediate CA, KMS key, etcd encryption-provider-config | 재생성하면 기존 Secret/PVC/인증 체계와 안 맞을 수 있음 |
| Kubespray inventory, group_vars, host_vars, SSH key, bootstrap script | 클러스터 재구축의 실제 기준 |
| ArgoCD repo credential, cluster credential | Git에는 보통 평문으로 두지 않음 |
| Vault unseal key / recovery key / root token 관리 절차 | Velero로만 보호하면 안 됨 |
Velero는 아래 대상을 중심으로 가져가는 게 좋습니다. Velero는 namespace, resource type, label selector, resource policy로 백업 범위를 제어할 수 있고, 기본값은 필터가 없으면 모든 객체를 포함합니다. (Velero)
| 우선순위 | Velero 백업 대상 | 이유 |
|---|---|---|
| 높음 | Git에 없는 Secret | ArgoCD repo secret, cluster secret, webhook TLS secret, 수동 생성 credential |
| 높음 | cert-manager가 생성한 TLS Secret | Certificate 리소스는 Git에 있어도 실제 private key Secret은 런타임 생성 |
| 높음 | 동적으로 생성된 namespace와 그 안의 RBAC/Quota/LimitRange | 사용자 sandbox, Airflow/Jupyter 사용자 namespace 등 |
| 높음 | Operator가 생성했지만 재생성 비용이 큰 CR/Secret | Keycloak, ExternalSecret, Vault Agent, Ingress webhook 등 |
| 중간 | ArgoCD namespace 일부 | Git에 app-of-apps가 있어도 repo credential/cluster credential은 별도 보호 필요 |
| 중간 | 작은 규모의 PVC | ArgoCD Redis는 보통 제외 가능하지만, Keycloak DB, Airflow metadata DB, Jupyter home 등은 검토 |
| 낮음 | 일반 Deployment/Service/Ingress | 대부분 Git에서 재생성 가능 |
| 낮음 | Status성 리소스 | Endpoint, Lease, Event, ReplicaSet, Pod 등은 복구 가치 낮음 |
정리하면, Velero의 기본 백업 단위는 “namespace 전체”가 아니라 “백업 등급이 붙은 namespace/resource”가 되어야 합니다. 예를 들어 namespace에 다음 같은 label을 붙이는 식입니다.
metadata:
labels:
backup.platform.io/enabled: "true"
backup.platform.io/tier: "critical"
backup.platform.io/pv: "csi"
그리고 Velero schedule은 label selector 기반으로 잡습니다. Velero는 label selector 기반 include도 지원합니다. (Velero)
아래는 복구 가치보다 부작용이 큰 경우가 많습니다.
| 제외 대상 | 제외 이유 |
|---|---|
| Pod, ReplicaSet, Endpoint, EndpointSlice, Event, Lease | 컨트롤러가 재생성하는 런타임 상태 |
| CiliumEndpoint, CiliumNode 등 CNI 런타임 CR | 네트워크 상태성 리소스라 복원 부작용 가능 |
| kube-system 전체 | etcd snapshot 또는 Kubespray/GitOps로 복구하는 게 안전 |
| Spark shuffle, Trino spill, StarRocks cache, local cache PVC | 캐시/임시 데이터 |
| MinIO AIStor 데이터 디스크/DirectPV 데이터 | 규모가 크고 object store 자체 보호 방식이 별도여야 함 |
| Prometheus TSDB 장기 데이터 | remote write 또는 object storage 기반 장기보관이 더 적합 |
| OpenSearch 데이터 | OpenSearch snapshot repository 방식이 더 적합 |
| Jenkins workspace | artifact/Nexus/Git 기준으로 재생성하는 게 일반적 |
특히 MinIO AIStor 자체 데이터는 Velero 백업 대상이 아닙니다. 10~20PiB급 object store 데이터를 Velero FSB나 PV 백업으로 옮기는 건 성능, 시간, 일관성, 비용 측면에서 맞지 않습니다. AIStor 데이터는 AIStor의 versioning/object lock/replication/site replication/운영 절차로 보호하고, Velero는 AIStor를 사용하는 다른 K8s 워크로드의 metadata/PVC를 보호하는 쪽으로 역할을 분리하는 게 맞습니다.
MinIO AIStor 문서도 object transition/tiering은 비용 최적화 기능이지 백업/복구 기능이 아니며, DR 요구에는 site replication 또는 bucket replication을 사용하라고 설명합니다. (MinIO AIStor Documentation)
Velero의 File System Backup은 거의 모든 Kubernetes volume에 적용할 수 있다는 장점이 있지만, live filesystem을 읽기 때문에 동일 시점 일관성이 snapshot 방식보다 낮고, Node Agent가 root 또는 privileged 권한을 요구할 수 있습니다. Velero 문서에서도 FSB는 beta quality이며, live filesystem 기반이라 snapshot보다 일관성이 낮다고 설명합니다. (Velero)
가능하면 우선순위는 아래가 좋습니다.
| 데이터 유형 | 권장 백업 방식 |
|---|---|
| PostgreSQL/MySQL/MariaDB | DB native dump, physical backup, operator backup |
| Keycloak DB | DB native backup + realm export 검토 |
| Vault | Vault snapshot/Raft snapshot, unseal/recovery key 관리 |
| OpenSearch | OpenSearch snapshot repository to S3 |
| Prometheus 장기 데이터 | Thanos/Mimir/remote write/object storage |
| Longhorn PVC | Longhorn native backup 또는 CSI snapshot + Velero |
| OpenEBS/일반 CSI PVC | CSI snapshot 가능 여부 확인 후 Velero CSI Data Mover |
| NFS/local/CSI snapshot 불가 PVC | Velero FSB/Kopia, 단 중요 데이터는 app quiesce hook 필요 |
| Jupyter 사용자 home | 중요도에 따라 FSB 또는 별도 파일 백업 |
| Spark/Trino/StarRocks cache | 백업 제외 |
Velero의 CSI Snapshot Data Movement는 CSI snapshot 데이터를 backup storage로 이동하는 기능이고, 가능할 경우 live PV를 읽는 FSB보다 우선 사용하는 것이 권장됩니다. 다만 source cluster가 CSI snapshot v1 API를 지원하고 CSI driver가 volume snapshot을 지원해야 합니다. (Velero)
AIStor에 Velero backup bucket을 만들 때는 “그냥 S3 bucket 하나”가 아니라 복구용 저장소로 설계해야 합니다.
| 항목 | 권장 |
|---|---|
| Bucket | cluster별 또는 env별 분리: k8s-velero-prod, k8s-velero-dev |
| Prefix | velero/<cluster-name>/<date-or-schedule> |
| 계정 | cluster별 Velero 전용 access key |
| 권한 | 해당 bucket/prefix에만 List/Get/Put/Delete 허용 |
| 보호 | versioning + object lock + lifecycle |
| DR | 다른 AIStor site/bucket으로 replication |
| TLS | 사내 CA bundle을 Velero에 명시 |
| Failure domain | 백업 대상 클러스터와 다른 장애 도메인에 위치 |
MinIO AIStor Object Lock은 WORM 방식으로 versioned object 삭제를 보호하며, bucket 생성 시점에만 활성화할 수 있고 object locking을 활성화하면 versioning도 활성화됩니다. (MinIO AIStor Documentation) 이 기능은 Velero 백업을 실수 삭제나 랜섬웨어성 삭제로부터 보호하는 데 유용하지만, Velero TTL이 오래된 백업을 삭제하려 할 때 object lock retention과 충돌할 수 있습니다. 따라서 Velero TTL ≥ Object Lock retention + 여유기간으로 맞추고, lifecycle은 Velero TTL보다 뒤쪽에서 orphan 정리용으로 쓰는 편이 안전합니다.
사내 CA를 쓰는 HTTPS AIStor endpoint라면 Velero 설치 시 --cacert를 사용하거나 BackupStorageLocation의 objectStorage.caCert에 CA bundle을 넣어야 합니다. Velero 문서도 self-signed/S3-compatible storage에서 CA bundle을 제공하는 방식을 안내합니다. (Velero) 다만 AIStor endpoint 앞단에서 클라이언트 인증서 기반 mTLS를 강제하면 Velero 호환성을 별도 검증해야 합니다. Velero 문서에는 custom S3 server가 client certificate를 요구하는 경우 Velero client가 TLS handshake에 client certificate를 포함하지 않아 문제가 될 수 있다고 되어 있습니다. (Velero)
설치 방향은 대략 아래와 같습니다. 실제 plugin 버전은 운영 K8s 버전, Velero 버전, air-gap mirror 상태에 맞춰 고정해야 합니다.
velero install \
--provider aws \
--plugins <internal-registry>/velero/velero-plugin-for-aws:<pinned-version> \
--bucket k8s-velero-prod \
--prefix velero/prod-compute-cluster-a \
--secret-file ./credentials-velero \
--backup-location-config region=minio,s3ForcePathStyle=true,s3Url=https://aistor-backup.example.internal \
--use-node-agent \
--cacert ./company-root-ca.pem
Velero의 MinIO 예시도 S3-compatible storage에 대해 provider aws, AWS plugin, s3ForcePathStyle, s3Url 같은 구성을 사용합니다. 다만 공식 예시는 평가용이며 production MinIO 구성은 별도 설계가 필요하다고 명시되어 있습니다. (Velero)
BackupStorageLocation은 GitOps로 관리하되, credential Secret 자체는 ExternalSecret/Vault/SealedSecret 등으로 관리하는 편이 좋습니다.
apiVersion: velero.io/v1
kind: BackupStorageLocation
metadata:
name: aistor-primary
namespace: velero
spec:
provider: aws
objectStorage:
bucket: k8s-velero-prod
prefix: velero/prod-compute-cluster-a
# 사내 CA 사용 시 base64 인코딩된 CA bundle
# caCert: <base64-encoded-ca-bundle>
config:
region: minio
s3ForcePathStyle: "true"
s3Url: https://aistor-backup.example.internal
credential:
name: velero-aistor-credential
key: cloud
BackupStorageLocation은 bucket, prefix, CA certificate, credential, accessMode 등을 정의할 수 있습니다. (Velero)
ArgoCD, cert-manager, ingress, external-secrets, keycloak 등에서 Git에 없는 Secret/동적 상태를 보호합니다.
apiVersion: velero.io/v1
kind: Schedule
metadata:
name: platform-runtime-daily
namespace: velero
spec:
schedule: "CRON_TZ=Asia/Seoul 0 2 * * *"
useOwnerReferencesInBackup: false
template:
ttl: 720h0m0s # 30일
storageLocation: aistor-primary
includedNamespaces:
- argocd
- cert-manager
- ingress-nginx
- external-secrets
- keycloak
includedResources:
- secrets
- configmaps
- serviceaccounts
- roles
- rolebindings
- applications.argoproj.io
- appprojects.argoproj.io
- certificates.cert-manager.io
- issuers.cert-manager.io
- clusterissuers.cert-manager.io
includeClusterResources: true
snapshotVolumes: false
Velero Schedule은 cron 기반으로 반복 백업을 만들고, TTL을 지정할 수 있습니다. Velero 문서의 Schedule API도 includedNamespaces, includedResources, excludedResources, includeClusterResources, ttl, snapshotVolumes, storageLocation 같은 필드를 제공합니다. (Velero)
사용자 namespace가 Git에서 모두 생성되는 게 아니라 포털이나 자동화 도구에서 동적으로 만들어진다면, namespace별 label을 기준으로 백업합니다.
apiVersion: velero.io/v1
kind: Schedule
metadata:
name: tenant-metadata-daily
namespace: velero
spec:
schedule: "CRON_TZ=Asia/Seoul 30 2 * * *"
template:
ttl: 720h0m0s
storageLocation: aistor-primary
labelSelector:
matchLabels:
backup.platform.io/enabled: "true"
includedResources:
- namespaces
- secrets
- configmaps
- serviceaccounts
- roles
- rolebindings
- resourcequotas
- limitranges
- networkpolicies.networking.k8s.io
- persistentvolumeclaims
excludedResources:
- pods
- replicasets.apps
- events
- events.events.k8s.io
- endpoints
- endpointslices.discovery.k8s.io
- leases.coordination.k8s.io
snapshotVolumes: false
중요 PVC만 별도 label로 opt-in하는 방식이 좋습니다. 전체 PVC를 무작정 FSB로 백업하면 대규모 환경에서 백업 트래픽, object 수, 복구시간이 감당하기 어려워질 수 있습니다.
apiVersion: velero.io/v1
kind: Schedule
metadata:
name: critical-pvc-daily
namespace: velero
spec:
schedule: "CRON_TZ=Asia/Seoul 0 3 * * *"
template:
ttl: 168h0m0s # 7일
storageLocation: aistor-primary
includedNamespaces:
- airflow
- jupyterhub
- keycloak
labelSelector:
matchLabels:
backup.platform.io/pv: "true"
snapshotVolumes: true
snapshotMoveData: true
datamover: velero
uploaderConfig:
parallelFilesUpload: 4
FSB/Kopia 또는 CSI Data Mover를 사용할 때 Velero는 parallel file upload 옵션으로 업로드 병렬도를 조정할 수 있습니다. (Velero) 대규모 환경에서는 처음부터 병렬도를 높이기보다, 야간 저부하 시간대에 작은 namespace부터 측정해 AIStor, 네트워크, kubelet, node-agent 부하를 봐야 합니다.
플랫폼 변경 전에는 schedule과 별도로 수동 백업을 하나 생성합니다.
velero backup create pre-change-$(date +%Y%m%d-%H%M) \
--from-schedule platform-runtime-daily \
--wait
Velero는 schedule에서 즉시 수동 백업을 생성할 수 있고, 이 경우 다음 정기 schedule에는 영향을 주지 않습니다. (Velero)
ArgoCD가 Velero Schedule CR을 GitOps로 관리하는 것은 좋습니다. 다만 Backup과 Restore 객체는 운영 중 자동 생성되는 런타임 객체이므로 ArgoCD가 prune하거나 diff noise를 만들지 않게 해야 합니다.
특히 Velero schedule에서 useOwnerReferencesInBackup: true를 쓰면 schedule 삭제 시 backup CR이 Kubernetes GC에 의해 삭제되고, Velero가 object storage metadata에서 다시 sync하면서 충돌할 수 있다고 Velero 문서가 경고합니다. (Velero) 따라서 GitOps 환경에서는 보통 다음 원칙을 권합니다.
spec:
useOwnerReferencesInBackup: false
그리고 ArgoCD에는 Velero의 Backup, Restore, PodVolumeBackup, PodVolumeRestore, DataUpload, DataDownload 같은 런타임 CR은 관리 대상에서 제외하거나 ignore/prune 예외를 둡니다.
ArgoCD 자체는 argocd admin export/import로 전체 ArgoCD 데이터를 export/import할 수 있습니다. (Argo CD) 다만 귀하 환경처럼 Application/AppProject가 Git에 있다면, ArgoCD export는 “주 복구 수단”보다는 빠른 RTO용 보조 백업 정도로 보는 게 좋습니다.
GitOps 환경이라도 etcd snapshot은 필요합니다. 이유는 다음입니다.
| 상황 | Git/Velero만으로 충분한가? | etcd snapshot 필요성 |
|---|---|---|
| 특정 app namespace 삭제 | 대체로 Velero + ArgoCD로 충분 | 낮음 |
| ArgoCD 오작동으로 리소스 대량 삭제 | Velero 유용 | 중간 |
| control-plane 노드 다수 손실 | 부족 | 높음 |
| etcd corruption | 부족 | 높음 |
| cluster 전체 rollback | etcd snapshot 필요 | 높음 |
| API object 전체 forensic 비교 | etcd snapshot/Velero metadata 모두 유용 | 중간 |
기본 권장 주기는 대략 이 정도입니다.
| 백업 | 주기 | 보관 |
|---|---|---|
| etcd snapshot | 4~6시간 또는 1일 1회 | 7~30일 |
| 변경 전 etcd snapshot | upgrade, CNI 변경, admission 변경, 대형 배포 전 | 7~14일 |
| Velero platform runtime | 1일 1회 | 30~90일 |
| Velero critical secret/runtime | 4~12시간 | 14~30일 |
| Velero PVC | 업무 RPO에 따라 | 7~30일 |
| DR 리허설 backup | 월 1회 | 3~6개월 |
etcd snapshot은 복구 시 전체 클러스터 상태를 특정 시점으로 되돌리는 성격이 강하므로, 일반적인 app 단위 복구에는 Velero를 쓰고, etcd는 break-glass control-plane DR 용도로 분리하는 것이 좋습니다.
BackupStorageLocation에는 accessMode가 있고 ReadWrite/ReadOnly를 설정할 수 있습니다. (Velero) 신규 클러스터 DR 리허설에서는 실수로 백업 저장소를 변경하지 않도록 ReadOnly로 시작하는 게 안전합니다.
귀하처럼 Cloud Native Data Lakehouse + GitOps + AIStor + 대규모 사용자 namespace 구조라면 다음 설계를 추천합니다.
Git/ArgoCD가 복구의 중심입니다. Git에 있는 manifest/Helm values는 Velero 복구 대상에서 원칙적으로 제외합니다.
Velero는 네 가지 대상만 강하게 가져갑니다.
runtime Secret, 동적 namespace, 운영자가 수동 생성한 리소스, 중요 소규모 PVC.
AIStor/MinIO 데이터 자체는 Velero로 백업하지 않습니다.
AIStor 데이터는 AIStor replication, object lock, versioning, lifecycle, site DR로 보호합니다.
Longhorn/OpenEBS PVC는 등급제로 나눕니다.
DB는 app-native backup 우선, 일반 PVC는 CSI snapshot/Data Mover, snapshot이 안 되는 경우만 FSB/Kopia를 사용합니다.
etcd snapshot은 반드시 별도 운영합니다.
GitOps가 있어도 control-plane 전체 재난에는 etcd snapshot이 필요합니다.
AIStor Velero bucket은 object lock/versioning/replication을 켭니다.
단, Velero TTL과 object lock retention이 충돌하지 않게 보관기간을 설계합니다.
DR 리허설을 자동화합니다.
월 1회 정도 빈 클러스터 또는 DR namespace에 restore test를 수행하고, 복구 소요시간/RTO, 누락 리소스, ArgoCD sync 충돌을 기록해야 합니다.
가장 현실적인 1차 도입안은 etcd daily + Velero platform-runtime daily + tenant metadata daily + critical PVC opt-in daily + pre-change on-demand 조합입니다. 이 정도면 GitOps 기준을 해치지 않으면서도, 실제 사고 때 Git만으로 복구되지 않는 영역을 꽤 잘 막을 수 있습니다.