[EKS] backup & restore Velero
Velero는 Kubernetes 클러스터의 안전한 백업과 복구를 지원하며, 다양한 클라우드 환경에서 리소스 마이그레이션을 간편하게 수행합니다.
개요
Velero는 안전하게 백업과 복구 DR을 수행할 수 있는 오픈 소스 툴입니다. 동시에 k8s 클러스터 리소스와 영구 볼륨의 여러 마이그레이션 방법을 지원합니다.
- 클러스터를 백업하고 손실에 대비합니다.
- 클러스터 리소스를 다른 클러스터(AWS, Azure를 포함한)로 마이그레이션합니다.
- 프로덕션 클러스터를 개발 및 테스트 클러스터로 복제합니다.\
Velero는 다음으로 구성될 수 있습니다.
- 클러스터에서 실행되는 서버
- 로컬에서 실행되는 명령줄 클라이언트
backup 작동 방식
각각의 Velero 작업(온디맨드 백업, 예약된 백업, 복원)은 Kubernetes Custom Resource Definition(CRD)으로 정의되고 etcd에 저장되는 커스텀 리소스입니다. Velero는 또한 백업, 복원 및 모든 관련 작업을 수행하기 위해 커스텀 리소스를 처리하는 컨트롤러들을 포함하고 있습니다.
클러스터의 모든 오브젝트들을 백업하거나 복원할 수 있으며, 타입, 네임스페이스, 그리고/또는 레이블을 기준으로 오브젝트들을 필터링할 수 있습니다. Velero는 재해 복구 사용 사례에 이상적이며, 업그레이드와 같은 클러스터에 대한 시스템 작업을 수행하기 전에 애플리케이션 상태를 스냅샷하는 데에도 적합합니다.
On-demand backups
백업 작업은 다음과 같이 진행됩니다:
- 복사된 Kubernetes 오브젝트들을 tar 파일로 묶어 클라우드 오브젝트 스토리지에 업로드합니다.
- 지정된 경우, 영구 볼륨의 디스크 스냅샷을 생성하기 위해 클라우드 프로바이더 API를 호출합니다.
백업 중에 실행될 백업 훅을 선택적으로 지정할 수 있습니다. 예를 들어, 스냅샷을 생성하기 전에 데이터베이스에게 메모리 내 버퍼를 디스크로 플러시하도록 지시해야 할 수 있습니다. 백업 훅에 대한 자세한 내용은 아래 링크를 참조해주세요.
클러스터 백업은 완전히 원자적이지 않다는 점에 유의하세요. 백업 시점에 Kubernetes 오브젝트가 생성되거나 편집 중인 경우 백업에 포함되지 않을 수 있습니다. 일관성 없는 정보가 캡처될 가능성은 낮지만, 가능성은 존재합니다.
Scheduled backups
스케줄 작업 을 통해 데이터를 반복적인 간격으로 백업할 수 있습니다. 언제든지 예약된 백업을 만들 수 있으며, 첫 번째 백업은 스케줄의 지정된 간격으로 수행됩니다. 이러한 간격은 Cron 표현식으로 지정됩니다.
Velero는 스케줄에서 생성된 백업을 이름으로 저장하며 <SCHEDULE NAME>-<TIMESTAMP>
, 여기서는 YYYYMMDDhhmmss<TIMESTAMP>
형식으로 지정됩니다 . 자세한 내용은 아래 링크를 참조하세요 .
backup workflow

