Sao lưu Kubernetes có hai nửa và người ta hay chỉ làm một nửa. Bài này đo cả hai để thấy rõ ranh giới.

Kích thước snapshot, phần dữ liệu nó không chứa, và những gì kubectl get all bỏ sót

etcd snapshot: nhanh và nhỏ

cả thư mục /var/lib/etcd   206.569.472 byte
snapshot                    13.848.608 byte
thời gian chụp                    0,1 giây

Snapshot nhỏ hơn thư mục 14,9 lần. Phần lớn chênh lệch là WAL — 184 MB nhật ký ghi trước mà etcd giữ để phục hồi sau sự cố. Snapshot không cần chúng.

Lệnh:

kubectl exec -n kube-system etcd-<node> -- etcdctl \
  --cacert=/etc/kubernetes/pki/etcd/ca.crt \
  --cert=/etc/kubernetes/pki/etcd/server.crt \
  --key=/etc/kubernetes/pki/etcd/server.key \
  snapshot save /var/lib/etcd/snap.db

Ghi vào /var/lib/etcd vì đó là thư mục gắn từ node — container etcd không có shell, và như đo được ở phần 42, kubectl cp cũng cần shell. Ghi vào đường dẫn có gắn từ ngoài là cách đơn giản nhất lấy tệp ra.

Kiểm tra snapshot trước khi tin nó:

etcdutl --write-out=table snapshot status /var/lib/etcd/snap.db
HASH       REVISION   TOTAL KEYS   TOTAL SIZE   VERSION
799a7d4e   117589     544          14 MB        3.6.0

Có mã băm, có số khoá. Một snapshot hỏng lộ ra ngay ở đây thay vì lộ ra lúc khôi phục.

Đừng sao lưu bằng cách copy /var/lib/etcd. Nó vừa to gấp 15 lần vừa không nhất quán: các tệp đang được ghi trong lúc bạn copy, và kết quả có thể không mở được. snapshot save chụp một trạng thái nhất quán tại một revision.

Snapshot chứa đối tượng, không chứa dữ liệu

Đây là phép đo quan trọng nhất bài.

Tôi ghi 52.428.800 byte vào một PersistentVolume rồi chụp lại:

snapshot trước   13.848.608 byte
snapshot sau     13.983.776 byte
chênh lệch          135.168 byte

135 KB cho 50 MB dữ liệu — 0,26%. Và phần tăng đó là do có thêm đối tượng PVC, PV, Pod, chứ không phải do dữ liệu.

Điều này hiển nhiên khi nói ra: etcd lưu định nghĩa của PersistentVolume, còn nội dung nằm trên đĩa của node hoặc trên hệ thống lưu trữ ngoài. Nhưng nó không hiển nhiên lúc 3 giờ sáng, khi ai đó nói "chúng ta có snapshot etcd hàng đêm".

Khôi phục từ snapshot etcd cho lại mọi đối tượng — Deployment, Service, Secret, PVC — nhưng PVC sẽ trỏ tới một PV rỗng, hoặc tới một PV không còn tồn tại. Cơ sở dữ liệu quay lại với đúng cấu hình cũ và không có dòng dữ liệu nào.

Đó chính là chỗ Velero (hoặc tương đương) chen vào: nó chụp cả ảnh đĩa của volume, qua ảnh chụp của nhà cung cấp đám mây hoặc qua restic/kopia sao chép ở mức tệp.

kubectl get all không get all

Cách sao lưu "nghèo" mà nhiều người dùng:

kubectl get all -A -o yaml > sao-luu.yaml

Đo trên cụm này: 34 loại tài nguyên có phạm vi namespace, get all lấy được 8 loại.

Bị bỏ sót:

Loại Số lượng
ServiceAccount 56
ConfigMap 20
RoleBinding 17
Role 16
PVC 5
Secret 3
Ingress 2

119 đối tượng, kể cả mọi Secret. Bản "sao lưu" đó khôi phục lại một cụm không có mật khẩu, không có cấu hình, không có phân quyền.

Cái tên all gây hiểu nhầm nghiêm trọng: nó chỉ nghĩa là "nhóm tài nguyên có nhãn all", một danh sách cố định do API server định nghĩa.

Muốn lấy đủ thì phải liệt kê loại tài nguyên:

kubectl api-resources --verbs=list --namespaced -o name \
  | tr '\n' ',' | sed 's/,$//' \
  | xargs -I{} kubectl get {} -A -o yaml > that-su-tat-ca.yaml

Vẫn còn thiếu tài nguyên phạm vi cụm (Namespace, CRD, ClusterRole, PV) — và vẫn không có dữ liệu volume.

Ba tầng, chọn theo cái bạn sợ mất

Tầng Công cụ Cứu được gì
Đối tượng, toàn cụm etcdctl snapshot Cụm sập, control plane hỏng
Đối tượng, theo namespace Velero, hoặc xuất YAML Xoá nhầm, chuyển cụm
Dữ liệu volume Velero + ảnh chụp đĩa Mất dữ liệu thật

Snapshot etcd là tầng rẻ nhất và ít người bỏ qua nhất — nhưng nó cũng là tầng khó dùng nhất: khôi phục nó là khôi phục toàn bộ cụm về một thời điểm, không chọn lọc được namespace nào.

Nếu sự cố hay gặp của bạn là "ai đó xoá nhầm một namespace" thì snapshot etcd gần như vô dụng, và một bản xuất YAML theo namespace lại cứu được trong ba mươi giây.

Bốn điều làm sai thường gặp

Snapshot nằm trên chính node đó. Node chết là mất cả cụm lẫn bản sao lưu. Phải đẩy ra ngoài ngay sau khi chụp.

Không ai từng khôi phục thử. Bản sao lưu chưa khôi phục thử không phải bản sao lưu, nó là một tệp. Phần sau đo đúng chuyện này.

Quên chứng chỉ. Snapshot etcd không chứa /etc/kubernetes/pki. Thiếu chúng thì có snapshot cũng không dựng lại được control plane. Sao lưu cả thư mục đó — nó nhỏ.

Chỉ chụp một lần mỗi đêm. Với --event-ttl một giờ ở phần 41 thì sự kiện mất là chấp nhận được, nhưng mất 24 giờ thay đổi cấu hình thì không. Chụp thường xuyên hơn: snapshot mất 0,1 giây và 14 MB.

Thử ba mươi giây

Chụp thử ngay bây giờ và kiểm tra nó đọc được:

N=etcd-$(kubectl get node -l node-role.kubernetes.io/control-plane -o jsonpath='{.items[0].metadata.name}')
P=/etc/kubernetes/pki/etcd
kubectl exec -n kube-system $N -- etcdctl \
  --cacert=$P/ca.crt --cert=$P/server.crt --key=$P/server.key \
  snapshot save /var/lib/etcd/thu.db
kubectl exec -n kube-system $N -- etcdutl \
  --write-out=table snapshot status /var/lib/etcd/thu.db

Nếu lệnh này chạy được, bạn biết mình chụp được. Nếu nó báo lỗi chứng chỉ hoặc không tìm thấy pod, bạn vừa phát hiện điều đó trước khi cần tới — và đó là cả mục đích của việc thử.

Phần sau: khôi phục thật từ snapshot đó, đo từng bước và đo cả thời gian cụm không phục vụ.