etcd backup và restore
Mục tiêu bài học
Sau bài này, bạn phải làm được 3 việc sau, không cần mở tài liệu:
- Tạo snapshot etcd bằng
etcdctl snapshot savevới đúng endpoint và bộ cert. - Verify snapshot bằng
etcdutl snapshot status. - Restore thành công từ snapshot trên cluster lab, sửa đúng cả
--data-dirvàhostPathtrong static pod manifest.
Đây là dạng bài gần như chắc chắn xuất hiện trong CKA và là một trong những câu "ăn điểm nhanh" nhất. Mình đã chứng kiến rất nhiều bạn mất điểm chỉ vì quên sửa hostPath, nên bài này sẽ tập trung vào đúng cái bẫy đó.
Ôn nhanh
Ở bài trước, cluster của bạn được dựng bằng kubeadm init, và control plane chạy dưới dạng static pod với manifest nằm trong /etc/kubernetes/manifests/. etcd cũng là một static pod như vậy, tên etcd-<tên-node>, trong namespace kube-system.
Điểm mấu chốt cần nhớ: kubelet quét thư mục /etc/kubernetes/manifests/. File nào còn ở đó thì pod còn chạy, file nào bị move ra thì pod bị xoá. Chúng ta sẽ lợi dụng đúng cơ chế này để "tắt" etcd khi restore.
Bảng tham chiếu nhanh
| Thành phần | Giá trị mặc định trên cluster kubeadm |
|---|---|
| Client endpoint | https://127.0.0.1:2379 |
| Peer port | 2380 |
| CA | /etc/kubernetes/pki/etcd/ca.crt |
| Server cert | /etc/kubernetes/pki/etcd/server.crt |
| Server key | /etc/kubernetes/pki/etcd/server.key |
| Data dir | /var/lib/etcd |
| Static pod manifest | /etc/kubernetes/manifests/etcd.yaml |
etcd lắng nghe client request trên port {{c1::2379}} và trao đổi dữ liệu giữa các member trên port {{c2::2380}}.
Ví dụ mẫu: backup rồi restore trên cluster lab
Luồng tổng quát của một lần restore trông như sau:
flowchart TD
A["💾<br/>etcdctl snapshot save"] --> B["🔍<br/>etcdutl snapshot status"]
B --> C["🛑<br/>Move etcd.yaml ra khỏi manifests"]
C --> D["♻️<br/>etcdutl snapshot restore vào data-dir mới"]
D --> E["✏️<br/>Sửa --data-dir và hostPath"]
E --> F["🚀<br/>Move manifest trở lại"]
F --> G["✅<br/>kubectl get nodes và kiểm tra object"]
Bước 1: Xác nhận thông tin etcd đang chạy
kubectl get nodes
kubectl -n kube-system get pod -l component=etcd -o wide
Lấy nhanh các tham số quan trọng mà không cần mở file bằng tay:
kubectl -n kube-system get pod etcd-controlplane -o yaml | grep -E "data-dir|listen-client-urls|name="
Bạn sẽ thấy --data-dir=/var/lib/etcd và --listen-client-urls=https://127.0.0.1:2379,.... Hai dòng này chính là thứ bạn cần cho lệnh backup.
Bước 2: Tạo snapshot
sudo -i
mkdir -p /opt/backup
ETCDCTL_API=3 etcdctl snapshot save /opt/backup/etcd-snapshot.db \
--endpoints=https://127.0.0.1:2379 \
--cacert=/etc/kubernetes/pki/etcd/ca.crt \
--cert=/etc/kubernetes/pki/etcd/server.crt \
--key=/etc/kubernetes/pki/etcd/server.key
Kết quả mong đợi:
{"level":"info","msg":" fetched snapshot ...","totalKey":...
Snapshot saved at /opt/backup/etcd-snapshot.db
[!NOTE] Từ etcd 3.4 trở đi, API v3 là mặc định nên
ETCDCTL_API=3không còn bắt buộc. Cứ đặt vào cho chắc, nó không gây hại và giúp bạn không phải nhớ phiên bản etcd trên cluster thi.
Bước 3: Verify snapshot
Đừng bao giờ restore từ một file chưa kiểm tra. Chạy:
etcdutl snapshot status /opt/backup/etcd-snapshot.db -w table
Kết quả mong đợi có đủ 4 cột: hash, revision, totalKey, totalSize. Nếu lệnh báo lỗi đọc file thì snapshot hỏng, phải làm lại từ Bước 2.
Bước 4: Tạo "dữ liệu sau snapshot" để chứng minh restore có tác dụng
Đây là mẹo mình luôn dùng khi luyện thi: tạo một object sau khi snapshot, restore xong object đó phải biến mất. Đó là bằng chứng restore thật sự chạy.
kubectl create namespace demo-restore
kubectl create deployment web --image=nginx -n demo-restore
kubectl get all -n demo-restore
Bước 5: Dừng etcd static pod
mv /etc/kubernetes/manifests/etcd.yaml /etc/kubernetes/etcd.yaml.bak
Chờ khoảng 15 đến 30 giây, rồi kiểm tra bằng crictl (không dùng kubectl, vì lúc này API server không còn backend):
crictl ps | grep etcd
Không còn container etcd nào là đúng. Từ giờ đến khi etcd lên lại, mọi lệnh kubectl sẽ treo hoặc báo lỗi etcdserver: request timed out. Đó là bình thường, đừng hoảng.
Bước 6: Restore vào data-dir MỚI
etcdutl snapshot restore /opt/backup/etcd-snapshot.db \
--data-dir=/var/lib/etcd-restore
Kết quả mong đợi:
2024-xx-xx ... restored snapshot ... to /var/lib/etcd-restore
Từ etcd 3.5 trở đi, lệnh restore được khuyến nghị là {{c3::etcdutl snapshot restore}} thay cho etcdctl snapshot restore (đã deprecated nhưng vẫn chạy được).
[!WARNING] Tuyệt đối không restore đè lên
/var/lib/etcdkhi thư mục đó đang là data-dir của etcd. Hãy luôn restore ra một thư mục mới, ví dụ/var/lib/etcd-restore. Giữ nguyên/var/lib/etcdlàm bản dự phòng tại chỗ, nếu hỏng còn đường quay lại.
Bước 7: Sửa manifest, nhớ sửa HAI chỗ
Mở file backup ra sửa:
vi /etc/kubernetes/etcd.yaml.bak
Chỗ thứ nhất, trong command:
- --data-dir=/var/lib/etcd-restore
Chỗ thứ hai, trong volumes:
- hostPath:
path: /var/lib/etcd-restore
type: DirectoryOrCreate
name: etcd-data
[!IMPORTANT] Đây là bẫy số 1 của dạng bài này. Sửa
--data-dirmà quênhostPath.paththì container vẫn mount/var/lib/etcdcũ vào trong pod, etcd khởi động bình thường nhưng dữ liệu là dữ liệu cũ. Bạn sẽ tưởng mình restore hỏng và đi loanh quanh rất lâu.
Flag quyết định thư mục dữ liệu mới khi restore là {{c4::--data-dir}}. Và trong manifest, phần cần sửa thứ hai nằm ở volumes, cụ thể là {{c5::hostPath.path}}.
Bước 8: Đưa manifest trở lại và kiểm tra
mv /etc/kubernetes/etcd.yaml.bak /etc/kubernetes/manifests/etcd.yaml
sleep 20
crictl ps | grep etcd
kubectl get nodes
Khi kubectl get nodes trả về danh sách node là etcd đã sống lại. Kiểm tra bằng chứng restore:
kubectl get ns demo-restore
# Error from server (NotFound): namespaces "demo-restore" not found
kubectl get pods -A
kubectl get ns
Namespace demo-restore biến mất nghĩa là dữ liệu đã quay về đúng thời điểm snapshot. Cluster của bạn đã restore thành công.
Thực hành có hướng dẫn
Làm lần lượt 4 bài tập dưới đây trên cluster lab. Bài 4 mô phỏng sát đề thi nhất.
Bài tập 1: Trích xuất thông số etcd mà không mở file
Yêu cầu: chỉ dùng kubectl, in ra --data-dir và endpoint client mà etcd đang dùng.
Xem gợi ý
Dùng kubectl -n kube-system get pod etcd-<node> -o yaml, sau đó lọc bằng grep. Hoặc describe và đọc phần Command.
Xem đáp án
kubectl -n kube-system get pod etcd-controlplane -o yaml \
| grep -E "data-dir|listen-client-urls"
Kết quả mong đợi:
- --data-dir=/var/lib/etcd
- --listen-client-urls=https://127.0.0.1:2379,https://10.0.0.10:2379
Bài tập 2: Backup và verify
Yêu cầu: tạo snapshot tại /opt/backup/etcd-snapshot.db, sau đó in ra revision và totalKey dưới dạng bảng.
Xem đáp án
sudo -i
mkdir -p /opt/backup
ETCDCTL_API=3 etcdctl snapshot save /opt/backup/etcd-snapshot.db \
--endpoints=https://127.0.0.1:2379 \
--cacert=/etc/kubernetes/pki/etcd/ca.crt \
--cert=/etc/kubernetes/pki/etcd/server.crt \
--key=/etc/kubernetes/pki/etcd/server.key
etcdutl snapshot status /opt/backup/etcd-snapshot.db -w table
Ghi lại số revision. Bạn sẽ dùng nó để đối chiếu sau khi restore.
Bài tập 3: Restore và chứng minh bằng dữ liệu phát sinh
Yêu cầu:
- Tạo namespace
post-snapshotsau khi đã có snapshot. - Restore từ
/opt/backup/etcd-snapshot.db. - Chứng minh
post-snapshotkhông còn tồn tại, còn các namespace cũ vẫn nguyên.
Xem đáp án
kubectl create namespace post-snapshot
mv /etc/kubernetes/manifests/etcd.yaml /etc/kubernetes/etcd.yaml.bak
crictl ps | grep etcd # phải rỗng
etcdutl snapshot restore /opt/backup/etcd-snapshot.db \
--data-dir=/var/lib/etcd-restore
# sửa --data-dir và hostPath.path thành /var/lib/etcd-restore
vi /etc/kubernetes/etcd.yaml.bak
mv /etc/kubernetes/etcd.yaml.bak /etc/kubernetes/manifests/etcd.yaml
sleep 20
kubectl get ns
post-snapshot phải biến mất, default, kube-system vẫn còn.
Bài tập 4: Mô phỏng đề thi
Đề bài giả lập:
A cluster is running on node
controlplane. A snapshot of etcd exists at/opt/backup/etcd-snapshot-previous.db. Restore the cluster to this snapshot. Do not change the etcd data directory used by the static pod beyond what is required to complete the restore.
Yêu cầu: hoàn thành trong 10 phút, sau đó tự chấm theo 3 tiêu chí: etcd pod Running, kubectl get nodes trả về Ready, dữ liệu đúng thời điểm snapshot.
Xem hướng làm nhanh
crictl ps | grep etcdđể xác nhận chưa có gì bất thường.mv /etc/kubernetes/manifests/etcd.yaml /etc/kubernetes/etcd.yaml.baketcdutl snapshot restore /opt/backup/etcd-snapshot-previous.db --data-dir=/var/lib/etcd-restore- Sửa 2 chỗ trong manifest:
--data-dirvàhostPath.path. mvmanifest trở lại, chờ 20 đến 30 giây.- Verify:
crictl ps | grep etcd,kubectl get nodes,kubectl get ns.
[!TIP] Trong phòng thi, hãy làm câu etcd backup trước tiên. Nó chỉ mất 2 đến 3 phút, gần như không thể sai nếu bạn thuộc bộ cert, và mang lại cảm giác an toàn cho phần còn lại của bài.
Lỗi thường gặp và cách xử lý
1. Quên --cacert, --cert, --key
etcdctl báo context deadline exceeded hoặc transport: authentication handshake failed. etcd luôn yêu cầu TLS, không có ngoại lệ. Thiếu một trong ba flag là không chạy được.
2. Quên hostPath.path
Đây là lỗi phổ biến nhất. etcd pod lên Running, kubectl hoạt động, nhưng dữ liệu vẫn là dữ liệu cũ. Dấu hiệu nhận biết: object bạn tạo sau snapshot vẫn còn tồn tại. Cách sửa: kiểm tra lại phần volumes trong manifest, đảm bảo path trùng với --data-dir.
3. Restore đè lên data-dir đang dùng
etcd rơi vào crash loop, log báo lỗi đọc WAL hoặc snapshot file ... exists. Luôn restore ra thư mục mới.
4. Quên move manifest ra trước khi restore
Restore vẫn chạy xong, nhưng etcd đang chạy không hề biết. Khi bạn mv manifest trở lại, etcd vẫn dùng data-dir cũ. Luôn tắt etcd trước.
5. Dùng kubectl để kiểm tra khi etcd đã tắt
kubectl get pods sẽ treo rất lâu rồi trả về etcdserver: request timed out. Đừng chờ. Dùng crictl ps và journalctl -u kubelet -f để biết chuyện gì đang xảy ra.
6. Nhầm port 2379 và 2380
--endpoints phải dùng port client 2379. Port 2380 là peer traffic, dùng sai sẽ bị timeout.
7. Restore xong nhưng etcd không lên
Xem log: crictl logs <container-id> hoặc journalctl -u kubelet -n 100. Nếu log báo lỗi liên quan tới member name hoặc cluster config, chạy lại lệnh restore với bộ flag khớp manifest hiện tại:
etcdutl snapshot restore /opt/backup/etcd-snapshot.db \
--data-dir=/var/lib/etcd-restore \
--name=controlplane \
--initial-cluster=controlplane=https://127.0.0.1:2380 \
--initial-advertise-peer-urls=https://127.0.0.1:2380 \
--initial-cluster-token=etcd-cluster-1
Thay controlplane bằng đúng giá trị --name trong manifest của bạn.
8. Snapshot lấy từ máy khác, version etcd lệch
Restore báo lỗi hash. Thêm --skip-hash-check để bỏ qua bước kiểm tra, nhưng chỉ dùng khi bạn chắc file không hỏng.
9. Ghi snapshot vào thư mục không có quyền
Chạy sudo -i trước, hoặc dùng sudo cho từng lệnh. Lỗi permission denied ở /opt/backup là do chưa lên root.
10. Tưởng restore hỏng vì mất dữ liệu
Restore đưa cluster về đúng thời điểm snapshot. Mọi object tạo sau đó sẽ mất. Đó là hành vi đúng, không phải lỗi.
Sau khi restore, dữ liệu trong etcd sẽ ở đúng trạng thái tại thời điểm {{c6::snapshot được tạo}}, nên mọi object tạo sau đó đều biến mất.
Góc chuyên gia
Tạo alias cho bộ cert để gõ nhanh. Trong phòng thi, bạn sẽ dùng lại bộ flag này nhiều lần:
export E="--endpoints=https://127.0.0.1:2379 \
--cacert=/etc/kubernetes/pki/etcd/ca.crt \
--cert=/etc/kubernetes/pki/etcd/server.crt \
--key=/etc/kubernetes/pki/etcd/server.key"
etcdctl snapshot save /opt/backup/etcd-snapshot.db $E
Lưu ý: biến $E phải để không có dấu nháy khi gọi, nếu không shell sẽ coi cả chuỗi là một tham số.
Đừng đoán đường dẫn cert. Trên cluster kubeadm thì đường dẫn luôn nằm trong /etc/kubernetes/pki/etcd/, nhưng nếu đề cho cluster lạ, hãy kiểm tra bằng kubectl -n kube-system describe pod etcd-<node> và đọc phần Mounts.
Giữ lại data-dir cũ. Sau khi restore thành công, đừng xoá /var/lib/etcd. Nếu manifest mới có vấn đề, bạn chỉ cần sửa hostPath và --data-dir về lại giá trị cũ là cluster sống lại ngay. Đây là "bảo hiểm" miễn phí.
Thứ tự việc làm khi restore, thuộc lòng 5 bước:
1. Move `/etc/kubernetes/manifests/etcd.yaml` ra ngoài, chờ etcd container biến mất (`crictl ps | grep etcd`).
2. Chạy `etcdutl snapshot restore <file> --data-dir=/var/lib/etcd-restore`.
3. Sửa `--data-dir` trong `command` của manifest.
4. Sửa `hostPath.path` trong `volumes` của manifest.
5. Move manifest trở lại, chờ 20 đến 30 giây, verify bằng `crictl ps` rồi `kubectl get nodes`.
Backup định kỳ trong thực tế. Không ai chạy tay lệnh này mỗi ngày. Người ta đặt cron trên control plane node, ghi snapshot ra /opt/backup rồi đẩy lên object storage nằm ngoài cluster. Điểm cần nhớ: snapshot phải nằm ở nơi khác node control plane, nếu không thì mất node là mất luôn bản backup.
Đừng quên restore là bước bắt buộc trước khi upgrade. Bạn sẽ thấy điều này ở bài sau.
Thẻ ôn tập
[
{ "front": "etcd lưu những gì của cluster?", "back": "Toàn bộ state của cluster dưới dạng key-value, gồm mọi object, Secret, ConfigMap và trạng thái RBAC." },
{ "front": "etcd chạy dưới dạng gì trên control plane của cluster kubeadm?", "back": "Static pod, manifest tại /etc/kubernetes/manifests/etcd.yaml." },
{ "front": "Lệnh tạo snapshot etcd?", "back": "etcdctl snapshot save /path/snap.db kèm --endpoints, --cacert, --cert, --key." },
{ "front": "Port client của etcd là bao nhiêu?", "back": "2379 (port 2380 là peer traffic giữa các member)." },
{ "front": "Ba file cert cần cho etcdctl nằm ở đâu?", "back": "/etc/kubernetes/pki/etcd/ca.crt, server.crt và server.key." },
{ "front": "Công cụ được khuyến nghị để restore từ etcd 3.5 trở đi?", "back": "etcdutl snapshot restore (etcdctl snapshot restore đã deprecated)." },
{ "front": "Bước đầu tiên bắt buộc trước khi restore etcd?", "back": "Move /etc/kubernetes/manifests/etcd.yaml ra khỏi thư mục manifests để kubelet dừng static pod." },
{ "front": "Flag chỉ định thư mục dữ liệu mới khi restore?", "back": "--data-dir." },
{ "front": "Sau khi restore phải sửa những chỗ nào trong etcd.yaml?", "back": "Hai chỗ: --data-dir trong command và hostPath.path trong volumes." },
{ "front": "Lệnh kiểm tra snapshot có hợp lệ không?", "back": "etcdutl snapshot status /path/snap.db -w table." },
{ "front": "Khi etcd đã dừng thì kiểm tra bằng gì thay cho kubectl?", "back": "crictl ps, crictl logs và journalctl -u kubelet, vì kubectl cần etcd làm backend." },
{ "front": "Xem nhanh cấu hình etcd đang chạy bằng kubectl?", "back": "kubectl -n kube-system get pod etcd-<node> -o yaml, lọc theo data-dir và listen-client-urls." },
{ "front": "ETCDCTL_API=3 có còn bắt buộc không?", "back": "Không bắt buộc từ etcd 3.4 vì API v3 là mặc định, nhưng đặt vào vẫn an toàn." },
{ "front": "Object tạo sau thời điểm snapshot sẽ ra sao sau khi restore?", "back": "Biến mất, vì cluster quay về đúng trạng thái tại thời điểm snapshot." }
]
Tóm tắt và bài tiếp theo
Tóm gọn 4 dòng:
- Backup:
etcdctl snapshot savevới endpointhttps://127.0.0.1:2379và bộ ba cert trong/etc/kubernetes/pki/etcd/. - Verify:
etcdutl snapshot status <file> -w table. - Restore: tắt static pod bằng cách move manifest,
etcdutl snapshot restore --data-dir=<thư mục mới>, sửa cả--data-dirvàhostPath.path, rồi move manifest trở lại. - Bẫy lớn nhất: quên
hostPath. Bẫy thứ hai: dùngkubectlkhi etcd đã tắt.
Bài tiếp theo là Upgrade cluster bằng kubeadm và drain node. Ở đó bạn sẽ dùng lại chính kỹ năng này: quy trình chuẩn là backup etcd trước, upgrade control plane, rồi drain và upgrade từng worker node. Nếu bạn làm thành thạo bài hôm nay, bài upgrade sẽ nhẹ đi rất nhiều.