velero backup create test-backup
를 실행하면:
- Velero 클라이언트가
Backup
오브젝트를 생성하기 위해 Kubernetes API 서버에 호출을 합니다. BackupController
가 새로운Backup
오브젝트를 감지하고 유효성 검사를 수행합니다.BackupController
가 백업 프로세스를 시작합니다. API 서버에 리소스를 쿼리하여 백업할 데이터를 수집합니다.BackupController
가 백업 파일을 업로드하기 위해 오브젝트 스토리지 서비스(예: AWS S3)를 호출합니다.
기본적으로 velero backup create
는 모든 영구 볼륨의 디스크 스냅샷을 생성합니다. 추가 플래그를 지정하여 스냅샷을 조정할 수 있습니다. 사용 가능한 플래그를 확인하려면 velero backup create --help
를 실행하세요. 스냅샷은 --snapshot-volumes=false
옵션으로 비활성화할 수 있습니다.
Restore 작동 방식
복원 작업을 통해 이전에 생성된 백업에서 모든 객체와 영구 볼륨을 복원할 수 있습니다.
또한 필터링된 객체와 영구 볼륨의 하위 집합만 복원할 수도 있습니다. Velero는 다중 네임스페이스 재매핑을 지원합니다. 예를 들어, 단일 복원에서 "abc" 네임스페이스의 객체를 "def" 네임스페이스 아래에서 재생성할 수 있고, "123" 네임스페이스의 객체를 "456" 아래에서 재생성할 수 있습니다.
복원의 기본 이름은 <BACKUP NAME>-<TIMESTAMP>
이며, 여기서 <TIMESTAMP>
는 YYYYMMDDhhmmss 형식입니다. 사용자 지정 이름을 지정할 수도 있습니다. 복원된 객체에는 키가 velero.io/restore-name
이고 값이 <RESTORE NAME>
인 레이블도 포함됩니다.
기본적으로 백업 스토리지 위치는 읽기-쓰기 모드로 생성됩니다. 그러나 복원 중에는 백업 스토리지 위치를 읽기 전용 모드로 구성할 수 있으며, 이는 해당 스토리지 위치에 대한 백업 생성 및 삭제를 비활성화합니다. 이는 복원 시나리오 중에 실수로 백업이 생성되거나 삭제되는 것을 방지하는 데 유용합니다.
선택적으로 복원 중이나 리소스가 복원된 후 실행될 복원 훅을 지정할 수 있습니다. 예를 들어, 데이터베이스 애플리케이션 컨테이너가 시작되기 전에 사용자 지정 데이터베이스 복원 작업을 수행해야 할 수 있습니다.
Restore workflow
velero restore create
를 실행하면:
- Velero 클라이언트가 Kubernetes API 서버에
Restore
객체를 생성하기 위한 호출을 합니다. RestoreController
가 새로운 Restore 객체를 감지하고 유효성 검사를 수행합니다.RestoreController
가 객체 스토리지 서비스에서 백업 정보를 가져옵니다. 그런 다음 백업된 리소스가 새 클러스터에서 작동하도록 하기 위해 일부 전처리를 실행합니다. 예를 들어, 백업된 API 버전을 사용하여 복원 리소스가 대상 클러스터에서 작동하는지 확인합니다.RestoreController
가 복원 프로세스를 시작하여 적격한 각 리소스를 한 번에 하나씩 복원합니다.
기본적으로 Velero는 비파괴적 복원을 수행합니다. 즉, 대상 클러스터의 데이터를 삭제하지 않습니다. 백업의 리소스가 대상 클러스터에 이미 존재하는 경우 Velero는 해당 리소스를 건너뜁니다. --existing-resource-policy
복원 플래그를 사용하여 대신 업데이트 정책을 사용하도록 Velero를 구성할 수 있습니다. 이 플래그가 update
로 설정되면 Velero는 대상 클러스터의 기존 리소스를 백업의 리소스와 일치하도록 업데이트를 시도합니다.
Velero 복원 프로세스에 대한 자세한 내용은 복원 참조 페이지를 참조하십시오.
Backed-up API versions
Velero는 각 그룹/리소스에 대한 Kubernetes API 서버의 기본 버전을 사용하여 리소스를 백업합니다. 리소스를 복원할 때 복원이 성공하려면 대상 클러스터에 동일한 API 그룹/버전이 존재해야 합니다.
예를 들어, 백업 중인 클러스터에 things
API 그룹에 gizmos
리소스가 있고, 그룹/버전이 things/v1alpha1
, things/v1beta1
, things/v1
이며, 서버의 선호 그룹/버전이 things/v1
인 경우, 모든 gizmos
는 things/v1
API 엔드포인트에서 백업됩니다. 이 클러스터의 백업을 복원할 때, gizmos
를 복원하려면 대상 클러스터에 반드시 things/v1
엔드포인트가 있어야 합니다. things/v1
이 대상 클러스터에서 선호 버전일 필요는 없으며, 존재하기만 하면 됩니다.
백업 만료 설정
백업을 생성할 때 --ttl <DURATION>
플래그를 추가하여 TTL(time to live)을 지정할 수 있습니다. Velero가 기존 백업 리소스가 만료된 것을 확인하면 다음을 제거합니다:
- 백업 리소스
- 클라우드 객체 스토리지의 백업 파일
- 모든 PersistentVolume 스냅샷
- 모든 관련 복원
TTL 플래그를 사용하면 사용자가 --ttl 24h0m0s
형식으로 시간, 분, 초 단위로 백업 보존 기간을 지정할 수 있습니다. 지정하지 않으면 기본 TTL 값 30일이 적용됩니다.
만료의 효과는 즉시 적용되지 않으며, 기본적으로 gc-컨트롤러가 매시간 조정 루프를 실행할 때 적용됩니다. 필요한 경우 --garbage-collection-frequency <DURATION>
플래그를 사용하여 조정 루프의 빈도를 조정할 수 있습니다.
백업 삭제에 실패하면 백업 커스텀 리소스에 velero.io/gc-failure=<Reason>
레이블이 추가됩니다. 이 레이블을 사용하여 삭제에 실패한 백업을 필터링하고 선택할 수 있습니다.
구현된 이유는 다음과 같습니다:
- BSLNotFound: 백업 스토리지 위치를 찾을 수 없음
- BSLCannotGet: API 서버에서 '찾을 수 없음' 이외의 이유로 백업 스토리지 위치를 검색할 수 없음
- BSLReadOnly: 백업 스토리지 위치가 읽기 전용임
object storage sync
Velero는 객체 스토리지를 신뢰할 수 있는 소스로 취급합니다. 올바른 백업 리소스가 항상 존재하는지 지속적으로 확인합니다. 스토리지 버킷에 적절한 형식의 백업 파일이 있지만 Kubernetes API에 해당하는 백업 리소스가 없는 경우, Velero는 객체 스토리지의 정보를 Kubernetes와 동기화합니다.
이를 통해 원본 백업 객체가 새 클러스터에 존재하지 않는 클러스터 마이그레이션 시나리오에서 복원 기능이 작동할 수 있습니다.
마찬가지로, Completed
백업 객체가 Kubernetes에는 있지만 객체 스토리지에는 없는 경우, 백업 Tarball 더 이상 존재하지 않으므로 Kubernetes에서 삭제됩니다. Failed
또는 PartiallyFailed
백업은 객체 스토리지 동기화에 의해 제거되지 않습니다.
Velero EKS Backup & Restore Test
Requirements
- 사전 구성된 EKS 환경이 필요합니다.
- 백업용 S3 버킷 생성과 작업에 필요한 IAM 역할을 생성할 수 있는 권한이 필요합니다.
현재 테스트 문서에서 IAM OIDC 공급자가 필요합니다.
# check again
aws iam list-open-id-connect-providers | grep $oidc_id
# output
- Arn: arn:aws:iam::xxxxxxxxxx:oidc-provider/oidc.eks.us-east-1.amazonaws.com/id/xxxxxxxxxxxxxxxxxxxxxxx
EKS workflow

