Sửa lỗi Kubernetes Node NotReady: Node node-1 status is now: NodeNotReady

intermediate☸️ Kubernetes2026-04-21| Kubernetes 1.24+, mọi bản phân phối Linux (Ubuntu 20.04/22.04, CentOS 7/8, RHEL), kubeadm hoặc managed clusters (EKS, GKE, AKS)

Error Message

Node node-1 status is now: NodeNotReady
#kubernetes#node#notready#kubelet#kubectl

Chuyện gì đã xảy ra

Bạn kiểm tra cluster và thấy các pod bị kẹt ở trạng thái Pending. Chạy kubectl get nodes cho thấy một hoặc nhiều node có trạng thái NotReady. Event log của control plane hiển thị:

Node node-1 status is now: NodeNotReady

Scheduler lập tức ngừng đặt pod mới lên node đó. Các pod đang chạy trên đó có thể bị evict tùy thuộc vào cấu hình tolerations — thường sau 5 phút theo mặc định. Đã đến lúc tìm nguyên nhân thực sự.

Triage nhanh — kiểm tra những gì trước tiên

SSH vào node bị ảnh hưởng trước khi làm bất cứ điều gì khác. Phần lớn nguyên nhân gốc rễ nằm trên chính node đó, không phải ở API server.

1. Kiểm tra trạng thái và điều kiện của node

kubectl get nodes
kubectl describe node node-1

Cuộn xuống phần Conditions trong kết quả describe. Bốn trường này cho bạn biết gần như mọi thứ:

  • Ready — phải là True. False hoặc Unknown có nghĩa là kubelet không giao tiếp được với control plane.
  • MemoryPressure / DiskPressure / PIDPressure — bất kỳ giá trị nào là True đều cho thấy node đang cạn kiệt tài nguyên.
  • NetworkUnavailable — chỉ ra sự cố với CNI plugin.

2. Kiểm tra trạng thái kubelet trên node

systemctl status kubelet
journalctl -u kubelet -n 100 --no-pager

Kubelet là agent báo cáo tình trạng node lên control plane. Khi nó crash hoặc dừng lại, node sẽ chuyển sang NotReady trong vòng 40 giây — đó là giá trị mặc định của node-monitor-grace-period. Journal hầu như luôn cho bạn biết chính xác điều gì đã xảy ra ngay trong 10 dòng đầu tiên.

Nguyên nhân thường gặp và cách khắc phục

Nguyên nhân 1: kubelet bị dừng hoặc crash

Chín trong mười trường hợp là do đây. Tiến trình kubelet chết lặng lẽ và không có gì khởi động lại nó.

# Khởi động lại kubelet
systemctl restart kubelet
systemctl enable kubelet

# Theo dõi node phục hồi
kubectl get nodes -w

Vẫn tiếp tục crash? Theo dõi log theo thời gian thực:

journalctl -u kubelet -f

Ba nguyên nhân phụ thường gặp là: /var/lib/kubelet/config.yaml bị cấu hình sai, chứng chỉ TLS hết hạn, hoặc cgroup driver không khớp. Cái cuối cùng hay gây nhầm lẫn — node chạy cgroupfs nhưng cluster được cấu hình cho systemd, hoặc ngược lại.

Kiểm tra sự không khớp như sau:

# Docker runtime
docker info | grep -i cgroup

# containerd runtime
containerd config dump | grep -i cgroup

# Kubelet kỳ vọng gì
cat /var/lib/kubelet/config.yaml | grep cgroupDriver

Nếu chúng khác nhau, hãy cập nhật /var/lib/kubelet/config.yaml để khớp với runtime, rồi khởi động lại kubelet.

Nguyên nhân 2: Disk pressure

Disk đầy nhanh hơn nhiều người nghĩ trên các node bận. Khi mức sử dụng vượt qua ngưỡng eviction — mặc định 85% — kubelet đặt DiskPressure=True và đánh dấu node là unschedulable.

