Skip to main content

6. Cluster Maintenance

Mục lục


1. Giới thiệu phần Cluster Maintenance

Phần này bàn về các chủ đề liên quan tới cluster maintenance. Bắt đầu với việc xem xét operating system upgrade — xem điều gì xảy ra khi mất một node khỏi cluster, hoặc khi chủ động đưa một node ra khỏi cluster, ví dụ để áp dụng patch hoặc upgrade trên chính OS. Sau đó xem tới quy trình cluster upgrade. Nhưng trước khi làm điều đó, cần biết một chút về Kubernetes release và version, cùng các best practice xoay quanh việc upgrade — khi nào nên upgrade, upgrade lên version nào, v.v.

Sau khi học quy trình upgrade, và được yêu cầu tự upgrade một cluster, sẽ tự thực hiện một lượt upgrade end-to-end cho một cluster đang có live application chạy trên đó. Cuối cùng, xem xét một số phương pháp backup và restore. Sẽ thực hành một kịch bản disaster recovery, trong đó backup Kubernetes cluster, rồi trải qua một disaster mô phỏng, sau đó được yêu cầu recover từ disaster đó và đưa cluster trở về trạng thái trước đó.


2. Bảo trì Node: OS Upgrade, Drain, Cordon và Uncordon

Bàn về các kịch bản có thể phải đưa node ra khỏi cluster, ví dụ cho mục đích bảo trì như upgrade phần mềm nền tảng, hoặc áp dụng các patch như security patch, v.v. trên cluster. Xem các lựa chọn để xử lý những trường hợp này.

Có một cluster với vài node và pod đang phục vụ application. Điều gì xảy ra khi một trong các node này down? Tất nhiên các pod trên đó không truy cập được. Tuỳ vào cách deploy các pod, user có thể bị ảnh hưởng. Ví dụ, vì có nhiều replica của pod blue, user truy cập application blue không bị ảnh hưởng, vì vẫn được phục vụ qua pod blue khác đang online. Tuy nhiên, user truy cập pod green bị ảnh hưởng vì đó là pod duy nhất chạy application green.

Vậy Kubernetes làm gì trong trường hợp này? Nếu node quay lại online ngay lập tức, process kubelet khởi động lại và các pod trở lại online. Tuy nhiên, nếu node down hơn 5 phút, các pod bị terminate khỏi node đó — Kubernetes xem chúng như đã chết. Nếu các pod đó thuộc một ReplicaSet, chúng sẽ được recreate trên node khác. Khoảng thời gian chờ pod quay lại online được gọi là pod eviction timeout, được set trên controller manager với giá trị mặc định là 5 phút. Trong các phiên bản Kubernetes hiện đại, việc eviction pod được xử lý qua node taint và pod toleration — khi một node trở thành NotReady hoặc unreachable, Kubernetes áp dụng taint NoExecute, và pod bị evict sau một grace period trừ khi chúng tolerate các taint đó.

Bất cứ khi nào node offline, master node chờ tối đa 5 phút trước khi coi node đó là dead. Khi node quay lại online sau pod eviction timeout, nó lên lại nhưng trống trơn, không có pod nào được lập lịch trên đó. Vì pod blue thuộc một ReplicaSet, nó có một pod mới được tạo trên node khác. Tuy nhiên, vì pod green không thuộc ReplicaSet nào, nó biến mất hoàn toàn.

Vì vậy, nếu có tác vụ bảo trì cần thực hiện trên một node, và biết rằng workload chạy trên node đó có các replica khác, và chấp nhận được việc chúng down trong một khoảng thời gian ngắn, và chắc chắn node sẽ quay lại online trong vòng 5 phút, có thể thực hiện upgrade nhanh rồi reboot. Tuy nhiên, không có gì chắc chắn node sẽ quay lại online trong 5 phút — thậm chí không chắc nó sẽ quay lại được.

Vậy có một cách an toàn hơn: chủ động drain node khỏi tất cả workload, để các workload được chuyển sang các node khác trong cluster. Về mặt kỹ thuật, chúng không thực sự được "di chuyển" — khi drain một node, các pod bị terminate một cách graceful khỏi node đó và được recreate trên node khác. Node cũng bị cordon hoặc đánh dấu unschedulable, nghĩa là không pod nào có thể được lập lịch trên node này cho tới khi gỡ bỏ hạn chế đó một cách tường minh. Giờ các pod đã an toàn trên các node khác, có thể reboot node đầu tiên. Khi nó quay lại online, nó vẫn ở trạng thái unschedulable, cần uncordon để các pod có thể được lập lịch trên nó trở lại.

Nhớ rằng, các pod đã được chuyển sang node khác không tự động quay về. Nếu bất kỳ pod nào trong số đó bị xoá, hoặc nếu có pod mới được tạo trong cluster, chúng mới được tạo trên node này.

Ngoài drainuncordon, còn có một lệnh khác gọi là cordon. Lệnh kubectl cordon chỉ đơn giản đánh dấu một node là unschedulable. Không như drain, nó không terminate hay di chuyển các pod đang có trên node — nó chỉ đảm bảo không có pod mới nào được lập lịch trên node đó.

💡 Hình dung: cordon giống treo biển "Không nhận khách mới" trước một quầy phục vụ — khách đang ngồi trong quầy vẫn được phục vụ bình thường, chỉ là không ai mới được xếp vào quầy đó nữa. Drain giống vừa treo biển đó, vừa lịch sự mời hết khách đang ngồi trong quầy chuyển sang quầy khác trước khi đóng cửa bảo trì. Uncordon là gỡ biển đó xuống — quầy nhận khách trở lại, nhưng khách cũ không tự động quay về, chỉ khách mới tới sau mới có thể được xếp vào đây.

Node lifecycle: cordon, drain, và uncordonReady(schedulable)cordon (pod ở nguyên)drain (evict pod trước)SchedulingDisabled(pod vẫn chạy nguyên chỗ)SchedulingDisabled(trống — pod đã evict)uncordonReady(schedulable lại)Pod đã chuyển node không tự quay về — chỉ pod mới mới được lập lịch lên node vừa uncordon

3. Lab: Thực hành Bảo trì Node

Có bao nhiêu node trong cluster? Set alias cho kubectl, chạy kubectl get nodes — có hai node: controlplanenode01.

