Upgrade cluster bằng kubeadm và drain node
Cluster của bạn đang chạy v1.30, đề thi yêu cầu nâng lên v1.31. Nghe thì đơn giản, nhưng đây là dạng bài mà người mới hay mất điểm nhất, không phải vì lệnh khó, mà vì sai thứ tự hoặc quên uncordon. Bài này tôi đi qua đúng trình tự tôi vẫn làm trong phòng thi, kèm những chỗ tôi từng làm hỏng cluster lab của mình.
Ôn lại nhanh
Bài trước bạn đã biết cách etcdctl snapshot save và restore. Nhắc lại một câu: backup etcd là bước 0 bắt buộc trước khi upgrade. Nếu kubeadm upgrade apply hỏng giữa chừng và control plane không lên được, snapshot etcd là đường lui duy nhất của bạn.
[!WARNING] Trong môi trường thi thật, bạn thường không cần backup etcd vì cluster lab dùng được ngay. Nhưng nếu đề có yêu cầu backup trước khi upgrade, hãy làm trước, đừng làm sau.
Mục tiêu học tập
Sau bài này, bạn phải làm được:
- Đọc đúng
kubeadm upgrade planvà xác định phiên bản đích hợp lệ (chỉ nhảy một minor version). - Nâng cấp control plane node đúng thứ tự: kubeadm, apply, drain, kubelet, uncordon.
- Nâng cấp từng worker node bằng
kubeadm upgrade nodevà đưa node về trạng thái phục vụ. - Xử lý được 4 lỗi drain/upgrade thường gặp nhất trong phòng thi.
Nguyên tắc không được phá
| Nguyên tắc | Chi tiết |
|---|---|
| Thứ tự | Control plane trước, worker sau, mỗi lần một node |
| Số minor | Mỗi lần chỉ nâng {{c1::một}} minor version (1.30 → 1.31, không nhảy 1.30 → 1.32) |
| Version skew | kubelet không được mới hơn kube-apiserver, chỉ được cũ hơn tối đa 3 minor; kubectl lệch tối đa 1 minor |
| Ai nâng gì | kubeadm upgrade nâng control plane components và image; kubelet/kubectl do bạn cài bằng package manager |
flowchart TD
Start["🚀 Bắt đầu"] --> Plan["📋 kubeadm upgrade plan"]
Plan --> CP1["🖥️ Control plane đầu tiên<br/>kubeadm upgrade apply"]
CP1 --> CPN["🖥️ Control plane còn lại<br/>kubeadm upgrade node"]
CPN --> W["⚙️ Từng worker node<br/>drain → upgrade node → uncordon"]
W --> Done["✅ kubectl get nodes"]
Ví dụ mẫu: nâng cấp cụm 1 control plane + 2 worker
Bối cảnh: controlplane, node01, node02 đều đang chạy v1.30.5, mục tiêu là v1.31.4. Bạn đang đứng trên controlplane.
Bước 1: Kiểm tra hiện trạng
kubectl get nodes -o wide
kubeadm version -o short
kubectl version --short
Ghi lại phiên bản hiện tại. Nếu các node lệch nhau sẵn (ví dụ node02 còn 1.29), xử lý node đó trước.
Bước 2: Xem phiên bản có thể cài
apt-get update
apt-cache madison kubeadm | head
Bạn sẽ thấy các dòng kiểu kubeadm | 1.31.4-1.1 | https://pkgs.k8s.io/.... Ghi nhớ chuỗi 1.31.4-1.1, đó là tên package đầy đủ cần dùng.
Bước 3: Nâng kubeadm trên control plane đầu tiên
apt-mark unhold kubeadm
apt-get install -y kubeadm=1.31.4-1.1
apt-mark hold kubeadm
kubeadm version
Nếu package đang bị hold mà bạn quên unhold, apt sẽ báo lỗi và gợi ý --allow-change-held-packages. Cả hai cách đều được.
Bước 4: Xem kế hoạch
kubeadm upgrade plan
Đọc kỹ output: nó liệt kê component nào sẽ lên version nào, và nhắc rằng kubelet phải nâng thủ công. Nếu thấy dòng cảnh báo version skew, dừng lại kiểm tra trước khi apply.
Bước 5: Nâng cấp control plane
kubeadm upgrade apply v1.31.4
Chờ tới dòng [upgrade/successful] SUCCESS!. Lệnh này restart các static pod kube-apiserver, kube-controller-manager, kube-scheduler, etcd bằng image mới. Nếu fail giữa chừng, đọc log, sửa nguyên nhân rồi chạy lại, lệnh này tương đối an toàn khi chạy lại.
Bước 6: Drain control plane node
kubectl drain controlplane --ignore-daemonsets
Bước 7: Nâng kubelet và kubectl
apt-mark unhold kubelet kubectl
apt-get install -y kubelet=1.31.4-1.1 kubectl=1.31.4-1.1
apt-mark hold kubelet kubectl
systemctl daemon-reload
systemctl restart kubelet
Bước 8: Đưa control plane về phục vụ
kubectl uncordon controlplane
kubectl get nodes
controlplane phải hiện v1.31.4 và không còn chữ SchedulingDisabled.
Bước 9: Nâng worker node01
Từ control plane, đẩy pod ra khỏi node:
kubectl drain node01 --ignore-daemonsets --delete-emptydir-data
SSH vào node01 rồi làm 3 việc:
apt-mark unhold kubeadm && apt-get install -y kubeadm=1.31.4-1.1 && apt-mark hold kubeadm
kubeadm upgrade node
apt-mark unhold kubelet kubectl && apt-get install -y kubelet=1.31.4-1.1 kubectl=1.31.4-1.1 && apt-mark hold kubelet kubectl
systemctl daemon-reload && systemctl restart kubelet
Quay lại control plane:
kubectl uncordon node01
kubectl get nodes
Bước 10: Lặp lại với node02 và kiểm tra cuối
kubectl get nodes
kubectl -n kube-system get pods
kubectl get pods -A | grep -v Running
Cả 3 node phải cùng version, mọi pod hệ thống Running, không còn node nào SchedulingDisabled.
[!NOTE] Nếu cụm có nhiều control plane node, các node phụ dùng
kubeadm upgrade node(không phảiapply), giống worker. Chỉ node control plane đầu tiên mới dùngkubeadm upgrade apply.
Luyện tập có hướng dẫn
Làm lần lượt, đừng mở đáp án trước khi thử. Mỗi bài đều có bước tự kiểm tra.
Bài 1: Đọc hiện trạng và lập kế hoạch
- Chạy
kubectl get nodes -o widevà ghi ra giấy: tên node, role, version. - Chạy
kubectl get node <node> -o jsonpath='{.status.nodeInfo.kubeletVersion}'cho từng node. - Chạy
kubeadm upgrade planvà trả lời: version đích là gì, kubelet có tự lên theo không.
Gợi ý và đáp án
kubectl get nodes -o widecho bạn cột VERSION, nhưng dùng jsonpath thì chắc chắn hơn khi đề yêu cầu version chính xác của kubelet.kubeadm upgrade planin ra bảng các component (kube-apiserver,kube-controller-manager,kube-scheduler,kube-proxy,CoreDNS) và version đích.- kubelet không tự lên. Bạn phải cài package và restart kubelet thủ công.
- Nếu output có dòng
Unable to check for upgradehoặc lỗi mạng, kiểm tra repopkgs.k8s.iotrong/etc/apt/sources.list.d/.
Bài 2: Drain an toàn một worker node
- Chạy thử trước:
kubectl drain node01 --ignore-daemonsets --delete-emptydir-data --dry-run=client. - Chạy thật, rồi kiểm tra trạng thái node.
- Kiểm tra pod đã được chuyển sang node khác chưa.
kubectl get nodes
kubectl get pods -A -o wide | grep node01
Gợi ý và đáp án
- Sau khi drain, node hiện
SchedulingDisabledtrong cột STATUS, đó là bình thường. - Pod còn lại trên node chỉ nên là DaemonSet pod (log agent, kube-proxy) và static pod nếu có.
- Nếu drain báo
cannot delete Pods with local storage, thêm--delete-emptydir-data. - Nếu drain báo
cannot delete DaemonSet-managed Pods, thêm--ignore-daemonsets. - Nếu có pod "trần" (không do controller quản lý), drain sẽ chặn, dùng
--forcesau khi chắc chắn pod đó bỏ được.
Bài 3: Nâng cấp control plane node
Thực hiện Bước 3 đến Bước 8 ở ví dụ mẫu trên cluster lab của bạn. Tự kiểm tra bằng:
kubectl get nodes
kubectl -n kube-system get pods
Gợi ý và đáp án
- Sau
kubeadm upgrade apply, các static pod trongkube-systemsẽ restart, đợi 1 đến 2 phút rồi mới kết luận là lỗi. - Nếu
kubectl get nodesvẫn hiện version cũ cho control plane, gần như chắc chắn bạn quênsystemctl restart kubelet. - Kiểm tra nhanh image đang chạy:
kubectl -n kube-system get pod kube-apiserver-controlplane -o jsonpath='{.spec.containers[0].image}'.
Bài 4: Nâng cấp worker node và uncordon
Làm đủ 3 bước trên node01: drain từ control plane, kubeadm upgrade node + cài kubelet trên node, uncordon từ control plane.
Gợi ý và đáp án
- Nhớ
systemctl daemon-reloadtrướcrestart kubelet, thiếu bước này kubelet có thể vẫn dùng binary cũ. - Trên worker không bắt buộc cài
kubectl, nhưng trong đề thi cứ cài cho đồng bộ. - Sau
uncordon, chạykubectl get nodestới khi node trả vềReadyvà version mới.
Bài 5: Tình huống lỗi tổng hợp
Cluster lab của bạn đang ở trạng thái: node02 hiện SchedulingDisabled, version vẫn 1.30.5, và kubectl drain node02 --ignore-daemonsets báo lỗi về local storage. Hãy đưa node02 lên 1.31.4 và trở lại phục vụ.
Gợi ý và đáp án
Trình tự đúng:
kubectl drain node02 --ignore-daemonsets --delete-emptydir-data(thêm flag còn thiếu).- SSH vào
node02, nângkubeadm, chạykubeadm upgrade node. - Nâng
kubeletvàkubectl, sau đósystemctl daemon-reload && systemctl restart kubelet. kubectl uncordon node02.- Kiểm tra
kubectl get nodes. Node phảiReadyvàv1.31.4, không cònSchedulingDisabled.
Lỗi hay gặp ở bài này: drain xong nhưng quên uncordon, hoặc uncordon sai node.
Lỗi thường gặp và cách xử lý
| Triệu chứng | Nguyên nhân | Cách sửa |
|---|---|---|
cannot delete DaemonSet-managed Pods |
Thiếu flag | Thêm --ignore-daemonsets |
cannot delete Pods with local storage |
Pod dùng emptyDir | Thêm --delete-emptydir-data |
| Drain treo ở pod không có controller | Pod "trần" | Thêm --force |
Node cứ ở SchedulingDisabled |
Chưa uncordon | kubectl uncordon <node> |
kubectl get nodes vẫn version cũ |
Chưa restart kubelet hoặc chưa cài package | systemctl daemon-reload && systemctl restart kubelet |
kubeadm upgrade apply báo version skew |
Nhảy quá một minor, hoặc kubelet mới hơn apiserver | Nâng tuần tự từng minor, control plane trước |
Node NotReady sau upgrade |
kubelet không khởi động được | systemctl status kubelet, journalctl -u kubelet -n 50 |
kubeadm upgrade plan lỗi kết nối |
Repo package chưa đúng | Kiểm tra file trong /etc/apt/sources.list.d/ |
[!TIP] Trước khi drain thật, luôn chạy
kubectl drain <node> --dry-run=clientđể biết ngay thiếu flag nào. Mất 5 giây, tiết kiệm vài phút.
Góc chuyên gia
Vài thứ tôi ước mình biết trước khi thi:
- Học thuộc 3 lệnh, không học thuộc 30 lệnh:
kubeadm upgrade plan,kubeadm upgrade apply,kubeadm upgrade node. Chỉ vậy thôi. Phần còn lại làapt-get installvàkubectl drain/uncordon. - Đề cho sẵn repo package. Đừng mất thời gian cấu hình
pkgs.k8s.io, chỉ cầnapt-cache madison kubeadmlà thấy version. apt-mark holdlà bạn của bạn. Nếu bạn từng holdkubelet kubeadm kubectlđể tránhapt upgradetự nâng, nhớunholdtrước khi cài.- Luôn kết thúc bằng
kubectl get nodes. Đây là bước chấm điểm thực tế: node đúng version và khôngSchedulingDisabled. - Đừng drain cả 3 node cùng lúc. Nếu cluster chỉ có 1 worker và bạn drain nó, pod hệ thống có thể không có chỗ chạy.
- Thời gian hợp lý: đề 1 control plane + 2 worker nên xong trong 10 đến 12 phút. Nếu quá 15 phút, kiểm tra xem có đang drain nhầm node hay đợi pod eviction quá lâu (
--timeout=60s). - Nếu bị kẹt ở
kubeadm upgrade apply, đọc dòng log cuối cùng. Phần lớn lỗi là do etcd không healthy hoặc certificate hết hạn, cả hai đều đã học ở bài trước.
Thẻ ôn tập nhanh
[
{ "front": "Thứ tự nâng cấp chuẩn của một cluster kubeadm?", "back": "Control plane node đầu tiên, rồi các control plane node còn lại, cuối cùng là từng worker node." },
{ "front": "Lệnh nâng cấp control plane node đầu tiên?", "back": "kubeadm upgrade apply v1.31.x" },
{ "front": "Lệnh nâng cấp một worker node hoặc control plane node phụ?", "back": "kubeadm upgrade node" },
{ "front": "Trước khi nâng cấp kubelet trên một node phải làm gì với pod?", "back": "kubectl drain node đó để đẩy pod sang node khác." },
{ "front": "Flag bắt buộc khi drain node có DaemonSet?", "back": "--ignore-daemonsets" },
{ "front": "Flag cần thêm khi pod trên node dùng emptyDir?", "back": "--delete-emptydir-data" },
{ "front": "Sau khi nâng cấp xong trên node, lệnh nào đưa node nhận pod trở lại?", "back": "kubectl uncordon <node>" },
{ "front": "kubectl cordon khác kubectl drain ở điểm nào?", "back": "cordon chỉ đánh dấu SchedulingDisabled; drain cordon rồi evict pod ra khỏi node." },
{ "front": "Có được nhảy từ 1.29 lên 1.31 trong một lần không?", "back": "Không, mỗi lần chỉ nâng một minor version, phải làm hai lần." },
{ "front": "Thành phần nào không được nâng cấp bởi kubeadm upgrade apply?", "back": "kubelet và kubectl, phải cài bằng package manager rồi restart kubelet." },
{ "front": "Lệnh xem kế hoạch nâng cấp trước khi thực hiện?", "back": "kubeadm upgrade plan" },
{ "front": "Sau khi cài kubelet bản mới cần chạy gì để kubelet dùng binary mới?", "back": "systemctl daemon-reload && systemctl restart kubelet" },
{ "front": "Quy tắc version skew giữa kubelet và kube-apiserver?", "back": "kubelet không được mới hơn kube-apiserver, chỉ được cũ hơn tối đa 3 minor version." },
{ "front": "Node hiển thị SchedulingDisabled nghĩa là gì?", "back": "Node đang bị cordon, không nhận pod mới cho tới khi uncordon." }
]
Kiểm tra nhanh bằng cloze
Điền từ còn thiếu:
- Để đẩy pod ra khỏi node trước khi nâng cấp, ta dùng
kubectl {{c2::drain}}. - Control plane node đầu tiên dùng
kubeadm upgrade {{c3::apply}}. - Các node còn lại dùng
kubeadm upgrade {{c4::node}}. - Sau khi nâng cấp xong, phải chạy
kubectl {{c5::uncordon}}để node nhận pod trở lại. - Node có DaemonSet cần thêm flag
--{{c6::ignore-daemonsets}}khi drain.
Tóm tắt và bước tiếp theo
Tóm gọn trong 5 dòng:
kubeadm upgrade plantrước,kubeadm upgrade applycho control plane đầu tiên,kubeadm upgrade nodecho phần còn lại.- Drain trước khi chạm vào kubelet, uncordon sau khi xong. Không bao giờ bỏ qua bước cuối.
kubeadmlo control plane,kubeletvàkubectldo bạn cài tay.- Mỗi lần một minor version, control plane luôn đi trước.
- Kết thúc bằng
kubectl get nodes: đúng version,Ready, khôngSchedulingDisabled.
Bài tiếp theo là Checkpoint: Cluster architecture và upgrade, một bài tổng hợp gồm dựng cluster bằng kubeadm, backup/restore etcd và nâng cấp cluster, đúng dạng bài bạn sẽ gặp trong phần 25% của đề CKA. Trước khi sang đó, hãy tự chạy lại Bài 5 mà không mở đáp án.