편의를 위해 EKSv1와 EKSv2로 구분하여 작성하였고 EKSv1은 백업시키는 대상이며 EKSv2는 복구되는 대상입니다.
EKSv1 - Velero backup
- 백업에 필요한 버킷을 생성합니다.
BUCKET=<BUCKETNAME>
REGION=<REGION>

- velero 정책을 설정합니다.
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"ec2:DescribeVolumes",
"ec2:DescribeSnapshots",
"ec2:CreateTags",
"ec2:CreateVolume",
"ec2:CreateSnapshot",
"ec2:DeleteSnapshot"
],
"Resource": "*"
},
{
"Effect": "Allow",
"Action": [
"s3:GetObject",
"s3:DeleteObject",
"s3:PutObject",
"s3:AbortMultipartUpload",
"s3:ListMultipartUploadParts",
"s3:ListBucket"
],
"Resource": [
"${YOUR_BUCKET_ARN}/*",
"${YOUR_BUCKET_ARN}"
]
}
]
}

EKSv1에서 serviceaccount를 통해 Velero가 해당 역할을 수임하여 들어갈 수 있도록 생성합니다.
- eksctl은 CloudFormation으로 생성됩니다.

eksctl create iamserviceaccount \
--cluster=bjchoi-test-cluster-eks \
--name=velero-server \
--namespace=velero \
--role-name=Velero_Backup_Restore_Role_bjchoi \
--role-only \
--attach-policy-arn=arn:aws:iam::759320821027:policy/VeleroEC2VolumeAndS3AccessPolicy_bjchoi \
--approve
- Install Velero in EKSv1 cluster
velero를 설치하기 전 S3 및 Helm config 파일을 구성합니다.
configuration:
backupStorageLocation:
- bucket: bjchoi-standard-bucket
prefix: eks-cluster-backup
provider: aws
volumeSnapshotLocation:
- config:
region: ap-northeast-2
provider: aws
initContainers:
- name: velero-plugin-for-aws
image: velero/velero-plugin-for-aws:v1.7.1
volumeMounts:
- mountPath: /target
name: plugins
credentials:
useSecret: false
serviceAccount:
server:
annotations:
eks.amazonaws.com/role-arn: "arn:aws:iam::759320821027:role/VeleroBackupIAMRole_bjchoi"
helm을 설치합니다.
# add helm repository
helm repo add vmware-tanzu https://vmware-tanzu.github.io/helm-charts
# 업그레이드 하는 경우
helm upgrade velero vmware-tanzu/velero \
--namespace velero \
-f velero-config.yaml
# create velero-config.yaml file for install velero helm chart
helm upgrade velero vmware-tanzu/velero \
--namespace velero \
-f velero-config.yaml
정상적으로 서비스가 올라온 것을 확인해볼 수 있습니다.
$ k get all -n velero
NAME READY STATUS RESTARTS AGE
pod/velero-5d68ddfcbb-dnmg4 1/1 Running 0 63s
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/velero ClusterIP 172.20.7.95 <none> 8085/TCP 63s
NAME READY UP-TO-DATE AVAILABLE AGE
deployment.apps/velero 1/1 1 1 63s
NAME DESIRED CURRENT READY AGE
replicaset.apps/velero-5d68ddfcbb 1 1 1 63s
- backup 생성
# velero create backup <DIRECTORY_NAME> <--OPTION>
velero create backup 2024-12-19-1320 --ttl 4320h # 6개월
$ velero get backup
NAME STATUS ERRORS WARNINGS CREATED EXPIRES STORAGE LOCATION SELECTOR
2024-12-19-1320 Completed 0 0 2024-12-19 13:29:58 +0900 KST 179d default <none>
서비스가 정상적으로 생성된 것을 확인할 수 있습니다.

