Bỏ qua để đến nội dung
Knowledge Hub

Kubernetes probes: startup, readiness và liveness xử lý ba trạng thái khác nhau Cơ bản

Thời gian đọc ước tính: 8 phút

Một API cần 40 giây nạp dữ liệu khi khởi động. Kubernetes gọi /health sau vài giây, thấy lỗi.

  1. Nếu /health cũng là liveness probe, container bị restart trước khi kịp khởi tạo, rồi lặp lại mãi.
  2. Sửa bằng cách cho /health trả 200 ngay thì Pod nhận traffic khi chưa mở kết nối database và trả 500 cho người dùng.
  3. Cuối cùng, database gián đoạn vài giây kéo mọi Pod vào vòng restart, và database hồi phục thì gặp tải khởi động của cả đội Pod cùng lúc.

Ba tình huống này là ba câu hỏi khác nhau, nên có ba probe:

Probe Câu hỏi Khi fail
Startup Khởi tạo xong chưa? Kill container, áp dụng restart policy
Readiness Nhận traffic được chưa? Rút Pod khỏi EndpointSlice, không restart
Liveness Process có kẹt không hồi phục được không? Restart container sau đủ ngưỡng

Hỏi một câu: restart container này có sửa được lỗi không?

  • Có (deadlock, event loop kẹt, process hỏng nội bộ) → liveness.
  • Không, nhưng Pod chưa/không phục vụ được (đang nạp, mất kết nối) → readiness.
  • Không và không ảnh hưởng chức năng chính → không probe nào.
Sự cố Probe fail Vì sao
Handler deadlock, event loop kẹt Liveness Chỉ restart mới thoát
Đang nạp index/cache lúc khởi động Startup (rồi readiness) Chờ, đừng restart
Connection pool của Pod này hỏng, Pod khác vẫn tốt Readiness Rút riêng Pod này, nó tự hồi phục
Database dùng chung chết Cẩn thận, xem dưới Restart vô ích; fail readiness cả đội = không còn endpoint
Dependency phụ (email, gợi ý sản phẩm) lỗi Không probe nào Chỉ làm giảm chức năng phụ

Dependency dùng chung: coi chừng rút cả đội Pod

Phần tiêu đề “Dependency dùng chung: coi chừng rút cả đội Pod”

Kubernetes gợi ý readiness có thể kiểm tra các backend bắt buộc. Nhưng nếu database chung chết và readiness của mọi Pod đều gọi vào nó, mọi Pod cùng not ready, Service hết endpoint và người dùng nhận lỗi từ load balancer. Thường tệ hơn một API trả lỗi có kiểm soát hoặc phục vụ dữ liệu cache.

Nguyên tắc: readiness kiểm tra những gì chính Pod này cần và có thể khác với Pod khác (đã khởi tạo, pool còn kết nối, queue nội bộ không đầy). Với dependency dùng chung, ưu tiên degraded mode, circuit breaker hoặc timeout hợp lý ở tầng request, và alert theo SLO thay vì để probe quyết định.

Liveness thì không bao giờ gọi dependency ngoài. Tài liệu Kubernetes cảnh báo liveness cấu hình sai gây cascading failure: restart dưới tải cao, request client lỗi, và tải dồn sang các Pod còn lại.

Kubelet kiểm tra Pod, Service chỉ gửi traffic khi readiness đạt
Kubelet kiểm tra Pod, Service chỉ gửi traffic khi readiness đạtBước 1/5: Container khởi động. Startup probe chưa thành công nên liveness/readiness chưa bắt đầu kiểm tra.kubeletPodServicestartup
kubelet → Podstartup
Bước 1/5

Container khởi động. Startup probe chưa thành công nên liveness/readiness chưa bắt đầu kiểm tra.

Mỗi giai đoạn, từng probe có trạng thái riêng:

Trạng thái từng probe qua vòng đời Pod
Trạng thái từng probe qua vòng đời PodBước 1/5: Đang khởi động: chỉ startup probe chạy. Liveness và readiness chờ đến khi startup thành công.giai đoạn của Podđang thửFailchưa chạychưa chạyStartupkhởi tạo xong chưa?Readinessnhận traffic được chưa?Livenesscó cần restart không?
Bước 1/5

Đang khởi động: chỉ startup probe chạy. Liveness và readiness chờ đến khi startup thành công.

Điểm cần nhớ từ timeline:

  • Có startup probe thì liveness và readiness chưa chạy cho đến khi nó pass. Sau đó nó không chạy lại.
  • Readiness chạy suốt vòng đời Pod, nên Pod có thể ra/vào endpoint nhiều lần mà không restart.
  • Liveness không chờ readiness; hai probe không phụ thuộc nhau.

