Sao Lưu etcd và Xoay Certificate

K
Kai··5 min read

Part XII mở rộng cụm. Part XIII chuyển sang giữ cho nó sống: sao lưu, nâng cấp, dọn rác, quan sát. Bắt đầu ở thứ mất là mất tất — etcd. Mọi object trong cụm (Pod, Secret, RBAC, cả custom resource ở Bài 57) đều nằm trong etcd; nếu ba node etcd cùng hỏng mà không có bản sao lưu, cụm coi như xây lại từ đầu. Bài này chụp snapshot, kiểm nó, khôi phục thử ra chỗ khác để chắc nó dùng được, rồi nhìn sang hạn của certificate.

etcd của cụm

Cụm chạy etcd 3.6 stacked trên ba controller (Bài 6). Kiểm sức khỏe ba endpoint trước khi sao lưu:

ssh controller-0
E="sudo etcdctl --cacert=/etc/etcd/etcd-ca.pem --cert=/etc/etcd/etcd.pem --key=/etc/etcd/etcd-key.pem"
$E --endpoints=https://10.0.1.11:2379,https://10.0.1.12:2379,https://10.0.1.13:2379 endpoint health -w table
+------------------------+--------+-------------+-------+
|        ENDPOINT        | HEALTH |    TOOK     | ERROR |
+------------------------+--------+-------------+-------+
| https://10.0.1.11:2379 |   true |  14.23545ms |       |
| https://10.0.1.13:2379 |   true | 15.991822ms |       |
| https://10.0.1.12:2379 |   true | 14.031481ms |       |
+------------------------+--------+-------------+-------+

Ba member đều khỏe. HA ba node chịu được mất một node mà cụm vẫn chạy (cần đa số 2/3), nhưng HA không phải sao lưu: xóa nhầm một object thì cả ba member cùng xóa. Sao lưu là chuyện khác.

Chụp snapshot

etcdctl snapshot save chụp toàn bộ keyspace tại một thời điểm vào một file:

$E snapshot save /tmp/etcd-backup.db
Snapshot saved at /tmp/etcd-backup.db
Server version 3.6.0

File 18–19 MB. Một snapshot không kiểm là một snapshot không tin được, nên xem nó chứa gì. Ở etcd 3.6, snapshot statusrestore chuyển sang công cụ riêng etcdutl (thao tác thẳng trên file, không cần etcd chạy):

sudo etcdutl snapshot status /tmp/etcd-backup.db -w table
+----------+----------+------------+------------+---------+
|   HASH   | REVISION | TOTAL KEYS | TOTAL SIZE | VERSION |
+----------+----------+------------+------------+---------+
| 2bd8e3d9 |   115022 |        569 |      19 MB |   3.6.0 |
+----------+----------+------------+------------+---------+

TOTAL KEYS 569 là số object trong cụm tại lúc chụp, REVISION là mốc thời gian logic của etcd. Hash giúp phát hiện file hỏng.

Khôi phục thử mà không đụng cụm

Điểm dễ bỏ qua: snapshot chỉ đáng tin nếu khôi phục được. Kiểm bằng cách restore ra một thư mục dữ liệu mới — thao tác này hoàn toàn cục bộ, không chạm etcd đang chạy:

sudo etcdutl snapshot restore /tmp/etcd-backup.db --data-dir=/tmp/etcd-restore
sudo ls /tmp/etcd-restore/member
... restored snapshot ... data-dir: /tmp/etcd-restore ...
snap  wal

Restore sinh ra một data-dir hợp lệ với member/snapmember/wal — chính là cấu trúc một member etcd cần để khởi động. Đây là cách diễn tập DR an toàn: chụp định kỳ, và thỉnh thoảng restore thử ra chỗ khác để chắc bản sao lưu thật sự dùng được, chứ không đợi tới lúc cháy nhà mới biết file hỏng.

Quy trình khôi phục thật

Khi phải khôi phục thật (mất cả ba member, hoặc cần quay về một mốc), quy trình trên cụm HA stacked là:

1. Dừng kube-apiserver (cả 3) — không cho ghi vào etcd trong lúc khôi phục
2. Dừng etcd (cả 3 member):           systemctl stop etcd
3. Trên MỖI member, restore snapshot ra data-dir mới với
   --name / --initial-cluster / --initial-advertise-peer-urls đúng của member đó
4. Thay data-dir cũ bằng data-dir vừa restore
5. Khởi động lại etcd (cả 3), rồi kube-apiserver

Điểm tinh tế của HA: mỗi member phải restore với đúng định danh (--name, --initial-cluster) của nó, vì snapshot không mang thông tin thành viên — nếu không, ba member sẽ không hợp thành một cluster. Bài này không chạy bước phá hủy đó trên cụm sống; phần kiểm chứng là snapshot hợp lệ và restore được ra data-dir đúng cấu trúc.

Hạn certificate

Phần vận hành thứ hai dễ quên cho tới khi cụm tự gãy: certificate hết hạn. Soi hạn bộ cert dựng ở Bài 4:

for c in ca kube-apiserver etcd admin front-proxy-ca; do
  printf "%-16s %s\n" "$c" "$(openssl x509 -in $c.pem -noout -enddate | cut -d= -f2)"
done
ca               May 22 13:33:00 2031 GMT      # CA: 10 năm
kube-apiserver   May 23 13:34:00 2027 GMT      # leaf: 1 năm
etcd             May 23 13:34:00 2027 GMT
admin            May 23 13:33:00 2027 GMT
front-proxy-ca   May 22 13:33:00 2031 GMT

Hai loại hạn khác nhau: CA (gồm front-proxy-ca) sống 10 năm, còn cert lá (apiserver, etcd, admin, kubelet...) chỉ một năm — tới 2027 là hết. Khi cert lá hết hạn, thành phần dùng nó không bắt tay TLS được nữa: apiserver không nói chuyện được với etcd, kubelet không nối được apiserver, cụm đứng. Xoay cert lá là ký lại chúng bằng đúng CA cũ (CA chưa hết hạn nên client vẫn tin), rồi đặt cert mới vào chỗ cũ và khởi động lại thành phần — chính là chạy lại phần ký cert của Bài 4 với CA hiện có, không phải dựng CA mới. Vì CA sống 10 năm, xoay cert lá không làm gián đoạn niềm tin. (Cụm dùng kubeadm có kubeadm certs renew tự động hóa việc này; cụm tự dựng thì ta tự ký lại — đánh đổi của việc làm bằng tay.)

🧹 Dọn dẹp

sudo rm -rf /tmp/etcd-backup.db /tmp/etcd-restore /tmp/etcdutl

Bài này không sửa cấu hình cụm — chỉ chụp một snapshot (đọc) và restore ra thư mục tạm. Xóa file tạm là sạch. Lệnh dùng trong bài ở github.com/nghiadaulau/kubernetes-from-scratch, thư mục 62-etcd-backup.

Tổng kết

etcd là nguồn sự thật duy nhất của cụm, và HA không thay được sao lưu — xóa nhầm thì cả ba member cùng xóa. Ta chụp snapshot bằng etcdctl snapshot save, kiểm bằng etcdutl snapshot status (HASH/REVISION/569 keys/19MB), và restore ra một data-dir mới (member/snap+member/wal hợp lệ) để chứng minh bản sao lưu dùng được, tất cả không đụng etcd sống. Quy trình DR thật trên HA stacked: dừng apiserver + etcd, restore với đúng định danh từng member, khởi động lại. Phần vận hành thứ hai là certificate: CA sống 10 năm (tới 2031) nhưng cert lá chỉ một năm (hết 2027), và hết hạn cert lá làm cụm đứng — xoay là ký lại cert lá bằng CA cũ, không dựng CA mới. Bài học chung: cả hai thứ này âm thầm cho tới lúc hỏng, nên phải diễn tập restore và theo dõi hạn cert trước khi cần.

Bài 63 sang một việc vận hành thường xuyên hơn: nâng cấp phiên bản. Cụm đang ở v1.36, và Kubernetes có quy tắc version skew nghiêm ngặt về việc thành phần nào được lệch phiên bản bao nhiêu so với apiserver — nâng cấp đúng thứ tự là cốt lõi để không vỡ cụm giữa chừng.