Các phương pháp khôi phục thảm họa trong Kubernetes: GitOps vs Snapshot lưu trữ vs Operator sao lưu
Các ứng dụng stateless rất dễ khôi phục. Nhưng workload stateful thì không đơn giản như vậy. Khi xảy ra sự cố vô tình chạy lệnh kubectl delete namespace, migration thất bại hoặc etcd bị hỏng dữ liệu, việc chỉ áp dụng lại các manifest sẽ khiến bạn đối mặt với các volume trống rỗng và những dependency bị gãy đổ.
Các đội ngũ vận hành production thường dựa vào ba mô hình khôi phục chính:
- GitOps & Infrastructure as Code (IaC): Các công cụ như ArgoCD hoặc Flux đồng bộ hóa manifest trực tiếp từ Git. Chúng tái tạo các stateless deployment, Service và CRD chỉ trong vài giây. Tuy nhiên, GitOps hoàn toàn không nhận biết được trạng thái runtime thực tế. Nó không thể giúp bạn lấy lại các bảng dữ liệu Postgres hay topic Kafka.
- Cloud Storage Volume Snapshot: Việc tạo snapshot định kỳ ở cấp độ block (như AWS EBS, GCP PD hoặc Ceph RBD) giúp bảo vệ dữ liệu nhị phân thô. Dẫu vậy, các snapshot này hoạt động độc lập bên ngoài Kubernetes. Nếu không tạm dừng các thao tác ghi hoặc gắn kết ổ đĩa trở lại đúng định nghĩa pod đang chạy, việc khôi phục chúng qua các namespace thường trở thành một bài toán viết script phức tạp và dễ phát sinh lỗi.
- Kubernetes-Native Backup Operator (Velero): Velero chạy trực tiếp bên trong cluster của bạn, truy vấn API server và điều phối quá trình sao lưu tới bộ lưu trữ tương thích S3. Nó đóng gói cả hai thành phần: tài nguyên Kubernetes API và dữ liệu persistent volume (thông qua CSI volume snapshot hoặc node agent cấp tệp tin như Kopia).
Đánh giá các phương pháp sao lưu: Ưu và nhược điểm
Việc lựa chọn kiến trúc khôi phục phù hợp phụ thuộc vào mục tiêu điểm khôi phục (RPO – Recovery Point Objective) và độ phức tạp trong vận hành của bạn.
Kho lưu trữ GitOps
- Ưu điểm: Nhật ký kiểm toán có quản lý phiên bản, quy trình phê duyệt pull-request, tự động khắc phục sai lệch cấu hình (drift correction).
- Nhược điểm: Không bảo vệ trạng thái; các secret động do operator tạo ra và dữ liệu thực tế trên đĩa cần một công cụ bổ trợ riêng.
Snapshot từ nhà cung cấp hạ tầng lưu trữ
- Ưu điểm: Sao chép cấp độ block nhanh chóng (thường đạt RPO dưới 1 phút đối với các volume trên 500GB), không tiêu tốn CPU trên worker node.
- Nhược điểm: Bị phụ thuộc vào nhà cung cấp cloud (vendor lock-in), khó điều phối trên các node phân tán, phức tạp khi cần migration giữa các cluster khác nhau.
Velero kết hợp với S3 Object Storage
- Ưu điểm: Tính linh hoạt cao, cho phép chuyển đổi toàn bộ cluster giữa bare-metal và public cloud, lọc chi tiết theo label/namespace, tích hợp sẵn node-agent Kopia.
- Nhược điểm: Sao lưu ở cấp độ filesystem (Kopia) tiêu tốn CPU/RAM của node trong quá trình đọc dữ liệu, và tốc độ truyền tải phụ thuộc trực tiếp vào băng thông mạng đến object storage.
Kiến trúc đề xuất: Kết hợp Velero cùng MinIO
Đối với mô hình hybrid cloud, bare-metal cluster hoặc các trung tâm dữ liệu air-gapped, việc kết hợp Velero với một cụm MinIO chuyên dụng sẽ mang lại sự cân bằng lý tưởng giữa tốc độ và quyền tự chủ hạ tầng.
Velero đảm nhiệm điều phối các truy vấn API và backup hook. Trong khi đó, MinIO cung cấp dịch vụ object storage gọn nhẹ, tương thích chuẩn S3, cho tốc độ lên đến hàng gigabyte mỗi giây trên các ổ NVMe cục bộ—hoàn toàn không phát sinh chi phí truyền tải dữ liệu ra ngoài (egress fee).
Velero vận hành dưới dạng một deployment controller trong cluster. Trong quá trình backup, nó đóng gói các manifest API được chỉ định thành một file tarball nén và đẩy lên MinIO. Đối với PersistentVolume, DaemonSet node-agent của Velero sử dụng Kopia để stream dữ liệu tập tin vào cùng bucket đó. Khi sự cố control plane bất ngờ xảy ra hoặc bản release bị lỗi lúc 2 giờ sáng, bạn chỉ cần thực thi một lệnh restore duy nhất để phục hồi toàn bộ ứng dụng trong vài phút.
Hướng dẫn triển khai từng bước
Phần hướng dẫn sau đây sẽ thiết lập MinIO, triển khai Velero với tính năng sao lưu cấp tệp tin và kiểm thử quy trình sao lưu – phục hồi thảm họa từ đầu đến cuối.
1. Triển khai MinIO Object Storage
Nếu bạn chưa có sẵn một cụm MinIO bên ngoài, hãy khởi tạo phiên bản standalone này để thử nghiệm:
# Tạo namespace cho MinIO
kubectl create namespace minio
# Triển khai MinIO standalone với bộ nhớ persistent
kubectl apply -n minio -f - <<EOF
apiVersion: apps/v1
kind: Deployment
metadata:
name: minio
spec:
replicas: 1
selector:
matchLabels:
app: minio
template:
metadata:
labels:
app: minio
spec:
containers:
- name: minio
image: minio/minio:RELEASE.2024-05-10T01-41-38Z
args:
- server
- /data
- --console-address
- :9001
env:
- name: MINIO_ROOT_USER
value: "admin-velero"
- name: MINIO_ROOT_PASSWORD
value: "StrongSecretKey123"
ports:
- containerPort: 9000
- containerPort: 9001
volumeMounts:
- name: storage
mountPath: /data
volumes:
- name: storage
emptyDir: {}
---
apiVersion: v1
kind: Service
metadata:
name: minio
spec:
ports:
- port: 9000
targetPort: 9000
name: api
selector:
app: minio
EOF
Tiếp theo, đăng nhập vào MinIO Console qua cổng 9001 hoặc sử dụng MinIO client (mc) để tạo một bucket có tên là velero-backups.
2. Cài đặt Velero CLI và cấu hình thông tin xác thực
Tải Velero CLI (bản v1.13 trở lên) phù hợp với hệ điều hành của bạn và lưu thông tin xác thực MinIO vào một file định dạng INI ở máy local:
# Tạo file credentials-velero
cat <<EOF > credentials-velero
[default]
aws_access_key_id = admin-velero
aws_secret_access_key = StrongSecretKey123
EOF
3. Cài đặt Velero Server với Node-Agent được kích hoạt
Triển khai Velero vào cluster. Trỏ Velero tới endpoint của MinIO service trong cluster và thêm cờ --use-node-agent để hỗ trợ sao lưu volume ở cấp độ tập tin mà không cần plugin snapshot của cloud:
velero install \
--provider aws \
--plugins velero/velero-plugin-for-aws:v1.9.0 \
--bucket velero-backups \
--secret-file ./credentials-velero \
--use-node-agent \
--backup-location-config region=minio,s3ForcePathStyle="true",s3Url=http://minio.minio.svc.cluster.local:9000
Xác nhận deployment và node-agent DaemonSet đã hoạt động ổn định:
kubectl get pods -n velero
Tất cả các pod controller và node-agent cần chuyển sang trạng thái Running trong vòng 30 đến 60 giây.
4. Triển khai workload stateful mẫu
Tạo một namespace thử nghiệm chứa web server Nginx được gắn với một PersistentVolumeClaim dung lượng 1Gi:
kubectl create namespace production-app
kubectl apply -n production-app -f - <<EOF
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: web-data
spec:
accessModes: [ "ReadWriteOnce" ]
resources:
requests:
storage: 1Gi
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: web-server
spec:
replicas: 1
selector:
matchLabels:
app: web
template:
metadata:
labels:
app: web
spec:
containers:
- name: nginx
image: nginx:alpine
volumeMounts:
- mountPath: /usr/share/nginx/html
name: storage
volumes:
- name: storage
persistentVolumeClaim
claimName: web-data
EOF
Ghi dữ liệu mẫu vào volume để xác minh tính toàn vẹn sau khi khôi phục:
POD_NAME=$(kubectl get pod -n production-app -l app=web -o jsonpath="{.items[0].metadata.name}")
kubectl exec -n production-app $POD_NAME -- sh -c 'echo "Khôi phục thảm họa cluster thành công!" > /usr/share/nginx/html/index.html'
5. Thực hiện sao lưu toàn bộ Namespace
Yêu cầu Velero tiến hành sao lưu namespace production-app cùng toàn bộ dữ liệu PVC của nó:
velero backup create production-backup \
--include-namespaces production-app \
--default-volumes-to-fs-backup \
--wait
Kiểm tra trạng thái bản sao lưu sau khi lệnh hoàn tất:
velero backup describe production-backup --details
Bạn sẽ thấy trạng thái chuyển thành Completed với 0 lỗi cùng bản sao lưu volume Kopia được ghi nhận trong danh sách snapshot.
6. Kiểm thử quy trình khôi phục thảm họa
Mô phỏng sự cố mất dữ liệu ngoài ý muốn bằng cách xóa namespace production:
kubectl delete namespace production-app
kubectl get namespace production-app
Khi Kubernetes đã dọn dẹp xong namespace, hãy tiến hành khôi phục ứng dụng và volume từ MinIO:
velero restore create --from-backup production-backup --wait
velero restore get
Kiểm tra pod đã chạy trở lại và đọc nội dung tập tin được khôi phục:
RESTORED_POD=$(kubectl get pod -n production-app -l app=web -o jsonpath="{.items[0].metadata.name}")
kubectl exec -n production-app $RESTORED_POD -- cat /usr/share/nginx/html/index.html
Terminal sẽ hiển thị dòng chữ Khôi phục thảm họa cluster thành công!. Như vậy, các manifest, PVC và dữ liệu tập tin của bạn đã được khôi phục nguyên vẹn.

