Chuyển tới nội dung chính

Sao lưu và phục hồi Kubernetes với Velero

Velero là công cụ mã nguồn mở giúp sao lưu và phục hồi tài nguyên Kubernetes cùng persistent volume. Nó chạy một server trong cụm và một CLI trên máy bạn, đồng thời lưu bản sao lưu vào object storage tương thích S3.

Trong bài này, chúng ta cài Velero trên cụm Kubernetes của Vietnix Cloud, lưu bản sao lưu vào Vietnix Cloud S3, rồi sao lưu và phục hồi một ứng dụng mẫu — bao gồm cả persistent volume.

Cách hoạt động

  • Server Velero chạy dưới dạng Deployment trong namespace velero.
  • Mỗi bản sao lưu (metadata tài nguyên và dữ liệu volume) được lưu trong một bucket S3.
  • Persistent volume được chụp bằng CSI snapshot, và nhờ data mover tích hợp, dữ liệu snapshot được chuyển vào bucket.
  • Velero cũng hỗ trợ sao lưu theo file system (Kopia) cho các volume không hỗ trợ snapshot.

Điều kiện tiên quyết

  • Một cụm Kubernetes trên Vietnix Cloud — Create ClusterConnect Cluster.
  • Một bucket S3 và một access keyQuản lý BucketQuản lý Access Key.
  • Đã cài kubectlHelm trên máy cá nhân (xem Connect Cluster).
  • Đã cài Velero CLI trên máy cá nhân. Xem hướng dẫn cài Velero.
  • Một StorageClass dùng CSI driver hỗ trợ snapshot. Trên Vietnix Cloud dùng cinder.csi.openstack.org và đặt volume type cụ thể (xem Bước 1).
  • Đủ quota block storage (Cinder) trong project để tạo các persistent volume cần sao lưu, vì CSI snapshot được tạo từ volume Cinder.

Bước 1: Tạo StorageClass mặc định

Nếu cụm chưa có StorageClass mặc định, hãy tạo một StorageClass dùng provisioner CSI của Vietnix Cloud:

storage-class.yaml
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: default
annotations:
storageclass.kubernetes.io/is-default-class: "true"
provisioner: cinder.csi.openstack.org
parameters:
type: nvmer3
reclaimPolicy: Delete
volumeBindingMode: Immediate
allowVolumeExpansion: true
kubectl apply -f storage-class.yaml
kubectl get storageclass
Lưu ý

parameters.type chọn volume type của Cinder. Trên Vietnix Cloud là nvmer3. Nếu project của bạn dùng volume type khác, hãy đổi cho phù hợp — nếu không, việc tạo volume có thể lỗi gigabytes_default ... quota is 0G.

Bước 2: Kiểm tra hỗ trợ CSI snapshot

Velero dùng API CSI snapshot của Kubernetes, nên các CRD VolumeSnapshot và snapshot controller phải có sẵn. Kiểm tra:

kubectl api-resources | grep volumesnapshot
volumesnapshotclasses     vsclass,vsclasses     snapshot.storage.k8s.io/v1   false   VolumeSnapshotClass
volumesnapshotcontents vsc,vscs snapshot.storage.k8s.io/v1 false VolumeSnapshotContent
volumesnapshots vs snapshot.storage.k8s.io/v1 true VolumeSnapshot

Nếu kết quả có VolumeSnapshot, VolumeSnapshotClassVolumeSnapshotContent, bạn có thể bỏ qua phần còn lại của bước này. Nếu chưa có, cài external-snapshotter:

git clone https://github.com/kubernetes-csi/external-snapshotter/
cd external-snapshotter

# Chọn release tương thích với phiên bản Kubernetes của bạn
git checkout v8.6.0

kubectl apply -f client/config/crd/snapshot.storage.k8s.io_volumesnapshotclasses.yaml
kubectl apply -f client/config/crd/snapshot.storage.k8s.io_volumesnapshotcontents.yaml
kubectl apply -f client/config/crd/snapshot.storage.k8s.io_volumesnapshots.yaml
kubectl apply -f deploy/kubernetes/snapshot-controller/rbac-snapshot-controller.yaml
kubectl apply -f deploy/kubernetes/snapshot-controller/setup-snapshot-controller.yaml
Cảnh báo

Chọn release external-snapshotter tương ứng với phiên bản Kubernetes của bạn — xem bảng tương thích trong kho external-snapshotter. Ví dụ trên (v8.6.0) dành cho các phiên bản Kubernetes gần đây.

Bước 3: Tạo VolumeSnapshotClass

Tạo VolumeSnapshotClass cho driver Cinder CSI, kèm label mà Velero dùng để chọn:

snapshotclass.yaml
apiVersion: snapshot.storage.k8s.io/v1
kind: VolumeSnapshotClass
metadata:
name: cinder-snapclass
labels:
velero.io/csi-volumesnapshot-class: "true"
driver: cinder.csi.openstack.org
deletionPolicy: Delete
parameters:
force-create: "true"
kubectl apply -f snapshotclass.yaml
kubectl get volumesnapshotclass
NAME               DRIVER                     DELETIONPOLICY   AGE
cinder-snapclass cinder.csi.openstack.org Delete 1s

Bước 4: Chuẩn bị thông tin xác thực S3

Tạo file credentials với access key và secret key S3 của Vietnix Cloud (xem S3 Storage overview để biết endpoint):

credentials-velero
[default]
aws_access_key_id=<YOUR_ACCESS_KEY>
aws_secret_access_key=<YOUR_SECRET_KEY>

Bước 5: Cài Velero bằng Helm

Tạo file values trỏ Velero tới bucket S3 của bạn. Thay tên bucket bằng bucket bạn đã tạo để sao lưu:

velero-values.yaml
deployNodeAgent: true
snapshotsEnabled: false

initContainers:
- name: velero-plugin-for-aws
image: velero/velero-plugin-for-aws:v1.14.2
imagePullPolicy: IfNotPresent
volumeMounts:
- mountPath: /target
name: plugins

configuration:
features: EnableCSI
backupStorageLocation:
- name: default
provider: aws
bucket: <YOUR_BUCKET_NAME>
prefix: velero
default: true
config:
region: vn-hcm-1
s3Url: https://s3.vn-hcm-1.vietnix.cloud
s3ForcePathStyle: "true"
signatureVersion: "v4"

Cài chart:

helm repo add vmware-tanzu https://vmware-tanzu.github.io/helm-charts
helm repo update

helm install velero vmware-tanzu/velero \
--namespace velero \
--create-namespace \
--set-file credentials.secretContents.cloud=credentials-velero \
-f velero-values.yaml

Trong đó:

  • deployNodeAgent: true triển khai node agent — cần cho data moversao lưu file system.
  • snapshotsEnabled: false ngăn chart tạo VolumeSnapshotLocation mặc định — thứ không dùng cho CSI snapshot.
  • features: EnableCSI bật hỗ trợ CSI snapshot trên Velero server. Nếu thiếu, Velero sẽ dùng native snapshotter của plugin object storage và không thể di chuyển dữ liệu snapshot.
  • provider: aws vì Velero giao tiếp với storage tương thích S3 qua plugin AWS.
  • s3Urlregion là endpoint và region của Vietnix Cloud S3.
  • s3ForcePathStyle: "true" cần thiết cho endpoint tương thích S3.
Thông tin

Hỗ trợ CSI snapshot đã được tích hợp sẵn trong Velero (từ v1.14), nhưng bạn phải bật feature EnableCSI trên server — đó là lý do configuration.features: EnableCSI được đặt trong file values. Nếu thiếu, Velero dùng native snapshotter của plugin object storage và không di chuyển dữ liệu snapshot.

Bước 6: Kiểm tra cài đặt

kubectl get pods -n velero
kubectl get backupstoragelocations -n velero
velero version

Velero server, node agent và backup storage location default đều phải sẵn sàng:

NAME                       READY   STATUS    RESTARTS   AGE
node-agent-xxxxx 1/1 Running 0 1m
node-agent-yyyyy 1/1 Running 0 1m
node-agent-zzzzz 1/1 Running 0 1m
velero-xxxxxxxxxx-aaaaa 1/1 Running 0 1m
NAME      PHASE       LAST VALIDATED   AGE   DEFAULT
default Available 57s 4m true
Client:
Version: v1.18.2
Server:
Version: v1.18.1

Bật feature CSI trên Velero client để velero backup describe hiển thị chi tiết CSI snapshot:

velero client config set features=EnableCSI

Bước 7: Triển khai ứng dụng mẫu

Để minh hoạ việc sao lưu, hãy triển khai một ứng dụng nhỏ lưu dữ liệu trên persistent volume:

demo-app.yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: demo-pvc
labels:
app: demo-app
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 1Gi
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: demo-app
labels:
app: demo-app
spec:
replicas: 1
selector:
matchLabels:
app: demo-app
template:
metadata:
labels:
app: demo-app
spec:
containers:
- name: web
image: nginx:stable
ports:
- containerPort: 80
volumeMounts:
- name: data
mountPath: /usr/share/nginx/html
command: ["/bin/sh", "-c"]
args:
- echo "Hello from the Velero demo" > /usr/share/nginx/html/index.html && exec nginx -g 'daemon off;'
volumes:
- name: data
persistentVolumeClaim:
claimName: demo-pvc
---
apiVersion: v1
kind: Service
metadata:
name: demo-app
labels:
app: demo-app
spec:
selector:
app: demo-app
ports:
- port: 80
kubectl apply -f demo-app.yaml
kubectl get deployments,pods,pvc

Đợi tới khi pod chạy và volume được bind:

NAME                       READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/demo-app 1/1 1 1 30s

