0

Lab 3 - Productionize Todo Application

Series: Kubernetes từ Zero đến Production


Tình huống thực tế

Sau khi hoàn thành Lab 2, hệ thống Todo đã được deploy thành công.

Kiến trúc hiện tại:

Browser
   │
Ingress
   │
Frontend
   │
Backend
   │
PostgreSQL

Team bắt đầu mở hệ thống cho người dùng nội bộ sử dụng.

Mọi thứ đều ổn...

  • Cho đến một ngày backend bị treo. Người dùng không thể tạo Todo mới.
  • Một tuần sau, bạn cần deploy phiên bản mới.
  • Trong quá trình cập nhật, toàn bộ hệ thống bị gián đoạn khoảng 30 giây.
  • Lần khác nữa, backend tiêu tốn quá nhiều RAM khiến các Pod khác cũng bị ảnh hưởng.

Đây là những vấn đề rất phổ biến khi đưa ứng dụng lên production.

Trong bài lab này, chúng ta sẽ giải quyết chúng bằng các tính năng sẵn có của Kubernetes.


Mục tiêu

Sau khi hoàn thành bài lab, bạn sẽ biết cách:

  • Thêm Health Check cho ứng dụng
  • Cấu hình readinessProbe
  • Cấu hình livenessProbe
  • Giới hạn CPU và RAM của Pod
  • Thực hiện Rolling Update
  • Quan sát quá trình cập nhật không downtime

Kiến trúc sau khi Productionize

                  User
                    │
                 Ingress
                    │
            +-------+-------+
            │               │
        Frontend       Backend (3 Pods)
                            │
                        PostgreSQL

Mỗi Backend Pod sẽ:

  • Có Health Check
  • Có Resource Requests
  • Có Resource Limits
  • Có khả năng Rolling Update

Chuẩn bị

Tiếp tục sử dụng cluster từ Lab 2.

Kiểm tra trạng thái:

kubectl get all -n todo-app

Đảm bảo:

  • Frontend Running
  • Backend Running
  • PostgreSQL Running

Phần 1. Thêm Spring Boot Actuator

Đầu tiên, backend cần cung cấp API để Kubernetes kiểm tra sức khỏe.

Thêm dependency:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-actuator</artifactId>
</dependency>

Sau đó cấu hình:

management.endpoints.web.exposure.include=health
management.endpoint.health.show-details=always

Khởi động ứng dụng và kiểm tra:

curl http://localhost:8080/actuator/health

Kết quả:

{
  "status": "UP"
}

Đây chính là endpoint mà Kubernetes sẽ sử dụng để xác định ứng dụng còn hoạt động hay không.


Phần 2. Readiness Probe

Readiness Probe trả lời câu hỏi:

"Ứng dụng đã sẵn sàng nhận request chưa?"

Nếu câu trả lời là chưa, Kubernetes sẽ không gửi traffic đến Pod.

Thêm vào Deployment:

readinessProbe:
  httpGet:
    path: /actuator/health
    port: 8080
  initialDelaySeconds: 10
  periodSeconds: 5

Ý nghĩa:

  • Đợi 10 giây sau khi Pod khởi động.
  • Sau đó cứ mỗi 5 giây kiểm tra một lần.

Nếu Probe thất bại:

User
↓
Service
↓
❌ Pod chưa Ready

Traffic sẽ tự động chuyển sang các Pod khác.


Phần 3. Liveness Probe

Liveness Probe trả lời câu hỏi:

"Ứng dụng còn sống không?"

Nếu backend bị deadlock hoặc treo nhưng process vẫn tồn tại, Kubernetes sẽ tự khởi động lại Pod.

Ví dụ:

livenessProbe:
  httpGet:
    path: /actuator/health
    port: 8080
  initialDelaySeconds: 30
  periodSeconds: 10

Nếu Probe liên tục thất bại:

 Liveness Failed
        │
   Restart Pod
        │
Application chạy lại

Đây là cơ chế tự phục hồi rất quan trọng trong Kubernetes.


Phần 4. Resource Requests và Limits

Nếu không giới hạn tài nguyên, một Pod có thể sử dụng quá nhiều CPU hoặc RAM và ảnh hưởng đến toàn bộ Node.

Cấu hình cho Backend:

resources:
  requests:
    cpu: "500m"
    memory: "512Mi"
  limits:
    cpu: "1"
    memory: "1Gi"

Ý nghĩa:

Requests

Lượng tài nguyên tối thiểu Kubernetes đảm bảo cho Pod.

  • CPU: 500m (0.5 CPU)
  • RAM: 512Mi

Scheduler sẽ chỉ đặt Pod lên Node có đủ tài nguyên.