Có bao nhiêu application được host trên cluster? Kiểm tra số deployment bằng kubectl get deploy — có một deployment.

Các application được host trên node nào? Chạy kubectl get pods — có ba pod. Dùng option wide để xem node — tất cả đều nằm trên node01.

Đưa node01 ra khỏi cluster để bảo trì: empty node khỏi mọi application và đánh dấu unschedulable. Lệnh để đưa một node xuống bảo trì là drain:

kubectl drain node01

Chạy lệnh này báo lỗi node chưa được drain, vì không thể xoá pod được quản lý bởi DaemonSet. Có các pod do DaemonSet quản lý trên node này, nên cần dùng option --ignore-daemonsets:

kubectl drain node01 --ignore-daemonsets

Lệnh này evict các pod của deployment blue. Chờ pod thứ ba được evict xong.

Các app hiện đang nằm trên node nào? Kiểm tra lại pod — giờ tất cả nằm trên controlplane. Trạng thái node node01SchedulingDisabled.

Sau khi hoàn tất các tác vụ bảo trì trên node01, không cần cấu hình lại gì thêm vì sẽ không có pod nào được lập lịch lại tự động. Để đưa node ra khỏi trạng thái SchedulingDisabled và quay lại cluster, dùng uncordon kèm tên node:

kubectl uncordon node01

Kiểm tra kubectl get nodes — node đã trở về trạng thái bình thường.

Có bao nhiêu pod được lập lịch trên node01? Chạy lại kubectl get pods -o wide — tất cả pod vẫn nằm trên controlplane. Vậy hiện không có pod nào trên node01 — đáp án là 0.

Vì sao không có pod nào trên node01? Không phải vì node01 bị faulty, cũng không phải vì nó bị cordon (vừa mới uncordon), cũng không phải vì upgrade không thành công. Lý do là chỉ khi có pod mới được tạo, chúng mới được lập lịch — hiện chưa có pod mới nào được tạo, chưa deploy application mới nào sau khi uncordon node, nên không kỳ vọng gì trên node đó cả. Các pod đã chuyển sang controlplane sẽ không tự động chuyển ngược lại node01.

Vì sao các pod lại được đặt trên node controlplane? Kiểm tra chi tiết node controlplane. Thông thường không kỳ vọng application được deploy trên control plane vì nó thường có một taint nào đó. Nhưng kiểm tra taint trên node controlplane — không có taint nào. Đó là lý do các pod được lập lịch trên control plane node — không phải vì nó faulty, cũng không phải vì không bao giờ chạy được pod trên control plane node, mà đơn giản vì nó không có taint nào. Thông thường, với multi-node cluster, master node hay control plane node sẽ có taint để ngăn pod được đặt lên đó — trong trường hợp này thì không.

Time-travel tới đợt bảo trì tiếp theo. Thử drain lại node01 bằng đúng lệnh trước đó (kubectl drain node01 --ignore-daemonsets) — lần này gặp lỗi: cannot delete pods not managed by ReplicationController, ReplicaSet, Job, DaemonSet, or StatefulSet. Use --force to override. Lệnh này không thành công.

Vì sao lệnh drain fail trên node01? Lần trước nó hoạt động. Có gì đó thay đổi — có một pod tên hr-app mới xuất hiện, được deploy như một pod đơn lẻ kể từ đợt bảo trì trước, và nó nằm trên node01. Khi drain, đầu tiên nó cordon node và đánh dấu unschedulable, sau đó cố evict mọi pod. Việc xoá các pod được quản lý bởi một trong các controller (ReplicaSet, Job, ReplicationController) khá dễ dàng, vì khi xoá pod, controller đó sẽ tự tạo lại pod trên node khác — rủi ro thấp. Nhưng trong trường hợp này, đây chỉ là một pod đơn lẻ, không thuộc Deployment, ReplicaSet hay bất kỳ controller nào — nếu xoá pod này như một phần của quá trình drain, pod đó cùng bất kỳ dữ liệu nào được tạo hoặc lưu local trên nó sẽ mất vĩnh viễn. Đó là lý do có thông báo lỗi này, và lệnh không tự kill/terminate pod đó.

Tên pod trên node01 không thuộc ReplicaSet là gì? hr-app.

Điều gì sẽ xảy ra với hr-app nếu drain node một cách cưỡng bức? Có option --force để drain node cưỡng bức. Thử dùng option này — điều xảy ra là pod này sẽ bị xoá và mất vĩnh viễn, vì không có gì di chuyển hay reschedule pod này sang worker node khác — đó chính là lý do lệnh drain ngăn không cho làm điều đó. Đáp án: hr-app sẽ mất vĩnh viễn.

Không muốn điều đó xảy ra, vì hr-app là một application quan trọng không nên bị destroy. Đã revert lại trạng thái trước đó và redeploy hr-app dưới dạng một Deployment. Kiểm tra deployment — hr-app giờ được deploy dưới dạng Deployment. Kiểm tra pod — hr-app được deploy như một Deployment, có ReplicationController tương ứng, và vẫn nằm trên node01.

hr-app là app quan trọng, không muốn bị gỡ bỏ, cũng không muốn có pod mới nào được lập lịch trên node01. Cần đánh dấu node01 là unschedulable để không pod mới nào được lập lịch trên đó, nhưng vẫn phải đảm bảo hr-app không bị ảnh hưởng. Cách để làm điều này là chỉ cordon node — nếu drain, hr-app sẽ bị kill; nếu không làm gì, application khác có thể được lập lịch lên node vì nó đang ở trạng thái Ready. Dùng cordon:

kubectl cordon node01

Lệnh này chỉ đánh dấu node ở trạng thái SchedulingDisabled, đồng thời hr-app hoàn toàn không bị ảnh hưởng.


4. Kubernetes Software Releases và Versioning

Xem cách Kubernetes quản lý software release. Đã biết gì về API version trong Kubernetes cho tới nay? Khi cài đặt một Kubernetes cluster, cài đặt một version cụ thể của Kubernetes. Có thể thấy điều này khi chạy lệnh kubectl get nodes — ví dụ, version 1.33.0.

Nhìn kỹ hơn vào con số version này. Kubernetes release version gồm ba phần: major version, theo sau là minor version, rồi patch version. Minor version được release mỗi vài tháng với các tính năng và chức năng mới, trong khi patch được release thường xuyên hơn với các bản fix bug quan trọng.

