Skip to content

Mastering Kubernetes Probes

👨‍🔧 Góc nhìn SRE

Module này được viết từ góc nhìn của Site Reliability Engineer (SRE) tại HPN. Mục tiêu: Giữ cho hệ thống luôn khỏe mạnhphản ứng nhanh với các sự cố.

🧟 Vấn Đề: "Zombie Pods"

Kịch bản thực tế

Bạn có một ứng dụng Java Spring Boot chạy trên Kubernetes. Mọi thứ đang hoạt động tốt cho đến khi...

text
[SRE On-Call Alert - 3:00 AM]
🚨 500 Errors spike to 30% on /api/orders endpoint
📊 Pod CPU: 5% (LOW)
📊 Pod Memory: Normal
📊 Pod Status: "Running" ✅

❓ CÁI GÌ ĐÃ XẢY RA?

Kubernetes nghĩ Pod đang "Running" vì:

  • Process ID (PID) vẫn tồn tại
  • Container không crash

Nhưng thực tế:

  • Thread pool bị Deadlock (khóa chéo)
  • Ứng dụng Frozen - không thể xử lý request
  • Users nhận được 500 Internal Server Error

Đây chính là hiện tượng "Zombie Pod" - container "sống" nhưng không làm được gì. Kubernetes không có cách nào biết được điều này... trừ khi bạn cấu hình Health Probes.


🔬 Giải Pháp: Bộ Ba Probe

Kubernetes cung cấp 3 loại Probe để kiểm tra sức khỏe container:

1️⃣ Liveness Probe: "Bạn còn sống không?"

💡 Câu hỏi cốt lõi

"Container của bạn có còn hoạt động không?"

  • Nếu KHÔNG → Kubernetes sẽ RESTART container
  • Use case: Phát hiện Deadlock, Memory Leak, Infinite Loop
yaml
apiVersion: v1
kind: Pod
metadata:
  name: java-app
spec:
  containers:
  - name: app
    image: myapp:1.0
    # 🔥 LIVENESS PROBE: Phát hiện Zombie
    livenessProbe:
      httpGet:
        path: /actuator/health/liveness
        port: 8080
      # ⏱️ Chờ 30s sau khi container start
      initialDelaySeconds: 30
      # ⏱️ Kiểm tra mỗi 10 giây
      periodSeconds: 10
      # ❌ Fail 3 lần liên tiếp → RESTART
      failureThreshold: 3
      # ⏱️ Timeout mỗi lần check: 5s
      timeoutSeconds: 5

Khi nào container được restart?

text
Time 0s:   Container starts
Time 30s:  First liveness check (initialDelaySeconds)
Time 40s:  Second check ✅ OK
Time 50s:  Third check ❌ FAIL (Thread deadlock)
Time 60s:  Fourth check ❌ FAIL
Time 70s:  Fifth check ❌ FAIL (3 failures → failureThreshold reached)

🔄 KUBELET RESTARTS CONTAINER

2️⃣ Readiness Probe: "Bạn sẵn sàng nhận traffic chưa?"

💡 Câu hỏi cốt lõi

"Container có thể xử lý request từ users không?"

  • Nếu KHÔNG → Kubernetes sẽ XÓA IP khỏi Service/LoadBalancer
  • Use case: Slow startup, Cache warming, Overload protection
yaml
spec:
  containers:
  - name: app
    image: myapp:1.0
    # 🛡️ READINESS PROBE: Kiểm soát traffic
    readinessProbe:
      httpGet:
        path: /actuator/health/readiness
        port: 8080
      initialDelaySeconds: 10
      periodSeconds: 5
      failureThreshold: 3

Sự khác biệt quan trọng với Liveness:

AspectLiveness ProbeReadiness Probe
Mục đíchContainer còn sống?Container sẵn sàng?
Hành động khi FAIL🔄 RESTART container🚫 CUT TRAFFIC (không restart)
Use caseDeadlock, crash loopSlow startup, temporary overload