NAME READY STATUS RESTARTS AGE
pod/demo-app-647dc64f7-ztwfq 1/1 Running 0 30s

NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
persistentvolumeclaim/demo-pvc Bound pvc-72252ff1-9785-4345-a760-a59da46897ba 1Gi RWO default 30s

Bước 8: Tạo bản sao lưu

Sao lưu mọi tài nguyên mang label app=demo-app:

velero backup create demo-b1 \
--selector app=demo-app \
--snapshot-volumes --snapshot-move-data

Trong đó:

  • --selector app=demo-app chọn các tài nguyên của ứng dụng mẫu.
  • --snapshot-volumes chụp persistent volume bằng CSI snapshot.
  • --snapshot-move-data chuyển dữ liệu snapshot vào bucket S3.

Kiểm tra bản sao lưu và quá trình di chuyển dữ liệu:

kubectl get backups -n velero
kubectl get datauploads -n velero
velero backup describe demo-b1 --details
NAME      STATUS      ERRORS   WARNINGS   CREATED                         EXPIRES   STORAGE LOCATION   SELECTOR
demo-b1 Completed 0 0 2026-09-15 11:42:06 +0700 +07 29d default app=demo-app
NAME             STATUS      STARTED   BYTES DONE   TOTAL BYTES   STORAGE LOCATION   AGE   NODE
demo-b1-xxxxx Completed 68s 27 27 default 77s node-2

Phase của bản sao lưu phải là Completed, và các DataUpload phải ở trạng thái Completed. Trong velero backup describe, CSI snapshot hiển thị ở mục Backup Item OperationsBackup Volumes:

Phase:  Completed

Backup Item Operations:
Operation for persistentvolumeclaims default/demo-pvc:
Backup Item Action Plugin: velero.io/csi-pvc-backupper
Phase: Completed
Progress description: Completed

Backup Volumes:
CSI Snapshots:
default/demo-pvc:
Data Movement:
Data Mover: velero
Uploader Type: kopia
Moved data Size (bytes): 27
Result: succeeded

Bước 9: Phục hồi ứng dụng

Mô phỏng việc xoá nhầm:

kubectl delete -f demo-app.yaml

Phục hồi từ bản sao lưu:

velero create restore demo-restore1 --from-backup demo-b1
kubectl get restores -n velero
kubectl -n velero get datadownloads
NAME            AGE
demo-restore1 2m

NAME STATUS STARTED BYTES DONE TOTAL BYTES STORAGE LOCATION AGE NODE
demo-restore1-x5k2p Completed 112s 27 27 default 2m node-2

Sau vài phút, ứng dụng và dữ liệu persistent được phục hồi:

kubectl get deployments,pods,pvc
NAME                       READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/demo-app 1/1 1 1 2m

NAME READY STATUS RESTARTS AGE
pod/demo-app-647dc64f7-ztwfq 1/1 Running 0 2m

NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
persistentvolumeclaim/demo-pvc Bound pvc-96e97482-3e47-4d35-ab93-9ecb15c3a00d 1Gi RWO default 2m

Bước 10: Lên lịch sao lưu

Velero dùng biểu thức cron để lên lịch. Để sao lưu mỗi giờ:

velero schedule create demo-hourly \
--schedule="0 * * * *" \
--selector app=demo-app \
--snapshot-volumes --snapshot-move-data

velero schedule get
NAME          STATUS    CREATED                         SCHEDULE    BACKUP TTL   LAST BACKUP   SELECTOR       PAUSED
demo-hourly Enabled 2026-09-15 11:51:34 +0700 +07 0 * * * * 0s n/a app=demo-app false

Bước 11 (Tùy chọn): Sao lưu file system

Nếu một volume không thể chụp bằng CSI snapshot, Velero có thể sao chép dữ liệu từ file system:

velero backup create demo-b2 \
--selector app=demo-app \
--default-volumes-to-fs-backup

kubectl -n velero get podvolumebackups
velero backup describe demo-b2 --details
NAME             STATUS      STARTED   BYTES DONE   TOTAL BYTES   STORAGE LOCATION   AGE   NODE   UPLOADER
demo-b2-cj5j4 Completed 3s 27 27 default 4s kopia
Backup Volumes:
Pod Volume Backups - kopia:
Completed:
default/demo-app-7c9f6d8b5-x2lmn: data (size: 27, incremental size: 27)

Dọn dẹp

Xoá schedule và backup (tùy chọn):

velero schedule delete demo-hourly --confirm
velero backup delete demo-b1 --confirm

Gỡ ứng dụng mẫu và Velero:

kubectl delete -f demo-app.yaml
helm uninstall velero --namespace velero
Cảnh báo

Gỡ Velero không xoá các bản sao lưu đã lưu trong bucket S3. Hãy xoá thủ công tiền tố velero/ trong bucket nếu không còn cần.

Bài viết liên quan