Giống nhiều application phổ biến khác, Kubernetes theo một quy trình versioning phần mềm chuẩn. Mỗi vài tháng, nó ra mắt các tính năng và chức năng mới qua một minor release. Major version đầu tiên, version 1.0, được release vào tháng 7 năm 2015, các release sau đó tiếp tục qua các năm 2016 tới 2018, tới version 1.20 vào năm 2020, và version 1.33 vào tháng 4 năm 2025.

Ngoài ra còn có các bản alpha và beta release. Mọi bug fix và cải tiến trước tiên đi vào bản alpha release, gắn nhãn alpha. Ở release này, các tính năng bị tắt mặc định và có thể còn lỗi. Sau đó chúng chuyển tới bản Beta release, nơi code đã được test kỹ hơn — các tính năng mới được bật mặc định ở release này. Cuối cùng, chúng chuyển tới bản stable release.

Có thể tìm mọi release trên trang releases của Kubernetes repository hoặc trang tài liệu. Tải file kubernetes.tar.gz và giải nén để tìm executable cho tất cả các component khác nhau. Gói tải về, khi giải nén, chứa tất cả control plane component trong đó, tất cả đều cùng version.

Nhớ rằng có những component khác trong control plane không có cùng số version — etcd cluster và CoreDNS server có version riêng của chúng, vì đây là các project riêng biệt. Release note của mỗi bản release có thông tin về các version tương thích của các application phụ thuộc như etcd và CoreDNS. Xem link tham khảo cho một số thông tin này (mục 10 bên dưới).


5. Quy trình Nâng cấp Cluster

Ở phần trước đã xem Kubernetes quản lý software release ra sao và cách các component khác nhau có version riêng. Tạm gác các dependency với component bên ngoài như etcd và CoreDNS sang một bên, tập trung vào core control plane component. Có bắt buộc tất cả những component này phải cùng version không? Không, các component có thể ở các release version khác nhau.

Vì kube-apiserver là component chính trong control plane, và là component mà mọi component khác nói chuyện tới, không component nào khác nên ở version cao hơn kube-apiserver. Controller manager và scheduler có thể ở version thấp hơn một bậc — nếu kube-apiserver ở version x, controller manager và kube-scheduler có thể ở x hoặc x-1. Kubelet cùng kube-proxy có thể ở version thấp hơn tối đa ba bậc, tức x-3 (từ kubelet 1.25 trở về trước, giới hạn này chỉ là hai bậc — x-2). Ví dụ, nếu kube-apiserver ở 1.35, controller manager và scheduler có thể ở 1.35 hoặc 1.34, và kubelet cùng kube-proxy có thể ở tới 1.32. Không component nào được ở version cao hơn kube-apiserver, ví dụ 1.36.

Điều này không áp dụng cho kubectl. Utility kubectl có thể ở 1.36 (cao hơn API server một version), cùng version với API server (1.35), hoặc thấp hơn (1.34).

Độ lệch version được phép này (permissible skew) cho phép thực hiện live upgrade — có thể upgrade từng component nếu cần.

💡 Hình dung: version skew giống một đoàn tàu nhiều toa nối nhau — đầu tàu (kube-apiserver) phải luôn chạy phía trước hoặc ngang hàng, không toa nào được vượt lên trước đầu tàu. Toa gần đầu tàu (controller manager, scheduler) chỉ được phép tụt lại tối đa 1 bậc, còn toa xa nhất (kubelet, kube-proxy) được nới lỏng hơn — tụt lại tối đa 3 bậc mà đoàn tàu vẫn chạy an toàn.

Version skew policy: độ lệch cho phép so với kube-apiserverkube-apiserverversion X (cao nhất)≤ 1 bậccontroller-manager / schedulerX hoặc X-1≤ 3 bậckubelet / kube-proxyX, X-1, X-2, hoặc X-3±1 bậckubectlX+1, X, hoặc X-1Không component nào (trừ kubectl) được cao hơn kube-apiserver

Vậy khi nào nên upgrade? Giả sử đang ở 1.10, và Kubernetes release version 1.11 và 1.12. Tại bất kỳ thời điểm nào, Kubernetes chỉ hỗ trợ tối đa ba minor version gần nhất. Với 1.12 là bản release mới nhất, Kubernetes hỗ trợ 1.12, 1.11, và 1.10. Khi 1.13 được release, chỉ còn 1.13, 1.12, và 1.11 được hỗ trợ. Trước khi 1.13 được release là thời điểm tốt để upgrade cluster lên bản release mới.

Upgrade thế nào? Có upgrade trực tiếp từ 1.10 lên 1.13 không? Không. Cách tiếp cận được khuyến nghị là upgrade từng minor version một: 1.10 lên 1.11, rồi 1.11 lên 1.12, rồi 1.12 lên 1.13.

Quy trình upgrade phụ thuộc vào cách cluster được thiết lập. Ví dụ, nếu là managed Kubernetes cluster deploy trên cloud service provider như Google, Google Kubernetes Engine cho phép upgrade cluster dễ dàng chỉ với vài cú click. Nếu deploy cluster bằng tool như kubeadm, tool này có thể giúp lên kế hoạch và upgrade cluster. Nếu deploy cluster from scratch, sẽ phải tự upgrade các component khác nhau của cluster thủ công. Ở đây tập trung vào các lựa chọn bằng kubeadm.

Có một cluster với master và worker node, đang chạy production, host pod, phục vụ user. Các node và component đang ở version 1.10. Upgrade cluster gồm hai bước chính: đầu tiên upgrade master node, sau đó upgrade worker node. Trong lúc master đang được upgrade, các control plane component như API server, scheduler, và controller manager sẽ down trong một khoảng ngắn. Master down không có nghĩa worker node và application trên cluster bị ảnh hưởng. Mọi workload host trên worker node tiếp tục phục vụ user bình thường. Vì master đang down, mọi chức năng quản lý đều down — không thể truy cập cluster qua kubectl hay Kubernetes API, không thể deploy application mới hay xoá/sửa cái hiện có. Controller manager cũng không hoạt động — nếu một pod fail, một pod mới sẽ không tự động được tạo. Nhưng chừng nào node và pod còn up, application vẫn up và user không bị ảnh hưởng. Sau khi upgrade hoàn tất và cluster trở lại, nó sẽ hoạt động bình thường.