# Trên node
df -h
du -sh /var/lib/docker/*      # Docker runtime
du -sh /var/lib/containerd/   # containerd runtime

# Tìm thông báo eviction
journalctl -u kubelet | grep -i evict

Container image và log cũ thường là thủ phạm. Dọn dẹp chúng nhanh chóng:

# Docker
docker system prune -af

# containerd
crictl rmi --prune

# Xóa bớt log journal cũ
journalctl --vacuum-time=3d

Nguyên nhân 3: Memory pressure hoặc OOM kill

# Kiểm tra các OOM kill gần đây
dmesg | grep -i oom
cat /proc/meminfo | grep -i available

Kernel OOM killer hoạt động rất nhanh — nó có thể terminate chính kubelet để thu hồi bộ nhớ. Khởi động lại kubelet sẽ đưa node trở lại, nhưng nếu không có resource limit cho các pod, điều tương tự sẽ xảy ra lại sau một giờ. Tìm xem cái gì đang chiếm nhiều bộ nhớ và thêm resources.limits.memory cho các pod đó.

Nguyên nhân 4: CNI plugin bị lỗi (NetworkUnavailable)

Điều kiện NetworkUnavailable=True chỉ thẳng vào tầng CNI — Flannel, Calico, Cilium, Weave, hoặc bất cứ thứ gì bạn đang dùng. Plugin bị crash hoặc mất trạng thái trên node cụ thể đó.

# Tìm CNI pod đang chạy trên node bị lỗi
kubectl get pods -n kube-system -o wide | grep -E 'flannel|calico|cilium|weave'

# Đọc log của nó
kubectl logs -n kube-system <cni-pod-on-node-1>

# Xác nhận CNI binary và config tồn tại trên node
ls /opt/cni/bin/
ls /etc/cni/net.d/

Xóa CNI pod để Kubernetes lên lịch lại từ đầu. Việc khởi tạo lại thường giải quyết được vấn đề:

kubectl delete pod -n kube-system <cni-pod-on-node-1>

Nguyên nhân 5: Clock skew hoặc chứng chỉ hết hạn

Xác thực TLS bị hỏng khi đồng hồ bị lệch. Độ lệch hơn 2 phút khiến API server từ chối hoàn toàn chứng chỉ của kubelet.

# So sánh thời gian trên node với thời gian thực tế
date
timedatectl status

# Đồng bộ lại ngay lập tức
chronyc makestep        # dùng cho chrony
ntpdate -u pool.ntp.org # dùng cho ntp

Chứng chỉ hết hạn lại là chuyện khác — nó phụ thuộc vào lịch. Chứng chỉ do kubeadm cấp sẽ hết hạn sau đúng một năm. Kiểm tra và gia hạn từ control plane:

# Xem ngày hết hạn của tất cả chứng chỉ
kubeadm certs check-expiration

# Gia hạn tất cả cùng lúc
kubeadm certs renew all
systemctl restart kubelet

Nguyên nhân 6: Node không thể kết nối từ control plane

API server giao tiếp với kubelet qua port 10250. Thay đổi firewall rule, security group bị cấu hình sai (thường gặp sau khi cập nhật hạ tầng cloud), hoặc node đơn giản là offline — tất cả đều cho ra triệu chứng NotReady như nhau.

# Từ control plane node, kiểm tra trực tiếp
curl -k https://<node-ip>:10250/healthz

# Kiểm tra iptables trên node
iptables -L -n | grep 10250

# Thay thế với firewalld
firewall-cmd --list-all

Xác nhận node đã trở lại

# Node phải hiển thị Ready
kubectl get nodes

# Kết quả mong đợi:
# NAME     STATUS   ROLES    AGE   VERSION
# node-1   Ready    <none>   5d    v1.28.0

# Xác nhận các conditions đã sạch
kubectl describe node node-1 | grep -A 10 Conditions

# Chạy test scheduling nhanh
kubectl run test-pod --image=nginx --restart=Never
kubectl get pod test-pod -o wide

# Dọn dẹp
kubectl delete pod test-pod

Node có bị cordon trong sự cố không? Đừng quên bước này:

kubectl uncordon node-1

Cordon và drain trước khi bảo trì

Đang nâng cấp kernel hoặc dọn dẹp disk? Luôn drain node trước — evict pod đúng cách tốt hơn nhiều so với để chúng bị kill giữa chừng khi đang xử lý request.

# Ngừng đặt pod mới lên đây
kubectl cordon node-1

# Evict các pod hiện có một cách graceful
kubectl drain node-1 --ignore-daemonsets --delete-emptydir-data

# Thực hiện bảo trì...

# Đưa node trở lại vòng xoay
kubectl uncordon node-1

Làm gì khác đi lần sau

  • Cảnh báo khi disk ở 70%, không phải 85%. Đến lúc kubelet kích hoạt eviction ở 85%, bạn đã ở tình thế tồi tệ rồi. Cảnh báo ở 70% cho bạn khoảng đệm 15 điểm để dọn dẹp mà không cần incident trên production. DiskPressure làm nhiều người bất ngờ hơn bất kỳ nguyên nhân nào khác.
  • Bắt đầu từ kubelet log, không phải API server. Journal hầu như luôn chỉ ra đúng lỗi ngay trong 10 dòng đầu. Hãy vào đó trước.
  • Đồng bộ đồng hồ là bắt buộc. VM bị lệch giờ sau khi live migration trong môi trường cloud — đôi khi lệch đến vài phút. Chạy chrony hoặc ntpd và xem đó là hạ tầng thiết yếu, không phải tùy chọn.
  • Triển khai node-problem-detector. DaemonSet node-problem-detector đưa các kernel panic và runtime failure lên thành node conditions trước khi chúng leo thang thành NotReady. Cài đặt chỉ mất 2 phút với helm install node-problem-detector deliveryhero/node-problem-detector.
  • Theo dõi ngày hết hạn chứng chỉ trên lịch ops của bạn. Chứng chỉ kubeadm hết hạn sau một năm, vào một ngày cố định. Đặt nhắc nhở gia hạn ở tháng thứ 11 — coi đó là bất ngờ là điều hoàn toàn có thể tránh được.

Related Error Notes