다음과 같이 저장됩니다.
EKSv2 - Velero restore
- 복구용 테스트 EKSv2를 생성합니다.

이때 사용하려는 addon 및 Controller에 대한 설정은 모두 유지되어야합니다.
- 새로운 EKS Cluster의 config을 가져와서 등록합니다.
$ aws eks update-kubeconfig --region ap-northeast-2 --name bjchoi-test-cluster-eks2
Added new context arn:aws:eks:ap-northeast-2:759320821027:cluster/bjchoi-test-cluster-eks2 to /Users/byeongjuchoi/.kube/config
backup용 eks와 restore용 eks2가 존재하는 것을 확인할 수 있습니다.
k config get-contexts
-------------------------------------------
CURRENT NAME CLUSTER AUTHINFO NAMESPACE
* bjchoi-test-cluster-eks2 bjchoi-test-cluster-eks2 bjchoi-test-cluster-eks2
docker-desktop docker-desktop docker-desktop
bjchoi-test-cluster-eks bjchoi-test-cluster-eks smileshark_bjchoi
- 생성한 EKS Cluster에서 IAM OIDC provider를 위한 ID를 가져옵니다.

eksctl iam-oidc-provider가 정상적으로 생성되지 않은 경우
eksctl을 통한 방법
eksctl utils associate-iam-oidc-provider \
--cluster bjchoi-test-cluster-eks2 \
--region ap-northeast-2 \
--approve
aws iam list-open-id-connect-providers | grep A68D854E61B38B5F7BF2E01B38083309
"Arn": "arn:aws:iam::759320821027:oidc-provider/oidc.eks.ap-northeast-2.amazonaws.com/id/A68D854E61B38B5F7BF2E01B38083309"
- EKSv2에서 serviceaccount를 통해 Velero가 해당 역할을 수임하여 들어갈 수 있도록 생성합니다.
eksctl create iamserviceaccount \
--cluster=bjchoi-test-cluster-eks2 \
--name=velero-server \
--namespace=velero \
--attach-policy-arn=arn:aws:iam::759320821027:policy/VeleroEC2VolumeAndS3AccessPolicy_bjchoi \
--approve
$ k get serviceaccounts -A | grep velero
velero default 0 50m
velero velero-server 0 50m
Account가 생성된 것을 확인합니다.
- Velero 설치
앞서 생성한 iam service account를 통해 Velero를 설치합니다.
# VeleroEC2VolumeAndS3AccessPolicy_bjchoi
configuration:
backupStorageLocation:
- bucket: bjchoi-standard-bucket
prefix: eks-cluster-backup
provider: aws
volumeSnapshotLocation:
- config:
region: ap-northeast-2
provider: aws
initContainers:
- name: velero-plugin-for-aws
image: velero/velero-plugin-for-aws:v1.7.1
volumeMounts:
- mountPath: /target
name: plugins
credentials:
useSecret: false
serviceAccount:
server:
annotations:
eks.amazonaws.com/role-arn: "arn:aws:iam::759320821027:role/VeleroEC2VolumeAndS3AccessPolicy_bjchoi"
helm install velero vmware-tanzu/velero \
--create-namespace \
--namespace velero \
-f velero-config.yaml
설치가 완료된다면 velero get backup을 통해 확인할 수 있습니다.
이전에 EKSv1의 백업 리소스를 확인할 수 있습니다.
$ velero get backup
NAME STATUS ERRORS WARNINGS CREATED EXPIRES STORAGE LOCATION SELECTOR
2024-12-19-1320 Completed 0 0 2024-12-19 13:29:58 +0900 KST 176d default <none>
복구 실행하기
$ velero create restore 2024-12-23-0951-restore --from-backup 2024-12-19-1320
Restore request "2024-12-23-0951-restore" submitted successfully.
Run `velero restore describe 2024-12-23-0951-restore` or `velero restore logs 2024-12-23-0951-restore` for more details.
Nuke로 인한 EKS 클러스터 재생성 후 Velero 복원 시 ServiceAccount 관련 주의사항
- Velero로 백업된 리소스 중 ServiceAccount를 사용하는 Helm 차트들은 복원 시 백업 시점의 ServiceAccount 설정을 그대로 가져옵니다.
- EKS의 OIDC(OpenID Connect)를 통해 IAM Role과 연결된 ServiceAccount의 경우, 새로운 클러스터에서 정상 작동하기 위해서는 다음 두 가지 방법 중 하나를 선택해야 합니다:
- 기존 IAM Role의 신뢰 관계(Trust Relationship)를 새 클러스터의 OIDC Provider로 업데이트
- eksctl로 새로운 ServiceAccount를 생성하여 자동으로 새 클러스터의 OIDC Provider와 연결된 IAM Role 설정 적용
따라서 addon 같은 부분은 이전에 설치해두는 것이 좋습니다.
alb controller
helm upgrade aws-load-balancer-controller eks/aws-load-balancer-controller \
-n kube-system \
--set clusterName=bjchoi-seoul-eks-2024-12-23 \
--set serviceAccount.create=false \
--set serviceAccount.name=aws-load-balancer-controller
정상적으로 백업된 것을 확인할 수 있습니다.
$ k get pods -A
NAMESPACE NAME READY STATUS RESTARTS AGE
argo-rollouts argo-rollouts-65867bc597-n69wf 1/1 Running 0 41m
argocd argocd-application-controller-0 1/1 Running 0 41m
argocd argocd-applicationset-controller-684cd5f5cc-jj8qb 1/1 Running 0 41m
argocd argocd-dex-server-77c55fb54f-gpltr 1/1 Running 0 41m
argocd argocd-notifications-controller-69cd888b56-z45hp 1/1 Running 0 41m
argocd argocd-redis-55c76cb574-xqhpq 1/1 Running 0 41m
argocd argocd-repo-server-584d45d88f-ztcjj 1/1 Running 0 41m
argocd argocd-server-8667f8577-tj2pw 1/1 Running 0 41m
dev dev-test-app-5c86d5cf6b-4dstl 1/1 Running 0 11m
dev dev-test-app-5c86d5cf6b-j5gqn 1/1 Running 0 11m
kube-system aws-load-balancer-controller-74cdc49955-cf68j 1/1 Running 0 25m
kube-system aws-load-balancer-controller-74cdc49955-ggbsd 1/1 Running 0 25m
kube-system aws-node-gspsj 2/2 Running 0 107m
kube-system aws-node-k8c9p 2/2 Running 0 107m
kube-system aws-node-vmccl 2/2 Running 0 107m
kube-system coredns-5b9dfbf96-cg74p 1/1 Running 0 116m
kube-system coredns-5b9dfbf96-gg26s 1/1 Running 0 116m
kube-system ebs-csi-controller-9d9bd5db6-5d529 6/6 Running 0 102m
kube-system ebs-csi-controller-9d9bd5db6-jxhg2 6/6 Running 0 102m
kube-system ebs-csi-node-g428z 3/3 Running 0 102m
kube-system ebs-csi-node-lftxb 3/3 Running 0 102m
kube-system ebs-csi-node-ppklm 3/3 Running 0 102m
kube-system eks-pod-identity-agent-4s7gg 1/1 Running 0 107m
kube-system eks-pod-identity-agent-hj84v 1/1 Running 0 107m
kube-system eks-pod-identity-agent-tv2fh 1/1 Running 0 107m
kube-system kube-proxy-sdjms 1/1 Running 0 107m
kube-system kube-proxy-wcltb 1/1 Running 0 107m
kube-system kube-proxy-zxsc4 1/1 Running 0 107m
kube-system metrics-server-d5865ff47-k6xt8 1/1 Running 1 (41m ago) 41m
monitoring loki-loki-distributed-distributor-58bd46cc7-9lmz5 1/1 Running 0 41m
monitoring loki-loki-distributed-gateway-67686fdf98-wq5sg 1/1 Running 0 41m
monitoring loki-loki-distributed-ingester-0 1/1 Running 0 41m
monitoring loki-loki-distributed-querier-0 1/1 Running 0 41m
monitoring loki-loki-distributed-query-frontend-7dd49cd98c-2vmxt 1/1 Running 0 41m
monitoring my-grafana-74545c54c4-zrmkh 1/1 Running 0 41m
monitoring promtail-pn5wk 1/1 Running 0 41m
monitoring promtail-rbrzr 1/1 Running 0 41m
monitoring promtail-xcxxz 1/1 Running 0 41m
velero velero-5d68ddfcbb-cvsr7 1/1 Running 0 47m