Cả hai đều trì hoãn liveness.

  • initialDelaySeconds là hằng số: đặt 60 giây thì app khởi động trong 5 giây vẫn chờ 60 giây.
  • Startup probe thử mỗi periodSeconds và nhường chỗ cho liveness ngay khi app sẵn sàng; cửa sổ tối đa là failureThreshold × periodSeconds (ví dụ 30 × 10 = 300 giây trong tài liệu Kubernetes).

Với app khởi động chậm hoặc thay đổi thời gian khởi động, dùng startup probe.

Trường Ý nghĩa Mặc định
periodSeconds Chu kỳ gọi probe 10
timeoutSeconds Thời gian chờ mỗi lần 1
failureThreshold Số lần fail liên tiếp để coi là fail 3
successThreshold Số lần pass liên tiếp để coi là pass lại 1

successThreshold lớn hơn 1 chỉ cho phép với readiness (liveness và startup bắt buộc bằng 1). Dùng nó để Pod không vào/ra endpoint liên tục khi dependency chập chờn.

startupProbe:
httpGet: { path: /health/startup, port: 3000 }
periodSeconds: 5
failureThreshold: 24 # cửa sổ khoảng 120 giây
readinessProbe:
httpGet: { path: /health/ready, port: 3000 }
periodSeconds: 5
timeoutSeconds: 2
successThreshold: 2 # pass 2 lần liên tiếp mới nhận lại traffic
livenessProbe:
httpGet: { path: /health/live, port: 3000 }
periodSeconds: 10
failureThreshold: 3

/health/live chỉ trả lời “process còn xử lý request không”, không gọi database. Với service gRPC, kubelet gọi trực tiếp gRPC health check (ổn định từ Kubernetes v1.27):

livenessProbe:
grpc:
port: 9090 # server phải implement gRPC Health Checking Protocol
periodSeconds: 10

Probe gRPC chạy trên IP của Pod, mặc định không dùng TLS, và mọi lỗi đều tính là fail.

Readiness không phải cơ chế drain. Khi Pod bị xoá, endpoint của nó được cập nhật với ready = false bất kể probe, nên không cần readiness probe chỉ để drain. Nhưng việc cập nhật này lan không tức thời, nên vẫn cần preStop, xử lý SIGTERM và grace period; xem SIGTERM khi deploy.

Probe Dùng khi Có thể bỏ khi
Startup Khởi động chậm hoặc không ổn định (nạp index, warm cache, migration nhẹ) App sẵn sàng trong vài giây
Readiness Pod nhận traffic qua Service Workload không nhận traffic (worker thuần kéo từ queue)
Liveness Có kiểu lỗi kẹt mà process không tự thoát Process crash khi lỗi: restart policy đã xử lý

Demo mô phỏng 5 trạng thái, in ba boolean cho mỗi trạng thái (khớp timeline ở trên):

Terminal window
npx --prefix examples ts-node examples/src/k8s-probes/probe-demo.ts

Ở dependency outage kỳ vọng readiness: false, liveness: true; ở process stuck thì liveness: false. Demo chỉ mô phỏng quyết định của endpoint, không có kubelet, ngưỡng hay EndpointSlice.

Để kiểm chứng thật, thử trên cluster test:

  • Gây lỗi dependency: kubectl get endpointslice đổi nhưng restart count không tăng.
  • Gây kẹt process: kubectl describe pod ghi event liveness fail rồi restart.

Tách ba tín hiệu

  • Startup cho khởi động chậm mà vẫn giữ liveness nghiêm sau đó.
  • Readiness rút Pod khỏi traffic mà không restart.
  • Liveness hồi phục process kẹt không tự thoát.

Giá phải trả và rủi ro

  • Endpoint health sai gây nhận traffic quá sớm hoặc restart storm.
  • Probe kiểm tra dependency quá sâu/đắt thành nguồn tải và lan lỗi.
  • Không probe nào thay graceful shutdown, timeout, retry hay metrics lỗi nghiệp vụ.
  1. Ba endpoint tách biệt: /startup, /ready, /live; mỗi cái rẻ và có giới hạn thời gian.
  2. Liveness không gọi database, cache hay service khác.
  3. Readiness chỉ kiểm tra thứ riêng của Pod; có kế hoạch degraded mode cho dependency chung.
  4. Startup probe có cửa sổ đo từ thời gian khởi động thật (p99), không copy manifest mẫu.
  5. successThreshold ở readiness đủ để tránh flapping; failureThreshold ở liveness đủ để qua GC pause.
  6. terminationGracePeriodSeconds, preStop và xử lý SIGTERM đã cấu hình theo bài graceful shutdown.
  7. Có alert cho restart count tăng và cho số endpoint sẵn sàng về 0.
  8. Đã thử lỗi dependency và process kẹt trên cluster test và xác nhận đúng probe fail.

Tự kiểm tra: (1) Vì sao liveness ping database có thể làm outage nặng hơn? (2) Startup probe hơn initialDelaySeconds ở điểm nào? (3) Database dùng chung chết, readiness nên làm gì? (4) Readiness fail có bảo đảm request đang chạy được hoàn tất không?