COS, Node Bootstrap, Node Conditions và Auto-Repair
Vì sao chủ đề này quan trọng trong production
Đa số sự cố “cluster chập chờn” không bắt đầu từ API server mà từ node không còn hành vi dự đoán được: image pull chậm bất thường, kubelet mất heartbeat, disk đầy do log, PID cạn do fork storm, hoặc network plugin lỗi khiến node bị NetworkUnavailable. Nếu đội vận hành không có mental model rõ ràng từ OS → kubelet → node condition → auto-repair, bạn sẽ chỉ chữa triệu chứng và lặp lại cùng một incident.
Google khuyến nghị dùng node image được quản lý chuẩn (COS hoặc Ubuntu tùy use case) thay vì tùy biến nặng trên node để giảm drift và tăng tính lặp lại vận hành (Node images). Với Autopilot, COS containerd là mặc định; với Standard, bạn vẫn nên xem COS là baseline trừ khi có ràng buộc đặc biệt về driver/kernel module.
Internal model: từ COS đến trạng thái Ready
1) Container-Optimized OS (COS) không chỉ là “image nhẹ”
COS được thiết kế để chạy container an toàn với các đặc tính cốt lõi:
- Security hardening ở kernel/userland, giảm attack surface.
- Root filesystem immutable/read-only theo mô hình hạn chế thay đổi ngoài ý muốn.
- Verified boot và chain tin cậy khi khởi động.
- Chu kỳ cập nhật bảo mật được Google quản lý theo dòng COS release (COS overview, COS security).
Điểm vận hành quan trọng: immutable root khiến mọi “hotfix trực tiếp trên node” trở thành anti-pattern. Nếu bạn vá thủ công package trên node, thay đổi đó không phải contract bền vững và sẽ biến mất khi node được thay thế/repair.
2) Node bootstrap sequence trong GKE
Luồng khởi tạo điển hình của node pool mới:
- GKE tạo VM theo machine/image/disk cấu hình node pool.
- Runtime và kubelet khởi động.
- Kubelet đăng ký
Nodeobject với API server. - Node có thể mang startup taint hoặc chưa sẵn sàng scheduling cho đến khi các thành phần nền (CNI, kube-proxy hoặc dataplane agent, DNS path nội bộ) ổn định.
- Node chuyển
Ready=True, scheduler mới đặt pod thông thường lên node đó.
Kubernetes định nghĩa rõ kubelet chịu trách nhiệm cập nhật status/conditions theo heartbeat và kiểm tra cục bộ (Nodes architecture). Trong GKE, nếu bước đăng ký thất bại kéo dài, tài liệu troubleshooting node registration chỉ ra các nhóm nguyên nhân chính: lỗi mạng tới control plane, IAM/service account sai, hoặc bootstrap agent không hoàn tất (Troubleshoot node registration).
3) Node conditions là “giao diện hợp đồng” của sức khỏe node
Các condition cốt lõi bạn phải theo dõi:
ReadyDiskPressureMemoryPressurePIDPressureNetworkUnavailable
Đây là tín hiệu scheduler/controller dùng để ra quyết định placement và eviction (Node conditions).
Một insight quan trọng ở production: condition không phải metric tức thời. Nó là kết quả tổng hợp theo ngưỡng/thời gian quan sát của kubelet và có thể có độ trễ so với symptom trong ứng dụng. Vì vậy bạn cần quan sát đồng thời node condition + node metrics + event timeline.
Condition detection: kubelet probes, thresholds và eviction behavior
1) Cơ chế phát hiện áp lực tài nguyên
Kubelet đánh giá “node pressure” dựa trên tín hiệu memory, filesystem, PID và so với eviction thresholds. Khi vượt ngưỡng, kubelet kích hoạt eviction để bảo vệ node khỏi rơi vào trạng thái chết cứng (Node-pressure eviction).
Eviction là cơ chế tự vệ cấp node, không phải workload policy. Nếu design sai requests/limits hoặc density quá cao, kubelet có thể liên tục đuổi pod, tạo vòng lặp:
- Pod bị evict do pressure.
- Deployment tạo pod mới.
- Pod mới lại vào node đang áp lực.
- Eviction lặp lại → API churn + latency tăng toàn cluster.
2) Failure modes thường gặp
DiskPressure giả do image churn
- CI/CD deploy quá dày với image tag mới liên tục.
- Image garbage collection chạy không kịp.
- Node còn CPU/RAM nhưng hết dung lượng khả dụng cho runtime.
MemoryPressure do overcommit không kiểm soát
- Team đặt requests quá thấp để “nhét thêm pod”.
- Khi traffic tăng, node không đủ headroom cho system daemons.
- Kubelet buộc evict pod “dễ evict” trước, tạo outage cục bộ.
PIDPressure trong workload có nhiều process ngắn hạn
- Pattern fork-heavy hoặc sidecar lỗi gây process leak.
- Dù memory còn, node vẫn mất khả năng tạo process mới.
NetworkUnavailable kéo dài sau bootstrap
- CNI/dataplane agent chưa sẵn sàng hoặc lỗi policy/network path.
- Node treo ở trạng thái không thể nhận traffic ứng dụng đúng cách.
3) Trade-off khi tinh chỉnh thresholds
- Threshold quá bảo thủ: node evict sớm, giảm hiệu quả sử dụng tài nguyên.
- Threshold quá lỏng: node đụng “cliff” và sụp đột ngột, ảnh hưởng rộng.
Thiết kế đúng là theo tier workload: node pool cho latency-critical giữ headroom lớn hơn; node pool batch có thể đẩy utilization cao hơn nhưng phải chấp nhận eviction nhiều hơn.
GKE Node Auto-Repair: trigger, mechanism, retry logic
GKE cung cấp auto-repair để tự thay node không khỏe theo tiêu chí nền tảng. Theo tài liệu chính thức, trigger bao gồm tình huống node NotReady kéo dài, node không báo trạng thái, hoặc các trạng thái lỗi vận hành khác tùy chế độ cluster (Auto-repair nodes).
Cơ chế vận hành thực tế
Khi node bị xác định cần repair, GKE sẽ:
- Cordon + drain node (evict pod theo cơ chế disruption hợp lệ).
- Nếu drain không hoàn tất trong timeout, node có thể bị thay cưỡng bức.
- Tạo lại node thay thế trong node pool.
Chi tiết timeout drain (ví dụ cửa sổ khoảng một giờ cho một số tình huống) là điểm quan trọng để bạn thiết kế terminationGracePeriodSeconds, PDB, và shutdown hook không quá dài gây “kẹt nâng cấp/kẹt repair” (Auto-repair nodes).
Auto-repair không phải “thuốc thần”
Auto-repair chữa node hỏng, không chữa root cause ứng dụng. Nếu nguyên nhân là:
- image quá nặng khiến boot kéo dài,
- daemonset nội bộ làm đầy disk,
- sidecar memory leak,
thì node mới vẫn tái phát lỗi. Khi đó auto-repair chỉ làm symptom “nhảy vị trí” giữa các node.
Production architecture patterns
Pattern A: Baseline pool + Specialized pools
- Pool nền chạy COS, workload stateless phổ thông.
- Pool chuyên biệt cho workload nặng I/O hoặc memory.
- Mỗi pool có policy autoscaling, upgrade và SLO riêng.
Lợi ích: cô lập blast radius. Khi pool chuyên biệt có DiskPressure, pool nền vẫn giữ ổn định cho API quan trọng.
Pattern B: Canary node pool cho thay đổi runtime
Trước khi rollout thay đổi node image/kubelet config:
- Tạo pool canary nhỏ.
- Chuyển một phần workload đại diện qua nodeSelector/affinity.
- Theo dõi 24–72 giờ rồi mới mở rộng.
Pattern này bám nguyên tắc Operational Excellence: thay đổi nhỏ, đo được, rollback rõ ràng (Operational excellence).
Pattern C: Fault-domain theo zone + anti-affinity
Dù cluster regional, bạn vẫn cần ép workload trải đều zone để tránh “pool health xấu tại một zone” làm tụt quorum ứng dụng. Auto-repair chỉ có ý nghĩa nếu workload có nơi để chạy lại.
Real-world scenarios
Scenario 1: Node NotReady hàng loạt sau deploy agent bảo mật
Một DaemonSet agent mới tiêu tốn đột biến memory khi scan sâu filesystem. Trong 30 phút, nhiều node chuyển MemoryPressure=True, rồi NotReady. Auto-repair kích hoạt đồng loạt làm cluster churn.
Cách xử lý đúng:
- Ngừng rollout DaemonSet ngay tại pool bị ảnh hưởng.
- Tăng request/limit rõ cho agent và giới hạn concurrency.
- Tách pool chuyên cho workload cần agent này.
- Bật cảnh báo theo tỷ lệ node
MemoryPressurethay vì chờNotReady.
Scenario 2: DiskPressure do log + image garbage
Nhiều service ghi log local volume không giới hạn, cộng với tần suất deploy cao làm layer image tích tụ. Node vào DiskPressure, kubelet evict pod; app tưởng là “lỗi random”.
Cách xử lý đúng:
- Chuẩn hóa logging ra Cloud Logging thay vì giữ local quá lâu.
- Rà soát chu kỳ image pull và chiến lược tag.
- Nâng boot disk profile cho pool có mật độ pod cao.
Common mistakes / anti-patterns
SSH vào node để sửa tay rồi coi là fix xong
- Vì sao xảy ra: áp lực incident cần “chữa cháy”.
- Hệ quả: drift cấu hình, lần repair tiếp theo lỗi quay lại.
- Phòng tránh: mọi thay đổi phải đi qua node pool config/daemonset có version control.
Xem
Ready=Truelà đủ khỏe- Vì sao xảy ra: dashboard mặc định đơn giản.
- Hệ quả: bỏ qua pressure sớm, đến khi evict mới phát hiện.
- Phòng tránh: monitor đầy đủ tất cả conditions + eviction events.
Bật auto-repair nhưng không thiết kế drain-safe
- Vì sao xảy ra: hiểu sai rằng GKE sẽ luôn drain “êm”.
- Hệ quả: stuck drain, timeout, force replace, mất pod state.
- Phòng tránh: đồng bộ PDB, termination grace, preStop, và startupProbe.
Dồn quá nhiều workload dị biệt vào một pool
- Vì sao xảy ra: muốn đơn giản vận hành.
- Hệ quả: không tối ưu được threshold/profile theo từng loại workload.
- Phòng tránh: chia pool theo đặc tính tài nguyên và mức chịu rủi ro.
GCP-native implementation guidance
Quan sát nhanh tình trạng node
kubectl get nodes -o wide
kubectl describe node <node-name>
kubectl get events -A --sort-by=.lastTimestamp | grep -E "Evict|NodeNotReady|NodeReady|DiskPressure|MemoryPressure|PIDPressure"Bật auto-repair cho node pool (Standard)
gcloud container node-pools update <node-pool> \
--cluster=<cluster-name> \
--region=<region> \
--enable-autorepairKiểm tra cấu hình node image/pool
gcloud container node-pools describe <node-pool> \
--cluster=<cluster-name> \
--region=<region>Kết nối với Well-Architected và Architecture Framework
- Reliability: giảm single point of failure ở cấp node bằng auto-repair + phân tách pool + guardrail eviction (Reliability pillar).
- Operational Excellence: chuẩn hóa lifecycle node thành runbook lặp lại, giảm SSH/manual patching (Operational excellence pillar).
References
- GKE node images
- Container-Optimized OS overview
- Container-Optimized OS security overview
- GKE auto-repair nodes
- Troubleshoot node registration
- Kubernetes nodes
- Kubernetes node conditions
- Kubernetes node-pressure eviction
- Google Cloud Architecture Framework - Reliability
- Google Cloud Architecture Framework - Operational Excellence
Phụ lục chuyên sâu: runbook và mô hình quan sát cho Node Conditions
Ma trận tín hiệu cần theo dõi theo từng condition
Trong production, chỉ quan sát kubectl get nodes là không đủ. Nên xây một ma trận tín hiệu gồm 4 lớp:
- Control-plane signal: Node conditions, Node events, taints.
- Kubelet signal: eviction events, image GC logs, probe failures.
- Host signal: filesystem usage, inode usage, memory working set, PID usage.
- Workload signal: restart count, startup latency, request error rate.
Nếu một condition đổi trạng thái mà bạn chỉ có lớp 1, bạn sẽ không tách được “nguyên nhân tại node” và “hậu quả ở workload”.
Ví dụ với DiskPressure:
- Lớp 1 cho biết trạng thái có áp lực.
- Lớp 2 cho biết kubelet đã bắt đầu eviction chưa.
- Lớp 3 cho biết pressure đến từ image layers, logs hay
emptyDir. - Lớp 4 cho biết service nào bị ảnh hưởng nặng nhất.
Runbook điều tra NotReady theo 20 phút đầu
Phút 0–5: xác nhận phạm vi ảnh hưởng
- Bao nhiêu node bị
NotReady? - Tập trung ở một node pool hay nhiều pool?
- Tập trung ở một zone hay toàn vùng?
Nếu tập trung một zone, ưu tiên kiểm tra hạ tầng zone-level hoặc capacity event. Nếu tập trung một pool, khả năng cao do cấu hình/agent chung của pool.
Phút 5–10: xác định chuỗi nguyên nhân gần nhất
- Trước khi
NotReadycóMemoryPressure/DiskPressurekhông? - Có rollout daemonset hoặc thay đổi node config trong 1 giờ gần nhất không?
- Có nâng cấp node pool đang chạy không?
Phút 10–15: đánh giá tác động business
- Error rate tăng ở tier nào?
- Latency p95/p99 tăng ở API nào?
- Có thành phần stateful mất quorum không?
Phút 15–20: chọn biện pháp giảm thiểu
- Cô lập pool lỗi bằng cordon tạm nếu cần.
- Tăng tạm capacity ở pool khỏe.
- Tạm dừng rollout liên quan node/runtime.
Điểm mấu chốt: runbook phải ưu tiên giảm tác động trước khi truy tận gốc; root cause làm ngay sau khi hệ thống an toàn.
Kỹ thuật giảm false positive trong alerting node conditions
Nhiều đội tạo alert “bật tắt” theo condition đơn lẻ và gặp noise lớn. Cách tốt hơn:
- Alert mức cảnh báo khi condition xuất hiện ở 1–2 node nhưng chưa lan rộng.
- Alert mức nghiêm trọng khi tỷ lệ node bị condition vượt ngưỡng theo pool hoặc theo zone.
- Correlate với chỉ số workload (5xx, latency) để nâng ưu tiên đúng lúc.
Mẫu tư duy:
MemoryPressuređơn lẻ ở pool batch có thể chỉ là tín hiệu thông tin.MemoryPressure>10% node ở pool API critical phải vào chế độ incident.
Cách phân loại root cause để ngăn tái phát
Sau incident node, luôn phân loại root cause theo ba nhóm:
Configuration root cause
- Request/limit sai.
- PDB quá chặt.
- Kubelet thresholds không phù hợp.
Capacity root cause
- Node type thiếu headroom.
- Disk type/size không đủ cho cường độ pull/log.
- Thiếu capacity khi surge/repair.
Behavioral root cause
- Deploy patterns gây thác lũ (thundering herd).
- Workload leak memory/file descriptors/PIDs.
- Agent nền xung đột runtime.
Nếu sau postmortem bạn chỉ ghi “node lỗi ngẫu nhiên”, incident sẽ quay lại.
Thiết kế guardrails cho Auto-Repair
Auto-repair hữu ích khi đi kèm guardrails:
- Guardrail 1: giới hạn phạm vi rollout thay đổi hệ thống theo ring.
- Guardrail 2: cảnh báo sớm khi condition xấu tăng theo xu hướng.
- Guardrail 3: kiểm tra drain blockers định kỳ (PDB, pods đặc biệt).
- Guardrail 4: kiểm soát DaemonSet có đặc quyền cao qua quy trình review.
Mục tiêu là để auto-repair xử lý sự cố độc lập, không bị biến thành “máy khuếch đại lỗi cấu hình”.
Phân tích anti-pattern theo quy mô tổ chức
Ở tổ chức nhỏ, anti-pattern thường là thiếu tiêu chuẩn kỹ thuật. Ở tổ chức lớn, anti-pattern lại là tiêu chuẩn có nhưng không cưỡng chế.
Ví dụ:
- Có guideline không sửa tay node, nhưng vẫn cho phép SSH tự do khi có incident.
- Có chuẩn requests/limits, nhưng không có policy check ở CI admission.
- Có quy định monitoring, nhưng dashboard không tách theo node pool nên khó nhìn blast radius.
Giải pháp không chỉ là viết tài liệu, mà là biến chuẩn thành cơ chế bắt buộc:
- Policy enforcement.
- Automated checks.
- Runbook drill định kỳ.
Bài toán dữ liệu trạng thái tạm trên node
Nhiều workload dùng emptyDir như cache và giả định “mất cache thì chỉ chậm hơn chút”. Thực tế khi node repair hàng loạt:
- Cache miss đồng loạt tạo spike đến backend.
- Backend nghẽn, kéo theo timeout diện rộng.
- Autoscaler phản ứng muộn, hệ thống rơi vào vòng lặp retry.
Để tránh, cần:
- Thiết kế cache warmup có kiểm soát.
- Giới hạn tốc độ khởi tạo lại đồng thời.
- Có tầng cache trung gian bền hơn cho dữ liệu nóng quan trọng.
Sự khác biệt giữa tín hiệu node và tín hiệu pod
Một nhầm lẫn phổ biến là chẩn đoán incident thuần từ pod status. Nhưng pod status chỉ là hậu quả cuối cùng.
Ví dụ:
- Pod
CrashLoopBackOffcó thể do app bug, nhưng cũng có thể do node cạn disk khiến container runtime không ổn định. - Pod
Pendingcó thể do scheduler constraint, cũng có thể do node mới chưaReadyvì bootstrap kẹt.
Do đó dashboard production cần cho phép “nhảy ngược” từ pod về node rất nhanh.
Tối ưu tổ chức node pools để giảm incident coupling
Nguyên tắc:
- Không để workload critical và workload thử nghiệm chạy cùng pool.
- Không trộn workload có profile I/O quá khác nhau vào một pool.
- Tách pool platform agents khỏi pool business workloads nếu agent nặng.
Lý do: khi một profile workload gây pressure, bạn muốn ảnh hưởng chỉ nằm trong phạm vi hẹp nhất.
Checklist vận hành định kỳ cho chương này
Hàng tuần:
- Rà soát tỷ lệ node condition xấu theo pool.
- Kiểm tra top nguyên nhân eviction.
- Kiểm tra tốc độ node bootstrap trung vị/p95.
Hàng tháng:
- Diễn tập incident
NotReadytheo runbook 20 phút. - Đánh giá lại ngưỡng alert.
- Kiểm tra drift của daemonset hệ thống.
Hàng quý:
- Đánh giá lại chiến lược pool segmentation.
- Rà soát lại SLO và budget cho repair/upgrade disruptions.
- Cập nhật tài liệu theo phiên bản GKE đang dùng.
References bổ sung
FAQ thực chiến
Có nên tắt auto-repair để tránh node bị thay ngoài ý muốn?
Thông thường không nên. Tắt auto-repair chỉ hợp lý khi bạn đang điều tra một lỗi nền tảng nghiêm trọng và đã có biện pháp giám sát thủ công chặt chẽ trong thời gian ngắn. Về dài hạn, tắt auto-repair thường làm tăng MTTR vì node xấu tồn tại lâu hơn.
Vì sao node thỉnh thoảng Ready rồi lại NotReady liên tục?
Đây thường là dấu hiệu của hệ thống đang dao động quanh ngưỡng: tài nguyên thiếu nhẹ nhưng liên tục, agent nền lỗi ngắt quãng, hoặc network path không ổn định. Cần xem chuỗi sự kiện dài hơn thay vì chụp một thời điểm.
Có nên dùng script tự động SSH sửa node khi condition xấu?
Không nên trong kiến trúc chuẩn. Cách này tạo drift và khó audit. Thay vào đó hãy dùng thay node có kiểm soát (repair/upgrade) và quản lý cấu hình qua node pool/runtime config có versioning.
Khi nào cần tách thêm node pool mới thay vì tuning pool cũ?
Khi workload profile đã khác biệt rõ (I/O, memory, security, architecture) và tuning chung không thể tối ưu đồng thời. Tách pool giúp giới hạn blast radius và tăng khả năng điều phối thay đổi.