Giờ master và các master component ở version 1.11, worker node vẫn ở 1.10 — như đã biết, đây là cấu hình được hỗ trợ. Đến lúc upgrade worker node. Có nhiều chiến lược khác nhau để upgrade worker node:

  • Upgrade tất cả cùng lúc: pod sẽ down và user không thể truy cập application trong lúc các node đang upgrade. Sau khi hoàn tất, node lên lại, pod mới được lập lịch, user tiếp tục truy cập. Đây là chiến lược cần downtime.
  • Upgrade từng node một: quay lại trạng thái master đã upgrade và các node đang chờ upgrade — đầu tiên upgrade node đầu, workload chuyển sang node thứ hai và thứ ba, user vẫn được phục vụ từ đó. Sau khi node đầu upgrade xong và lên lại, tiếp tục node thứ hai, workload chuyển sang node một và ba. Cuối cùng node thứ ba, workload chia sẻ giữa hai node đầu. Lặp lại quy trình tương tự để upgrade các node từ 1.11 lên 1.12 rồi 1.13.
  • Thêm node mới với version mới hơn: đặc biệt thuận tiện nếu đang ở môi trường cloud, nơi có thể dễ dàng provision node mới và decommission node cũ. Node với software version mới có thể được thêm vào cluster, chuyển workload sang node mới rồi gỡ node cũ, cho tới khi tất cả node đều mới với software version mới.
3 chiến lược upgrade worker nodeAll-at-onceNode (v1.10)tất cả down cùng lúc (downtime)Node (v1.13)One-at-a-timeNode (v1.10)từng node một, luôn còn phục vụNode (v1.13)Node mới, gỡ node cũNode cũ (v1.10)thêm node mới trước, gỡ node cũ sauNode mới (v1.13)

Giả sử upgrade cluster từ 1.11 lên 1.13, kubeadm có lệnh upgrade giúp upgrade cluster. Với kubeadm, chạy lệnh kubeadm upgrade plan — lệnh này cho ra rất nhiều thông tin hữu ích: version hiện tại của cluster, version của tool kubeadm, version stable mới nhất của Kubernetes, danh sách tất cả control plane component cùng version của chúng và version chúng có thể upgrade lên. Nó cũng cho biết sau khi upgrade các control plane component, phải tự upgrade version kubelet trên từng node — nhớ rằng kubeadm không cài đặt hay upgrade kubelet. Cuối cùng, nó cho lệnh để upgrade cluster.

Cũng lưu ý phải upgrade chính tool kubeadm trước khi có thể upgrade cluster. Tool kubeadm cũng tuân theo cùng cách versioning phần mềm như Kubernetes. Đang ở 1.11 và muốn lên 1.13, nhưng chỉ có thể đi từng minor version một lúc, nên trước tiên đi tới 1.12: đầu tiên upgrade chính tool kubeadm lên version 1.12, sau đó upgrade cluster bằng lệnh từ output của upgrade plan:

kubeadm upgrade apply

Lệnh này pull các image cần thiết và upgrade các component của cluster. Hoàn tất, các control plane component giờ ở 1.12. Nếu chạy kubectl get nodes, vẫn thấy master node ở 1.11 — vì trong output của lệnh này, nó hiển thị version của kubelet trên từng node được đăng ký với API server, không phải version của chính API server.

Bước tiếp theo là upgrade kubelet. Nhớ rằng tuỳ vào setup, có thể có hoặc không có kubelet chạy trên master node. Trong trường hợp này, cluster deploy bằng kubeadm có kubelet trên master node, dùng để chạy các control plane component dưới dạng pod trên master node. (Khi tự thiết lập một Kubernetes cluster from scratch sau này trong khoá học, sẽ không cài kubelet trên master node — sẽ không thấy master node trong output của lệnh này trong trường hợp đó.)

Bước tiếp theo là upgrade kubelet trên master node. Nếu có kubelet trên đó, chạy lệnh apt-get install kubelet cho việc này. Sau khi package được upgrade, restart kubelet service. Chạy kubectl get nodes lúc này cho thấy master đã được upgrade lên 1.12. Worker node vẫn ở 1.11.

Tiếp tục với worker node, từng cái một. Đầu tiên cần di chuyển workload từ worker node đầu tiên sang các node khác. Lệnh kubectl drain cho phép an toàn terminate mọi pod khỏi một node và reschedule chúng sang các node khác — nó cũng cordon node, đánh dấu unschedulable để không pod mới nào được lập lịch trên đó. Sau đó upgrade các package kubeadmkubelet trên worker node, như đã làm trên master node. Rồi dùng lệnh upgrade của tool kubeadm để update cấu hình node cho version kubelet mới, sau đó restart kubelet service. Node giờ nên đã lên với software version mới.

Tuy nhiên, khi drain node, thực chất đã đánh dấu nó unschedulable. Cần gỡ đánh dấu đó bằng lệnh:

kubectl uncordon node01

Node giờ đã schedulable trở lại. Nhưng nhớ rằng, không nhất thiết các pod sẽ quay về ngay node này — nó chỉ được đánh dấu schedulable. Chỉ khi pod bị xoá khỏi các node khác, hoặc khi có pod mới được lập lịch, chúng mới thực sự quay về node đầu tiên này. Quy trình tương tự sẽ lặp lại khi đưa node thứ hai xuống để upgrade, và cuối cùng là node thứ ba. Sau đó tất cả node đã được upgrade.


6. Demo: Nâng cấp Cluster từ 1.28 lên 1.29 bằng kubeadm

Demo này đi qua quy trình upgrade một Kubernetes cluster từ version 1.28 lên version 1.29, bám theo tài liệu Kubernetes khi upgrade bằng kubeadm. Trên trang tài liệu Kubernetes, vào mục Tasks → Administer a Cluster → Administration with kubeadm → Upgrading a kubeadm Cluster. Trang này có đầy đủ hướng dẫn để thực hiện upgrade một Kubernetes cluster bằng kubeadm, với hướng dẫn riêng cho từng cặp version upgrade — ví dụ 1.28 lên 1.29 (mới nhất tại thời điểm ghi hình), nhưng cũng có 1.27 lên 1.28, 1.26 lên 1.27, 1.25 lên 1.26, và 1.24 lên 1.25. Chọn đúng upgrade path đang thực hiện — các bước gần như giống hệt nhau dù đang upgrade version nào.