Ví dụ thực tế: Cold Start

text
Pod khởi động → Cần 60s để load cache từ Redis

Không có Readiness Probe:
├── Time 0s: Pod "Running" → Nhận traffic ngay
├── Time 0-60s: Cache chưa sẵn sàng → 500 Errors!
└── User experience: BAD 😢

Có Readiness Probe:
├── Time 0s: Pod "Running" nhưng KHÔNG nhận traffic
├── Time 0-60s: Readiness check FAIL → Pod không trong Service
├── Time 60s: Cache loaded → Readiness check PASS
└── Time 61s: Pod được thêm vào Service → Nhận traffic
└── User experience: SMOOTH ✨

3️⃣ Startup Probe: "Bạn đã khởi tạo xong chưa?"

💡 Câu hỏi cốt lõi

"Container đã hoàn tất quá trình initialization chưa?"

  • Nếu THÀNH CÔNG → Bật Liveness & Readiness Probe
  • Use case: Legacy apps với startup time rất dài (5-10 phút)

Vấn đề với Legacy Applications:

Một số ứng dụng cũ cần nhiều phút để khởi động hoàn toàn:

  • Load large ML models
  • Connect to multiple databases
  • Warm up JIT compiler

Nếu cấu hình Liveness Probe với initialDelaySeconds: 30 nhưng app cần 5 phút để start:

text
❌ THẢM HỌA: Liveness kill container trước khi app ready
   → Container restart → Cần 5 phút → Liveness kill → RESTART LOOP!

Giải pháp: Startup Probe

yaml
spec:
  containers:
  - name: legacy-java-app
    image: legacy:1.0
    # 🐢 STARTUP PROBE: Cho apps chậm
    startupProbe:
      httpGet:
        path: /healthz
        port: 8080
      # Cho phép tối đa 300s (5 phút) để app khởi động
      # failureThreshold * periodSeconds = 30 * 10 = 300s
      failureThreshold: 30
      periodSeconds: 10
    
    # Liveness KHÔNG chạy cho đến khi Startup PASS
    livenessProbe:
      httpGet:
        path: /healthz
        port: 8080
      periodSeconds: 10
      failureThreshold: 3

Flow hoạt động:

text
1. Container start
2. Startup Probe chạy (Liveness & Readiness bị DISABLE)
3. Startup Probe PASS sau 4 phút → OK
4. Liveness & Readiness Probe được ENABLE
5. Hệ thống hoạt động bình thường

🏭 HPN Standard Configuration

📋 QUY CHUẨN HPN

Tất cả ứng dụng Production tại HPN BẮT BUỘC phải có Health Probes config đúng chuẩn.

Các tham số quan trọng

Tham sốMô tảHPN Recommended
initialDelaySecondsThời gian chờ trước lần check đầu tiên30-60s cho apps thông thường
periodSecondsKhoảng cách giữa các lần check10s (đủ nhạy, không quá aggressive)
timeoutSecondsTimeout cho mỗi lần probe5s (fail fast)
failureThresholdSố lần fail liên tiếp trước khi action3 (tránh false positive)
successThresholdSố lần success để coi là recovered1 (mặc định)

Template chuẩn cho Java/Spring Boot

yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: hpn-java-service
spec:
  replicas: 3
  template:
    spec:
      containers:
      - name: app
        image: hpn-registry/java-service:1.2.3
        ports:
        - containerPort: 8080
        
        # 📊 Resources (REQUIRED - Module 2)
        resources:
          requests:
            memory: "512Mi"
            cpu: "500m"
          limits:
            memory: "1Gi"
            cpu: "1000m"
        
        # 🔬 STARTUP PROBE (cho apps cần warm-up)
        startupProbe:
          httpGet:
            path: /actuator/health/liveness
            port: 8080
          failureThreshold: 30
          periodSeconds: 10
        
        # 💓 LIVENESS PROBE
        livenessProbe:
          httpGet:
            path: /actuator/health/liveness
            port: 8080
          initialDelaySeconds: 0  # Startup probe đã handle
          periodSeconds: 10
          failureThreshold: 3
          timeoutSeconds: 5
        
        # 🛡️ READINESS PROBE  
        readinessProbe:
          httpGet:
            path: /actuator/health/readiness
            port: 8080
          initialDelaySeconds: 10
          periodSeconds: 5
          failureThreshold: 3
          timeoutSeconds: 5

