1. Cấu hình Horizontal Pod Autoscaler (HPA) cho service inference
Mục tiêu là tự động tăng/giảm số lượng pod khi lượng request đến service inference thay đổi, đảm bảo latency thấp khi cao điểm và tiết kiệm tài nguyên khi ít request.
Bước đầu tiên là thiết lập Metric Server để Kubernetes đọc được CPU/Memory usage của các pod. Nếu chưa có, cần cài đặt metric-server.
kubectl apply -f https://github.com/kubernetes-sigs/metrics-server/releases/latest/download/components.yaml
Kiểm tra metric-server đang hoạt động và trả về dữ liệu CPU/Memory.
kubectl top nodes
Kết quả mong đợi: Xuất hiện bảng danh sách các node với cột CPU (core) và Memory (Gi) có giá trị số thực tế, không phải 0.
Định nghĩa Resource Request và Limit trong Deployment của service inference. HPA cần biết giới hạn tài nguyên (Limit) để tính toán tỷ lệ sử dụng.
Tạo file cấu hình deployment cho inference service với đường dẫn: config/inference-deployment.yaml.
apiVersion: apps/v1
kind: Deployment
metadata:
name: ai-inference-service
labels:
app: ai-inference
spec:
replicas: 1
selector:
matchLabels:
app: ai-inference
template:
metadata:
labels:
app: ai-inference
spec:
containers:
- name: inference
image: your-registry/ai-model:latest
resources:
requests:
cpu: "250m"
memory: "512Mi"
limits:
cpu: "1000m"
memory: "1Gi"
ports:
- containerPort: 8080
Deploy cấu hình này lên cluster. HPA sẽ dựa vào Limit (1000m CPU) để tính toán tỷ lệ sử dụng.
kubectl apply -f config/inference-deployment.yaml
Kết quả mong đợi: Deployment được tạo thành công với 1 replica.
Tạo Horizontal Pod Autoscaler (HPA) để tự động scale dựa trên CPU usage. Cấu hình target utilization percentage là 70%.
Tạo file cấu hình HPA với đường dẫn: config/inference-hpa.yaml.
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: ai-inference-hpa
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: ai-inference-service
minReplicas: 2
maxReplicas: 10
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 70
Áp dụng file HPA vào cluster. Kubernetes sẽ bắt đầu giám sát CPU usage của các pod thuộc deployment này.
kubectl apply -f config/inference-hpa.yaml
Kiểm tra trạng thái HPA để xác nhận nó đã liên kết với deployment và đang thu thập metrics.
kubectl get hpa ai-inference-hpa
Kết quả mong đợi: Cột TARGET hiện giá trị CPU usage (ví dụ: 45% hoặc 0% nếu chưa có traffic), REPLICAS hiện số lượng pod hiện tại (bắt đầu từ minReplicas là 2).
Cách verify kết quả mở rộng (Scaling Test)
Để kiểm tra HPA hoạt động thực tế, cần tạo load giả lập để đẩy CPU usage vượt quá 70%.
Sử dụng công cụ stress để tạo load vào service. Giả sử service đang chạy tại port 8080.
kubectl run -it --rm load-test --image=busybox --restart=Never -- /bin/sh -c "while true; do wget -q -O /dev/null http://ai-inference-service:8080/predict; done"
Chạy lệnh này trong terminal, sau đó quan sát số lượng pod tăng lên sau khoảng 1-2 phút.
kubectl get pods -l app=ai-inference -w
Kết quả mong đợi: Khi CPU usage vượt 70%, số lượng pod sẽ tăng từ 2 lên 3, 4... đến khi CPU usage giảm xuống dưới ngưỡng. Khi tắt load-test, pod sẽ giảm dần về mức minReplicas (2).
2. Quản lý Secret và Credential an toàn trong Kubernetes
Mục tiêu là tách biệt thông tin nhạy cảm (API key, Database password, MLflow token) khỏi code source và config file thông thường, sử dụng cơ chế Kubernetes Secrets.
Tuyệt đối không hardcode secret trong Docker image hoặc file YAML. Sử dụng kubectl hoặc công cụ mã hóa như Sealed Secrets (trong bài này dùng phương thức chuẩn của K8s để đơn giản hóa tutorial).
Tạo file chứa các secret cần thiết. Sử dụng format base64 để encode giá trị trước khi đưa vào YAML.
Tạo file: config/secrets.yaml.
apiVersion: v1
kind: Secret
metadata:
name: ai-platform-secrets
namespace: dataops-prod
type: Opaque
stringData:
MLFLOW_TRACKING_URI: https://mlflow.dataops.example.com
AWS_ACCESS_KEY_ID: "AKIAIOSFODNN7EXAMPLE"
AWS_SECRET_ACCESS_KEY: "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY"
DB_PASSWORD: "super_secure_password_123"
DVC_STORAGE_TOKEN: "dvc_token_xyz_999"
Sử dụng stringData thay vì data để Kubernetes tự động base64 encode cho bạn, tránh lỗi encode thủ công.
Apply secret vào cluster. Lưu ý: Secret này sẽ được lưu trong etcd, cần đảm bảo cluster đã bật encryption at rest cho secrets trong production.
kubectl apply -f config/secrets.yaml
Kiểm tra secret đã được tạo thành công.
kubectl get secret ai-platform-secrets -o yaml
Kết quả mong đợi: Xuất hiện nội dung secret với các trường đã được encode base64.
Tích hợp Secret vào Deployment của service inference. Mount secret dưới dạng biến môi trường (Environment Variable) để ứng dụng đọc.
Cập nhật file: config/inference-deployment.yaml (bổ sung phần envFrom hoặc env).
apiVersion: apps/v1
kind: Deployment
metadata:
name: ai-inference-service
labels:
app: ai-inference
spec:
replicas: 1
selector:
matchLabels:
app: ai-inference
template:
metadata:
labels:
app: ai-inference
spec:
containers:
- name: inference
image: your-registry/ai-model:latest
resources:
requests:
cpu: "250m"
memory: "512Mi"
limits:
cpu: "1000m"
memory: "1Gi"
ports:
- containerPort: 8080
envFrom:
- secretRef:
name: ai-platform-secrets
Deploy lại deployment đã cập nhật.
kubectl apply -f config/inference-deployment.yaml
Xác minh rằng pod mới khởi động với đúng các biến môi trường từ secret.
kubectl exec -it -- env | grep MLFLOW
Kết quả mong đợi: Xuất hiện biến môi trường MLFLOW_TRACKING_URI với giá trị đúng, không hiển thị plaintext trong file config YAML.
Cách verify bảo mật
Đảm bảo không ai có thể đọc được secret nếu không có quyền.
kubectl get secret ai-platform-secrets -o jsonpath='{.data.AWS_SECRET_ACCESS_KEY}' | base64 -d
Kết quả mong đợi: Nếu user hiện tại không có quyền, lệnh sẽ báo lỗi "Forbidden". Nếu có quyền, sẽ hiện ra giá trị plaintext sau khi decode.
3. Tách biệt môi trường Dev, Stage và Prod cho pipeline
Mục tiêu là cô lập các môi trường để tránh sự cố ở môi trường Dev làm ảnh hưởng đến Prod, đồng thời kiểm soát phiên bản mô hình và dữ liệu khác nhau cho từng stage.
Sử dụng Kubernetes Namespace để phân tách tài nguyên logic. Mỗi namespace sẽ có deployment, service, secret và config riêng.
Tạo 3 namespace: dev, stage, prod.
kubectl create namespace dev
kubectl create namespace stage
kubectl create namespace prod
Kết quả mong đợi: 3 namespace được tạo thành công.
Cấu hình Context trong kubeconfig để dễ dàng chuyển đổi giữa các môi trường khi chạy lệnh.
kubectl config set-context dev-context --namespace=dev
kubectl config set-context stage-context --namespace=stage
kubectl config set-context prod-context --namespace=prod
Chuyển đổi sang môi trường dev để test.
kubectl config use-context dev-context
Kiểm tra namespace hiện tại.
kubectl config view --minify | grep namespace
Kết quả mong đợi: Namespace hiện tại hiển thị là "dev".
Sử dụng ConfigMap để quản lý cấu hình khác nhau cho từng môi trường (ví dụ: URL MLflow, Storage path, Model Version).
Tạo file: config/configmap-dev.yaml.
apiVersion: v1
kind: ConfigMap
metadata:
name: ai-config
namespace: dev
data:
MLFLOW_TRACKING_URI: "http://mlflow-dev:5000"
DVC_REMOTE: "s3://bucket-dev/data"
MODEL_VERSION: "v1.0.0-alpha"
Tạo file: config/configmap-prod.yaml.
apiVersion: v1
kind: ConfigMap
metadata:
name: ai-config
namespace: prod
data:
MLFLOW_TRACKING_URI: "https://mlflow-prod.dataops.example.com"
DVC_REMOTE: "s3://bucket-prod/data"
MODEL_VERSION: "v1.0.0-stable"
Deploy ConfigMap vào namespace tương ứng.
kubectl apply -f config/configmap-dev.yaml -n dev
kubectl apply -f config/configmap-prod.yaml -n prod
Kết quả mong đợi: ConfigMap được tạo trong đúng namespace với giá trị khác nhau.
Trong Deployment, tham chiếu đến ConfigMap và Secret theo namespace hiện tại. Kubernetes tự động tìm kiếm trong cùng namespace nếu không chỉ định.
Cập nhật Deployment (giả sử file chung, nhưng deploy vào namespace khác nhau).
apiVersion: apps/v1
kind: Deployment
metadata:
name: ai-inference-service
namespace: prod
labels:
app: ai-inference
spec:
replicas: 3
selector:
matchLabels:
app: ai-inference
template:
metadata:
labels:
app: ai-inference
spec:
containers:
- name: inference
image: your-registry/ai-model:latest
envFrom:
- secretRef:
name: ai-platform-secrets
- configMapRef:
name: ai-config
Deploy vào namespace prod.
kubectl apply -f config/inference-deployment.yaml -n prod
Kiểm tra xem pod trong prod có đọc đúng config của prod không.
kubectl get pods -n prod -l app=ai-inference -o jsonpath='{.items[0].metadata.name}' && kubectl exec -it -n prod $(kubectl get pods -n prod -l app=ai-inference -o jsonpath='{.items[0].metadata.name}') -- env | grep MODEL_VERSION
Kết quả mong đợi: Biến MODEL_VERSION trong pod prod hiển thị "v1.0.0-stable", trong khi pod dev (nếu deploy) sẽ hiển thị "v1.0.0-alpha".
Cách verify sự cô lập
Đảm bảo xóa pod trong dev không ảnh hưởng đến prod.
kubectl delete pods --all -n dev
Kiểm tra số lượng pod trong prod vẫn giữ nguyên.
kubectl get pods -n prod
Kết quả mong đợi: Pod trong namespace prod vẫn đang chạy bình thường (Running), không bị xóa.
4. Tối ưu chi phí lưu trữ artifact và compute
Mục tiêu là giảm chi phí lưu trữ dữ liệu (Data/Model artifacts) trên cloud storage và giảm chi phí tính toán (Compute) khi không có request.
Chiến lược cho Storage: Sử dụng Lifecycle Policy trên Object Storage (S3/GCS/Azure Blob) để tự động chuyển artifact cũ sang lớp lưu trữ giá rẻ hơn (Glacier/Archive) hoặc xóa tự động.
Cấu hình Lifecycle rule cho bucket S3 lưu artifact của DVC/MLflow. Giả sử bucket tên là ai-mlflow-artifacts.
aws s3api put-bucket-lifecycle-configuration \
--bucket ai-mlflow-artifacts \
--lifecycle-configuration '{
"Rules": [
{
"ID": "TransitionToIA",
"Status": "Enabled",
"Filter": {"Prefix": "models/"},
"Transitions": [
{"Days": 30, "StorageClass": "STANDARD_IA"}
]
},
{
"ID": "ExpireOldArtifacts",
"Status": "Enabled",
"Filter": {"Prefix": "models/"},
"Expiration": {"Days": 365}
}
]
}'
Lệnh này chuyển artifact mô hình sang lớp STANDARD_IA sau 30 ngày và xóa hoàn toàn sau 1 năm.
Kết quả mong đợi: Không có lỗi trả về, lifecycle rule được áp dụng cho bucket.
Chiến lược cho Compute: Sử dụng Cluster Autoscaler hoặc KEDA (Kubernetes Event-driven Autoscaling) để scale về 0 khi không có traffic, kết hợp với HPA đã cấu hình ở phần 1.
Cấu hình HPA với minReplicas: 0 nếu sử dụng KEDA, hoặc kết hợp với Cluster Autoscaler để xóa node khi pod scale về 0.
Để đơn giản, chúng ta cập nhật HPA hiện tại cho phép scale về 0 (chỉ hoạt động nếu cluster có cơ chế scale down node, ví dụ: AWS EKS + Cluster Autoscaler).
Cập nhật file: config/inference-hpa.yaml.
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: ai-inference-hpa
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: ai-inference-service
minReplicas: 0
maxReplicas: 10
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 70
Deploy lại HPA với minReplicas là 0.
kubectl apply -f config/inference-hpa.yaml
Để kích hoạt scale về 0, cần đảm bảo không có traffic vào service. Nếu có LoadBalancer, có thể tắt nó tạm thời để test.
Kiểm tra số lượng pod sau khi không có traffic trong 5 phút.
kubectl get hpa ai-inference-hpa -w
Kết quả mong đợi: Cột REPLICAS giảm xuống 0. Các node chứa pod này sẽ được Cluster Autoscaler loại bỏ sau một khoảng thời gian (thường là 10-15 phút) nếu không còn pod nào khác.
Thêm chiến lược Cleanup cho artifact trong MLflow. Sử dụng API của MLflow để xóa model version cũ không được sử dụng.
Tạo script Python để chạy định kỳ (CronJob) xóa model version cũ.
#!/usr/bin/env python3
import mlflow
import time
tracking_uri = "https://mlflow-prod.dataops.example.com"
mlflow.set_tracking_uri(tracking_uri)
client = mlflow.tracking.MlflowClient()
# Lấy danh sách model
models = client.search_model_versions("name='my-ai-model'")
# Xóa các version không phải là latest (giả định chỉ giữ 2 version gần nhất)
versions_to_delete = [m.version for m in models][2:]
for version in versions_to_delete:
print(f"Deleting version: {version}")
# Lưu ý: MLflow không có API trực tiếp để xóa artifact file,
# cần logic tùy chỉnh để xóa folder trong S3 thông qua boto3
# Ở đây chỉ demo logic lấy version
Deploy script này dưới dạng CronJob trong Kubernetes để chạy mỗi ngày.
apiVersion: batch/v1
kind: CronJob
metadata:
name: cleanup-old-models
namespace: prod
spec:
schedule: "0 2 * * *"
jobTemplate:
spec:
template:
spec:
containers:
- name: cleanup
image: your-registry/cleanup-script:latest
envFrom:
- secretRef:
name: ai-platform-secrets
restartPolicy: OnFailure
Deploy CronJob.
kubectl apply -f config/cleanup-cronjob.yaml
Kiểm tra lịch chạy của CronJob.
kubectl get cronjob cleanup-old-models -n prod
Kết quả mong đợi: CronJob được tạo và sẽ chạy vào lúc 2:00 sáng mỗi ngày để dọn dẹp artifact cũ, giảm dung lượng lưu trữ.
Cách verify tối ưu chi phí
Kiểm tra dung lượng bucket S3 sau khi chạy lifecycle policy.
aws s3api list-object-versions --bucket ai-mlflow-artifacts --query 'Versions[].{Key:Key,StorageClass:StorageClass,Size:Size}' --output table
Kết quả mong đợi: Các file cũ có StorageClass là "STANDARD_IA" hoặc "GLACIER", không còn "STANDARD".
Kiểm tra số lượng pod và node khi không có traffic.
kubectl get pods -n prod
kubectl get nodes
Kết quả mong đợi: Số pod về 0, số node giảm xuống (nếu cluster autoscaler hoạt động).
Điều hướng series:
Mục lục: Series: Xây dựng nền tảng DataOps với DVC, MLflow và Kubernetes cho vòng đời AI
« Phần 8: Giám sát và ghi log hệ thống DataOps
Phần 9: Chiến lược mở rộng (Scaling) và bảo mật nâng cao »