Bước 1 — Thay đổi package repository. Có một lưu ý quan trọng ở đầu tài liệu về việc thay đổi package repository: các package repository cũ cho các tool và component Kubernetes được lưu tại apt.kubernetes.ioyum.kubernetes.io. Những repository này đã bị deprecated. Từ giờ, cần dùng repository pkgs.k8s.io để tải các phiên bản mới nhất của kubectl, kubeadm, và các tool khác.

Trước tiên xác định distribution đang dùng, vì lệnh sẽ khác nhau tuỳ distro. Cluster demo là two-node cluster (kubectl get nodes cho thấy một control plane, một worker node — dù cluster có 2, 3, 5 node, các bước upgrade đều giống hệt). Kiểm tra distribution bằng:

cat /etc/*-release

Kết quả cho thấy đang dùng Ubuntu 20.04.6 (Debian-based). Theo hướng dẫn cho hệ Debian/Ubuntu, thay thế định nghĩa apt repository để trỏ tới cái mới — chỉ cần copy lệnh mẫu, dán vào text editor, và cập nhật minor version cụ thể muốn dùng (có repository riêng cho mỗi minor version — 1.28, 1.29, 1.27, 1.26...). Vì đang upgrade lên version 1.29, đổi thành Debian 9 trong lệnh mẫu.

Có lệnh thứ hai để tải public signing key cho các Kubernetes package repository — copy lệnh, dán vào text editor, và cũng chỉ định version 1.29. Sau khi chạy cả hai lệnh, chạy apt-get update là xong. Thực hiện các bước này trên cả control plane node và worker node (nếu có cluster 3, 4, 5, 10 node, lặp lại trên tất cả các node).

Bước 2 — Xác định version cụ thể cần upgrade tới. Đang upgrade từ 1.28 lên 1.29, nhưng cần xác định version cụ thể trong nhánh 1.29 — chọn version mới nhất trong nhánh này. Sau khi update, chạy:

apt-cache madison kubeadm

Lệnh này cho thấy các version khả dụng, ví dụ 1.29.0-1.1 và mới nhất là 1.29.3-1.1 — chọn version mới nhất này.

Bước 3 — Upgrade control plane node. Luôn upgrade control plane trước, rồi mới tới worker node. Chọn một control plane node bất kỳ (nếu có nhiều), bước đầu tiên là upgrade tool kubeadm:

apt-get update && apt-get install -y kubeadm=1.29.3-1.1

Xác nhận bằng kubeadm version — thấy version 1.29, cụ thể 1.29.3. Tiếp theo chạy:

sudo kubeadm upgrade plan

Lệnh plan cho biết các version có thể upgrade tới, kiểm tra tương thích, và cảnh báo nếu có vấn đề. Output cho thấy: kubeadm hiện ở 1.29.3, cluster ở 1.28.0. Sau control plane, kubelet phải được upgrade thủ công — kubeadm không bao giờ tự upgrade kubelet. Phần đầu output cho biết cách upgrade lên version mới nhất trong nhánh 1.28 (1.28.8) nếu muốn — nhưng ở đây muốn upgrade lên 1.29.3, với các component mà kubeadm sẽ tự động upgrade được liệt kê, và phải chạy:

sudo kubeadm upgrade apply v1.29.3

Đây là lệnh thực hiện quá trình upgrade. Sau khi chạy xong, upgrade thành công. Nhưng nếu chạy kubectl get nodes lúc này vẫn thấy version 1.28.0 — vì cột version này lấy từ version kubelet đang chạy, và kubelet cần được upgrade thủ công sau khi kubeadm chạy xong.

Nếu cần upgrade CNI provider plugin (một số version yêu cầu điều này để hoạt động trơn tru với version mới), thực hiện ở bước này — trong demo này không cần thay đổi gì nên bỏ qua. Nếu có nhiều control plane node, các node còn lại sẽ chạy cùng các lệnh thay đổi package repository, upgrade kubeadm, nhưng thay vì kubeadm upgrade apply, dùng lệnh kubeadm upgrade node trên các control plane node đó.

Bước 4 — Upgrade kubelet trên control plane node. Bất cứ khi nào động tới kubelet, cần drain node trước — kể cả trên control plane node, vì chúng cũng có pod đang chạy (như CoreDNS pod và một số control plane component chạy dưới dạng pod). Drain bằng:

kubectl drain controlplane --ignore-daemonsets

Sau đó upgrade kubelet — lệnh upgrade kubelet cũng đồng thời upgrade kubectl:

apt-get update && apt-get install -y kubelet=1.29.3-1.1 kubectl=1.29.3-1.1

Sau đó restart kubelet process:

sudo systemctl daemon-reload
sudo systemctl restart kubelet

Chạy kubectl get node — control plane node đã lên 1.29.3, nhưng scheduling vẫn disabled vì đã drain node. Uncordon:

kubectl uncordon controlplane

Kiểm tra lại — không còn SchedulingDisabled bên cạnh control plane node. Nếu có nhiều control plane node, lặp lại quy trình tương tự trên từng node — drain, upgrade kubeadm và kubectl, upgrade, rồi restart kubelet — cho tới khi tất cả được upgrade.

Bước 5 — Upgrade worker node. Tài liệu có hướng dẫn riêng cho máy Linux và Windows — dùng hướng dẫn Linux. Cũng có bước đổi package repository, nhưng đã làm điều này rồi trên worker node. Upgrade kubeadm trên worker node (dùng lại lệnh đã lưu trong text editor):

apt-get update && apt-get install -y kubeadm=1.29.3-1.1

Sau đó, thay vì kubeadm upgrade apply, chạy:

sudo kubeadm upgrade node

Sau đó, tương tự control plane node, cần drain node — thực hiện lệnh này từ control plane node:

kubectl drain node01 --ignore-daemonsets

Sau đó upgrade kubeletkubectl (nếu có cài kubectl trên node — không bắt buộc nhưng nếu có thì cũng nên upgrade):

apt-get update && apt-get install -y kubelet=1.29.3-1.1 kubectl=1.29.3-1.1

Restart kubelet process:

sudo systemctl daemon-reload
sudo systemctl restart kubelet

Cuối cùng, uncordon node để có thể deploy pod lên đó lần nữa:

kubectl uncordon node01

Node đã được upgrade chính thức. Chạy kubectl get nodes — cả hai node đều đang ở version 1.29.3. Với cluster có nhiều worker node hơn, sau khi hoàn tất node đầu tiên, lặp lại đúng quy trình này trên từng worker node kế tiếp: upgrade kubeadm, chạy sudo kubeadm upgrade node, drain node trước khi update kubelet, update kubelet, restart kubelet, rồi uncordon — cho tới khi toàn bộ cluster được upgrade.


7. Lab: Thực hành Nâng cấp Cluster

Bài lab này test kỹ năng upgrade một Kubernetes cluster, với một production cluster đang có application chạy trên đó.

Version hiện tại của cluster là gì? Chạy kubectl get nodes — có hai node, version hiện tại là 1.19.0.

Có bao nhiêu node trong cluster? Hai node, gồm master và worker node.

Có bao nhiêu node có thể host workload trong cluster? Kiểm tra application và taint trên node bằng kubectl describe node, tìm taint — không có taint nào. Nghĩa là cả hai worker node đều có thể host application.

Có bao nhiêu application được host trên cluster? Chạy kubectl get deploy — có một application, application blue.

Các pod được host trên node nào? Chạy kubectl get pods -o wide — pod nằm trên cả control plane lẫn node01.

Nhiệm vụ: upgrade cluster mà không được ảnh hưởng user truy cập application, và không được provision VM mới. Hiện có hai VM: control plane và node01. Không thể provision VM mới, và user không được bị ảnh hưởng — không thể take down application hoàn toàn. Chiến lược nào phù hợp: upgrade từng node một trong khi di chuyển workload sang node còn lại — đây là lựa chọn tốt nhất. Các lựa chọn khác không phù hợp: nếu chỉ nói "user sẽ bị ảnh hưởng vì chỉ có một worker node" là sai, vì đã thấy workload có thể được lập lịch trên cả control plane lẫn worker node dù chỉ có một worker node — vậy dù take down worker node, deployment/application vẫn được recreate trên control plane node, user không bị ảnh hưởng. "Upgrade tất cả node cùng lúc" cũng sai vì application sẽ down trong lúc các node được upgrade, user bị ảnh hưởng. "Thêm node mới với version mới trong khi gỡ node cũ" cũng sai vì đề bài nói không được provision VM mới.

Version stable mới nhất khả dụng để upgrade bằng tool kubeadm là gì? Chạy kubeadm upgrade plan — câu hỏi không phải hỏi version stable mới nhất của Kubernetes nói chung, mà là version stable mới nhất mà chính tool kubeadm hiện tại biết tới. kubeadm hiện đang ở version 1.19, và version kubeadm này có thể upgrade cluster lên v1.19.16. Nếu cần upgrade lên version cao hơn (remote version tại thời điểm ghi hình là 1.23.5), như 1.20, 1.21, thì cần upgrade chính tool kubeadm trước. Nhưng để trả lời câu hỏi này, version stable khả dụng tại thời điểm ghi hình là 1.19.16.

Upgrade master node trước — drain master node khỏi workload và đánh dấu unschedulable.

kubectl drain controlplane --ignore-daemonsets

Chờ pod được evict. Kiểm tra trạng thái — control plane đã SchedulingDisabled, và các pod đều nằm trên node01.

Upgrade control plane component lên đúng version 1.20.0. Cần upgrade tool kubeadm trước, sau đó master component, rồi tới kubelet — đó là các bước ở mức cao. Tham khảo trang tài liệu Kubernetes, mục Upgrading kubeadm clusters, chọn đúng bản hướng dẫn 1.19 → 1.20 (tuỳ thời điểm làm bài, chọn đúng cặp version tương ứng câu hỏi). Trong hướng dẫn có hai phần: upgrading control plane nodes và upgrading worker nodes — nhớ theo đúng phần cần.

Cũng có hai bộ hướng dẫn: cho Ubuntu/Debian và cho CentOS — nếu chưa chắc, kiểm tra bằng cat /etc/*release. Xác nhận đang dùng Ubuntu.

Xác định chính xác version cần upgrade tới bằng lệnh xác định version có sẵn (theo hướng dẫn) — xác nhận là 1.20.0, cụ thể package là 1.20.0-00.

Upgrade kubeadm trước — có hai cách: chạy 3 lệnh riêng, hoặc gộp 2 lệnh (yêu cầu apt-get version lớn hơn 1.1, kiểm tra bằng apt-get version — xác nhận đang ở 1.16, đủ điều kiện dùng cách gộp):

apt-get update && apt-get install -y kubeadm=1.20.0-00

Xác nhận bằng kubeadm version — đã lên 1.20.0. Chạy lại kubeadm upgrade plan để lấy plan mới, thấy version hiện tại của API server và version khả dụng để upgrade tới. Chạy:

kubeadm upgrade apply v1.20.0

Xác nhận muốn tiếp tục — cluster đã upgrade lên version 1.20.0. Bước tiếp theo được gợi ý là upgrade CNI plugin — bỏ qua bước này. Không có control plane node nào khác cần xử lý. Node đã drain sẵn nên không cần làm lại bước đó.

Bước cuối là upgrade kubeletkubectl utility — theo cùng lệnh mẫu, đổi version thành 1.20.0. Sau đó restart kubelet:

apt-get update && apt-get install -y kubelet=1.20.0-00 kubectl=1.20.0-00
sudo systemctl daemon-reload
sudo systemctl restart kubelet

Đánh dấu control plane node schedulable trở lại:

kubectl uncordon controlplane

Xác nhận đã thành công.

Drain worker node khỏi workload và đánh dấu unschedulable. Node đang ở trạng thái Ready:

kubectl drain node01 --ignore-daemonsets

Chờ pod được evict. Kiểm tra trạng thái node — node01 đã cordon, tất cả pod nằm trên control plane. Vậy workload đã an toàn chuyển sang control plane, có thể upgrade node01 an toàn.

Upgrade worker node lên đúng version 1.20.0. Quy trình upgrade trên worker node nên thực hiện từng node một, hoặc vài node một, mà không ảnh hưởng capacity tối thiểu cần thiết — điều này đã được đảm bảo. Bước đầu tiên là upgrade kubeadm — thực hiện trên chính worker node. SSH vào worker node (gõ tên node nếu đã cấu hình, hoặc lấy internal IP qua kubectl get nodes -o wide rồi SSH tới đó).

Trên node01, upgrade kubeadm:

apt-get update && apt-get install -y kubeadm=1.20.0-00

Bước tiếp theo là gọi:

sudo kubeadm upgrade node

Lệnh này upgrade cấu hình kubelet local. Node đã được drain từ trước nên không cần làm lại. Bước tiếp theo là upgrade kubeletkubectl:

apt-get update && apt-get install -y kubelet=1.20.0-00 kubectl=1.20.0-00

Restart kubelet:

sudo systemctl daemon-reload
sudo systemctl restart kubelet

Cuối cùng, quay lại control plane node, uncordon node01:

kubectl uncordon node01

Kiểm tra trạng thái node — cả hai đều đang ở 1.20 và ở trạng thái Ready. Đã thành công di chuyển workload giữa các node và upgrade cả hai node trong cluster.


8. Backup và Restore trong Kubernetes

Xem các phương pháp backup và restore khác nhau. Trước tiên xem xét những gì nên backup trong một Kubernetes cluster. Đã deploy nhiều application khác nhau lên cluster bằng Deployment, Pod, và Service definition file. Đã biết etcd cluster là nơi lưu mọi thông tin liên quan tới cluster. Và nếu application được cấu hình với persistent storage, đó cũng là một đối tượng cần backup.

Với các resource đã tạo trong cluster, đôi khi dùng cách imperative để tạo object bằng cách chạy một lệnh, như khi tạo một namespace, Secret, hay ConfigMap, hoặc đôi khi để expose application. Và đôi khi dùng cách declarative — tạo definition file trước rồi chạy kubectl apply trên file đó. Đây là cách tiếp cận được ưu tiên nếu muốn lưu lại cấu hình, vì lúc đó có tất cả object cần thiết cho một application dưới dạng definition file trong một folder duy nhất. File này có thể dễ dàng tái sử dụng sau này hoặc chia sẻ với người khác. Tất nhiên phải luôn có một bản copy của các file này được lưu trữ đầy đủ.

Một thực hành tốt là lưu các file này trên source code repository — nhờ đó có thể được duy trì bởi cả team. Source code repository nên được cấu hình với giải pháp backup phù hợp. Với các source code repository công khai/được quản lý như GitHub, không cần lo lắng về điều này. Nhờ vậy, kể cả khi mất toàn bộ cluster, vẫn có thể redeploy application lên cluster chỉ bằng cách apply lại các configuration file này.

Dù cách declarative là cách tiếp cận được ưu tiên, không có gì đảm bảo tất cả thành viên trong team đều tuân theo chuẩn đó. Điều gì nếu ai đó tạo một object theo cách imperative mà không ghi lại thông tin đó ở đâu cả? Vậy một cách tiếp cận tốt hơn để backup resource configuration là query kube-api server. Query kube-api server dùng kubectl hoặc truy cập trực tiếp API server, và lưu lại toàn bộ resource configuration của mọi object đã tạo trên cluster như một bản copy. Ví dụ, một trong các lệnh có thể dùng trong một backup script là lấy tất cả pod, deployment, và service trong tất cả namespace bằng lệnh kubectl get all, xuất output ở định dạng YAML rồi lưu file đó:

kubectl get all --all-namespaces -o yaml > all-resources-backup.yaml

# Output minh họa (rút gọn)
apiVersion: v1
items:
- apiVersion: v1
kind: Pod
metadata:
name: webapp-blue-7d9f8c
namespace: default
spec:
containers:
- image: kodekloud/webapp-color:v1
name: webapp
status:
phase: Running
- apiVersion: apps/v1
kind: Deployment
metadata:
name: webapp-blue
namespace: default
spec:
replicas: 3
kind: List

(Output minh họa — cấu trúc đúng theo lệnh thật, số liệu cụ thể chỉ mang tính ví dụ.) File YAML này dùng lại được với kubectl apply -f để tái tạo resource, nhưng chỉ chứa những gì kubectl get all liệt kê — không bao gồm ConfigMap, Secret, PersistentVolume, và nhiều resource type khác, nên trong thực tế một backup script đầy đủ phải lặp qua nhiều resource group hơn con số này. Và đó mới chỉ là một vài resource group — còn nhiều resource group khác cần cân nhắc. Tất nhiên, không nhất thiết phải tự xây giải pháp này — có các tool như Ark, giờ gọi là Velero của Heptio, có thể làm việc này thay, giúp backup Kubernetes cluster dùng Kubernetes API.

Tiếp tục với etcd. etcd cluster lưu thông tin về trạng thái cluster — thông tin về cluster, các node, và mọi resource khác được tạo trong cluster đều được lưu ở đây. Vậy thay vì backup từng resource như trên, có thể chọn backup chính etcd server. Như đã biết, etcd cluster được host trên master node. Khi cấu hình etcd, đã chỉ định một vị trí lưu toàn bộ dữ liệu — data directory. Đó chính là directory có thể cấu hình để được backup bởi backup tool.

etcd cũng đi kèm sẵn một giải pháp snapshot built-in. Có thể take snapshot của etcd database bằng lệnh snapshot save của utility etcdctl, đặt tên cho snapshot, ví dụ snapshot.db. Một file snapshot được tạo với tên đó trong directory hiện tại — nếu muốn tạo ở vị trí khác, chỉ định full path. Có thể xem trạng thái của backup bằng lệnh snapshot status.

Để restore cluster từ backup này tại một thời điểm sau, trước tiên dừng service kube-apiserver, vì quá trình restore sẽ yêu cầu restart etcd cluster, và kube-apiserver phụ thuộc vào nó. Sau đó chạy lệnh etcdctl snapshot restore, chỉ định path tới file backup, chính là file snapshot.db. Khi etcd restore từ một backup, nó khởi tạo một cluster configuration mới và cấu hình các member của etcd như member mới của một cluster mới — nhằm ngăn một member mới vô tình join vào một cluster hiện có. Khi chạy lệnh này, một data directory mới được tạo, trong ví dụ tại vị trí /var/lib/etcd, từ backup. Sau đó cấu hình file cấu hình etcd để dùng data directory mới này, rồi reload service daemon và restart etcd service. Cuối cùng, khởi động lại service kube-apiserver. Cluster lúc này sẽ trở về trạng thái ban đầu.

Restore etcd từ snapshot — 5 bướcStopkube-apiserveretcdctlsnapshot restoreData dir mới(/var/lib/etcd)Restartetcd serviceRestartkube-apiserverCluster trở về đúng trạng thái tại thời điểm chụp snapshot

Một lưu ý nhanh: với mọi lệnh etcdctl, nhớ chỉ định các certificate file để authenticate — chỉ định endpoint tới etcd cluster, CA certificate, etcd server certificate, và key.

Vậy đã thấy hai lựa chọn: backup dùng etcd, và backup bằng cách query kube-apiserver. Cả hai đều có ưu và nhược điểm. Nếu dùng managed Kubernetes environment, đôi khi có thể sẽ không có quyền truy cập etcd cluster — trong trường hợp đó, backup bằng cách query kube-apiserver có lẽ là cách tốt hơn.


9. Làm việc với ETCDCTL và ETCDUTL

etcdctl là một command line client cho etcd. Trong toàn bộ các bài hands-on lab Kubernetes, ETCD key-value database được deploy dưới dạng static pod trên master. Version dùng là v3.

Để dùng etcdctl cho các tác vụ như backup, xác nhận nó đang chạy trên API version 3.x:

etcdctl version

Ví dụ output:

controlplane ~ ➜ etcdctl version
etcdctl version: 3.5.16
API version: 3.5

Backup ETCD — dùng etcdctl (Snapshot-based Backup). Để lấy snapshot từ một etcd server đang chạy:

ETCDCTL_API=3 etcdctl \
--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 \
snapshot save /backup/etcd-snapshot.db

Các option bắt buộc:

  • --endpoints trỏ tới etcd server (mặc định: localhost:2379).
  • --cacert path tới CA cert.
  • --cert path tới client cert.
  • --key path tới client key.

Backup file-level offline (không dùng snapshot). etcdutl không có subcommand backup — cách backup file-level offline thật sự là dừng etcd service rồi copy trực tiếp data directory:

sudo systemctl stop etcd
sudo cp -r /var/lib/etcd /backup/etcd-backup
sudo systemctl start etcd

Cách này copy nguyên vẹn backend database và WAL file (Write-Ahead Log — file mà etcd ghi lại mọi thay đổi vào đó trước khi áp dụng vào database chính, để nếu etcd crash giữa chừng, lúc khởi động lại nó replay đúng log này mà không mất dữ liệu vừa ghi) của etcd sang vị trí đích, nhưng bắt buộc etcd phải dừng trong lúc copy (khác với etcdctl snapshot save, vốn chụp snapshot được ngay cả khi etcd đang chạy).

Kiểm tra trạng thái snapshot. Có thể xem metadata của một snapshot file bằng:

etcdctl snapshot status /backup/etcd-snapshot.db \
--write-out=table

Lệnh này cho thấy các chi tiết như size, revision, hash, tổng số key, v.v. — hữu ích để xác nhận tính toàn vẹn của snapshot trước khi restore.

Restore ETCD — dùng etcdutl. Để restore một snapshot vào một data directory mới:

etcdutl snapshot restore /backup/etcd-snapshot.db \
--data-dir /var/lib/etcd-restored

Để dùng một backup file-level tạo bằng cách copy thủ công ở trên, chỉ cần copy nội dung backup trở lại /var/lib/etcd và restart etcd.

Ghi chú:

  • etcdctl snapshot save dùng để tạo snapshot .db từ etcd cluster đang chạy.
  • etcdctl snapshot status cung cấp thông tin metadata về file snapshot.
  • etcdutl snapshot restore dùng để restore một file snapshot .db.
  • Backup file-level (dừng etcd rồi cp -r data directory) là cách raw copy dữ liệu và WAL file của etcd — không phải một subcommand riêng của etcdutl, chỉ là thao tác filesystem thông thường trong lúc etcd không chạy.

10. Tip khi làm bài thi và Tài liệu tham khảo thêm

Tip cho kỳ thi: Trong kỳ thi, sẽ không biết những gì vừa làm là đúng hay sai, không như các practice test trong khoá học này. Phải tự verify công việc của mình. Ví dụ, nếu câu hỏi là tạo một pod với một image cụ thể, phải chạy lệnh kubectl describe pod để xác nhận pod được tạo đúng tên và đúng image.

Tài liệu tham khảo thêm (theo khoá học):


Nguồn tham khảo

Nguồn gốc: Khóa "Certified Kubernetes Administrator (CKA)" — phần "Cluster Maintenance" (Bảo trì Node: OS Upgrade, Drain, Cordon, Uncordon; Kubernetes Software Releases và Versioning; Quy trình Nâng cấp Cluster; Backup và Restore; Làm việc với ETCDCTL và ETCDUTL), nền tảng KodeKloud. Giảng viên: Mumshad Mannambeth.

Repo ghi chú, link tài liệu, và đáp án các practice question của toàn bộ khóa học: kodekloudhub/certified-kubernetes-administrator-course.

Fact-check:

  • Package repository chính thức để cài kubectl/kubeadm/kubeletpkgs.k8s.io (không phải packages.k8s.io) — repo cũ apt.kubernetes.io/yum.kubernetes.io đã freeze từ 2023-09-13, gỡ hẳn từ 2024-03-04 — 2026-09-13, Kubernetes blog: pkgs.k8s.io introduction
  • Từ kubelet v1.25 trở lên, độ lệch version cho phép so với kube-apiserver là tối đa 3 bậc (n-3), không còn là 2 bậc (n-2) như các phiên bản cũ hơn — 2026-09-13, Kubernetes: Version Skew Policy
  • etcdutl không có subcommand backup — các subcommand thật của etcdutldefrag, snapshot restore, snapshot status, hashkv, version, list-bucket, iterate-bucket, hash; backup file-level offline thực hiện bằng cách dừng etcd rồi copy trực tiếp data directory — 2026-09-13, etcd-io/etcd: etcdutl/README.md