☠️ Lỗi Phổ Biến: Probe Check External Dependencies

🚨 SAI LẦM NGHIÊM TRỌNG NHẤT

ĐỪNG BAO GIỜ để Liveness Probe kiểm tra external dependencies như Database, Redis, hay External APIs!

Kịch bản thảm họa

Cấu hình SAI:

yaml
# ❌ WRONG: Liveness check database connection
livenessProbe:
  httpGet:
    path: /health  # Endpoint này check DB connection
    port: 8080

Điều gì xảy ra khi Database gặp sự cố?

Tại sao điều này sai?

Database down 30sVới cấu hình SAINên xảy ra
Kết quảALL PODS RESTARTPods vẫn chạy, trả lỗi "DB unavailable"
Recovery time2-5 phút (cold start)0s (instant khi DB recover)
User impact100% downtimeGraceful degradation

Cấu hình ĐÚNG

yaml
# ✅ CORRECT: Liveness chỉ check internal state
livenessProbe:
  httpGet:
    # Endpoint này KHÔNG check DB
    # Chỉ kiểm tra: App có respond được không?
    path: /actuator/health/liveness
    port: 8080

# ✅ Readiness CÓ THỂ check dependency (optional)
readinessProbe:
  httpGet:
    # Endpoint này có thể check DB, Redis, etc.
    # Nếu DB down → Pod không nhận traffic
    # Nhưng KHÔNG BỊ RESTART!
    path: /actuator/health/readiness
    port: 8080

Spring Boot Actuator ví dụ:

java
// application.yml
management:
  endpoint:
    health:
      probes:
        enabled: true
      group:
        liveness:
          include: livenessState  # Internal only!
        readiness:
          include: readinessState, db, redis  # External deps OK here

🎯 Probe Types: HTTP vs TCP vs Exec

Kubernetes hỗ trợ 3 cách để thực hiện health check:

HTTP GET (Phổ biến nhất)

yaml
livenessProbe:
  httpGet:
    path: /healthz
    port: 8080
    httpHeaders:  # Optional: Custom headers
    - name: X-Custom-Header
      value: Probe
  • Ưu điểm: Kiểm tra chi tiết, flexible
  • ⚠️ Yêu cầu: App phải có HTTP endpoint

TCP Socket

yaml
livenessProbe:
  tcpSocket:
    port: 3306  # MySQL port
  • Ưu điểm: Đơn giản, không cần code
  • ⚠️ Hạn chế: Chỉ biết port mở, không biết app healthy

Exec Command

yaml
livenessProbe:
  exec:
    command:
    - cat
    - /tmp/healthy
  • Ưu điểm: Linh hoạt, chạy bất kỳ script nào
  • ⚠️ Hạn chế: Tốn resource, slow hơn HTTP

📊 Tổng Kết

ProbeCâu hỏiAction khi FAILCheck gì?
LivenessCòn sống?🔄 RESTARTInternal state ONLY
ReadinessSẵn sàng?🚫 Remove from LBCó thể check dependencies
StartupĐã init xong?⏳ Keep waitingOne-time initialization

⚠️ GHI NHỚ

  1. LUÔN cấu hình initialDelaySeconds phù hợp với thời gian boot của app
  2. KHÔNG để Liveness check external dependencies
  3. SỬ DỤNG Startup Probe cho legacy apps chậm
  4. READINESS là bạn của graceful degradation

🔗 Liên kết