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 Cluster và Connect Cluster.
- Một bucket S3 và một access key — Quản lý Bucket và Quản lý Access Key.
- Đã cài kubectl và Helm 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.orgvà đặ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:
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
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, VolumeSnapshotClass và VolumeSnapshotContent, 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
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:
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):
[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:
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: truetriển khai node agent — cần cho data mover và sao lưu file system.snapshotsEnabled: falsengăn chart tạoVolumeSnapshotLocationmặc định — thứ không dùng cho CSI snapshot.features: EnableCSIbậ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: awsvì Velero giao tiếp với storage tương thích S3 qua plugin AWS.s3Urlvàregionlà endpoint và region của Vietnix Cloud S3.s3ForcePathStyle: "true"cần thiết cho endpoint tương thích S3.
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:
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-appchọn các tài nguyên của ứng dụng mẫu.--snapshot-volumeschụp persistent volume bằng CSI snapshot.--snapshot-move-datachuyể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 Operations và Backup 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
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.