Limits

Giới hạn tối đa Pod được phép sử dụng.

  • CPU tối đa: 1 Core
  • RAM tối đa: 1Gi

Nếu vượt quá RAM:

  • Container có thể bị OOMKilled.

Nếu vượt quá CPU:

  • CPU sẽ bị giới hạn (throttling).

Kiểm tra:

kubectl describe pod <pod-name>

Bạn sẽ thấy:

Limits:
  cpu: 1
  memory: 1Gi

Requests:
  cpu: 500m
  memory: 512Mi

Phần 5. Rolling Update

Giả sử bạn đã build phiên bản mới:

todo-api:v2

Cập nhật image:

kubectl set image deployment/todo-backend \
backend=todo-api:v2 \
-n todo-app

Quan sát:

kubectl rollout status deployment/todo-backend -n todo-app

Hoặc:

kubectl get pods -w -n todo-app

Bạn sẽ thấy:

Old Pod 1   Running
Old Pod 2   Running
Old Pod 3   Running
        │
New Pod 1 Creating
        │
  New Pod Ready
        │
Old Pod 1 Terminating
        │
New Pod 2 Creating
        │
...

Kubernetes không xóa toàn bộ Pod cũ cùng lúc.

Thay vào đó, Pod mới chỉ bắt đầu nhận traffic khi đã vượt qua Readiness Probe.

Nhờ vậy, người dùng gần như không nhận thấy quá trình cập nhật.


Phần 6. Kiểm tra lịch sử Deployment

Xem lịch sử:

kubectl rollout history deployment/todo-backend -n todo-app

Kiểm tra trạng thái:

kubectl rollout status deployment/todo-backend -n todo-app

Nếu cập nhật gặp lỗi, bạn có thể quay lại phiên bản trước:

kubectl rollout undo deployment/todo-backend -n todo-app

Rollback là một trong những tính năng mạnh mẽ giúp giảm rủi ro khi triển khai phiên bản mới.


Phần 7. Kiểm tra Resource

Xem tài nguyên Pod:

kubectl top pods -n todo-app

Xem tài nguyên Node:

kubectl top nodes

Lưu ý: metrics-server cần được cài đặt và bật để các lệnh kubectl top hoạt động.

So sánh mức sử dụng thực tế với Requests và Limits để điều chỉnh cấu hình phù hợp.


Thử tạo lỗi

Tình huống 1: Health Check sai

Đổi đường dẫn:

path: /health

Thay vì:

path: /actuator/health

Quan sát:

kubectl describe pod <pod-name>

Bạn sẽ thấy các sự kiện Probe thất bại và Pod liên tục bị đánh dấu là Not Ready hoặc bị khởi động lại.


Tình huống 2: Thiếu tài nguyên

Giảm Memory Limit xuống:

memory: 128Mi

Nếu ứng dụng cần nhiều RAM hơn, Pod có thể bị:

OOMKilled

Kiểm tra:

kubectl describe pod <pod-name>

Dọn dẹp

Nếu không còn sử dụng cluster:

minikube stop

Hoặc tiếp tục giữ nguyên để thực hiện Lab 4.


Những gì bạn đã học

Sau bài lab này, bạn đã biết:

✅ Health Check với Spring Boot Actuator

✅ Readiness Probe

✅ Liveness Probe

✅ Resource Requests

✅ Resource Limits

✅ Rolling Update

✅ Rollback Deployment

✅ Theo dõi tài nguyên với kubectl top

✅ Debug các lỗi liên quan đến Probe và tài nguyên


Bài học rút ra

Một ứng dụng chạy được chưa đồng nghĩa với việc sẵn sàng cho production.

Muốn hệ thống ổn định, bạn cần đảm bảo:

  • Kubernetes chỉ gửi traffic đến các Pod đã sẵn sàng.
  • Pod bị treo sẽ được tự động khởi động lại.
  • Mỗi Pod có giới hạn tài nguyên rõ ràng để tránh ảnh hưởng lẫn nhau.
  • Việc cập nhật phiên bản mới diễn ra từng bước, không gây downtime cho người dùng.

Đó chính là nền tảng của một hệ thống có khả năng vận hành ổn định trong môi trường thực tế.

Ở bài lab tiếp theo, chúng ta sẽ tiếp tục mở rộng hệ thống Todo theo kiến trúc Microservices, nơi nhiều dịch vụ cùng phối hợp để tạo thành một ứng dụng hoàn chỉnh.


All rights reserved

Viblo
Hãy đăng ký một tài khoản Viblo để nhận được nhiều bài viết thú vị hơn.
Đăng kí