Xây dựng Docker Image cho Inference Service
Bước đầu tiên là đóng gói mã nguồn inference và artifact mô hình đã được huấn luyện vào một Docker image. Chúng ta sẽ sử dụng Python làm runtime, thư viện mlflow để tải model và flask để tạo API endpoint.
Mục đích là tạo một image nhẹ, chỉ chứa những gì cần thiết để chạy inference, giảm thiểu bề mặt tấn công và tăng tốc độ khởi động container trên Kubernetes.
Tạo file Dockerfile tại thư mục gốc của dự án (cùng cấp với inference.py).
FROM python:3.9-slim
WORKDIR /app
# Cài đặt các gói hệ thống cần thiết cho MLflow và Flask
RUN apt-get update && apt-get install -y \
gcc \
&& rm -rf /var/lib/apt/lists/*
# Copy code source vào container
COPY inference.py .
COPY requirements.txt .
# Cài đặt thư viện Python
RUN pip install --no-cache-dir -r requirements.txt
# Lưu trữ model sẽ được mount từ ConfigMap hoặc Volume sau này
RUN mkdir -p /app/model
# Mở cổng 8000 cho Flask
EXPOSE 8000
CMD ["python", "inference.py"]
Kết quả mong đợi: File Dockerfile được tạo sẵn sàng để build image.
Tiếp theo, tạo file requirements.txt để định nghĩa các thư viện phụ thuộc.
mlflow==2.9.1
flask==3.0.0
gunicorn==21.2.0
scikit-learn==1.3.2
numpy==1.24.3
Kết quả mong đợi: File requirements.txt liệt kê đầy đủ các gói cần thiết cho service inference.
Build Docker image với tag tên dự án và phiên bản cụ thể (ví dụ: ai-inference:v1).
docker build -t my-registry/ai-inference:v1 .
Kết quả mong đợi: Docker CLI hiển thị quá trình build thành công và image mới xuất hiện trong danh sách docker images.
Verify bằng cách chạy container cục bộ để đảm bảo code khởi động không lỗi.
docker run -p 8000:8000 my-registry/ai-inference:v1
Kết quả mong đợi: Container chạy, Flask lắng nghe cổng 8000 và hiển thị log Running on http://127.0.0.1:8000 (hoặc tương tự). Dùng curl http://localhost:8000/health (nếu có) để kiểm tra.
Chuẩn bị Kubernetes Manifests
Để Kubernetes biết cách chạy container, chúng ta cần định nghĩa các tài nguyên: ConfigMap để chứa mô hình, Deployment để quản lý pod, và Service để expose ra ngoài.
Tạo thư mục k8s để chứa tất cả các file cấu hình YAML.
mkdir -p k8s
Đầu tiên, tạo ConfigMap để lưu trữ model artifact. Trong môi trường production, model thường được lưu ở S3/GCS và tải về, nhưng ở đây để đơn giản hóa deployment, ta sẽ giả định model đã được tải về local và mount vào ConfigMap.
Tạo file k8s/configmap.yaml. Lưu ý: Dữ liệu trong data sẽ được base64 encode, nhưng ở đây ta dùng --from-file để Kubernetes tự động encode.
apiVersion: v1
kind: ConfigMap
metadata:
name: ai-model-config
namespace: default
data:
# Giả định thư mục model local của bạn là ./models/trained_model
model: |
# Nội dung model sẽ được mount vào /app/model tại đây
# Trong thực tế, hãy dùng lệnh: kubectl create configmap ai-model-config --from-file=./models/trained_model -n default
# Để đơn giản tutorial, ta sẽ mount volume sau khi model đã có sẵn
model_path: "/app/model"
Kết quả mong đợi: File configmap.yaml được tạo. Lưu ý: Trong thực tế, bạn sẽ tạo ConfigMap chứa file model thật bằng lệnh kubectl create configmap ai-model-config --from-file=./path/to/model -n default trước khi apply deployment.
Tiếp theo, tạo Deployment để quản lý các Pod chạy inference service. Đây là phần quan trọng nhất để tối ưu resource.
Tạo file k8s/deployment.yaml.
apiVersion: apps/v1
kind: Deployment
metadata:
name: ai-inference-deployment
namespace: default
labels:
app: ai-inference
spec:
replicas: 2
selector:
matchLabels:
app: ai-inference
template:
metadata:
labels:
app: ai-inference
spec:
containers:
- name: inference
image: my-registry/ai-inference:v1
imagePullPolicy: Always
ports:
- containerPort: 8000
name: http
# Tối ưu hóa resource cho inference
resources:
requests:
cpu: "500m"
memory: "1Gi"
limits:
cpu: "1000m"
memory: "2Gi"
volumeMounts:
- name: model-storage
mountPath: /app/model
# Health checks để K8s biết pod có sống không
livenessProbe:
httpGet:
path: /health
port: 8000
initialDelaySeconds: 10
periodSeconds: 10
readinessProbe:
httpGet:
path: /health
port: 8000
initialDelaySeconds: 5
periodSeconds: 5
volumes:
- name: model-storage
configMap:
name: ai-model-config
Kết quả mong đợi: File deployment.yaml được tạo với cấu hình rõ ràng về số lượng replica, resource request/limits và health checks.
Tạo file Service để expose Pod ra bên ngoài cluster hoặc nội bộ cluster.
Tạo file k8s/service.yaml.
apiVersion: v1
kind: Service
metadata:
name: ai-inference-service
namespace: default
spec:
selector:
app: ai-inference
ports:
- protocol: TCP
port: 80
targetPort: 8000
name: http
type: ClusterIP
Kết quả mong đợi: File service.yaml được tạo, ánh xạ cổng 80 của Service sang cổng 8000 của Container.
Triển khai lên Kubernetes Cluster
Bây giờ chúng ta sẽ áp dụng các manifest đã tạo lên cluster Kubernetes đang chạy.
Đầu tiên, đảm bảo bạn đã tạo ConfigMap chứa file model thật (nếu chưa làm ở bước trước).
kubectl create configmap ai-model-config --from-file=./path/to/your/model_artifacts -n default
Kết quả mong đợi: Kubernetes trả về configmap/ai-model-config created.
Apply toàn bộ các tài nguyên Deployment và Service.
kubectl apply -f k8s/deployment.yaml -f k8s/service.yaml
Kết quả mong đợi: Kubernetes trả về deployment.apps/ai-inference-deployment configured và service/ai-inference-service configured.
Verify trạng thái của Deployment và Pod.
kubectl get deployment ai-inference-deployment
kubectl get pods -l app=ai-inference
Kết quả mong đợi:
- Deployment hiển thị READY: 2/2.
- Pods hiển thị trạng thái Running với RESTARTS: 0 (sau khi ổn định).
Verify trạng thái của Service.
kubectl get service ai-inference-service
Kết quả mong đợi: Service hiển thị ClusterIP (ví dụ: 10.96.x.x) và cổng 80->8000/TCP.
Test khả năng phản hồi của service từ bên trong cluster (nếu có pod khác) hoặc từ local nếu đã expose (dùng port-forward).
kubectl port-forward svc/ai-inference-service 8080:80
Kết quả mong đợi: Terminal hiển thị Forwarding from 127.0.0.1:8080 -> 8000.
Trong một terminal khác, gọi API inference.
curl -X POST http://localhost:8080/predict -H "Content-Type: application/json" -d '{"data": [1, 2, 3, 4, 5]}'
Kết quả mong đợi: Nhận lại JSON response chứa kết quả dự đoán từ mô hình AI.
Tối ưu hóa Resource và Scaling
Để đảm bảo hệ thống hoạt động ổn định và không gây ảnh hưởng đến các workload khác, cần điều chỉnh Resource Request/Limits phù hợp với đặc thù của mô hình AI.
Công thức cơ bản:
- requests: Lượng tài nguyên tối thiểu K8s cần để schedule pod. Nếu không đủ, pod sẽ không chạy.
- limits: Giới hạn tối đa container được dùng. Nếu vượt quá, container sẽ bị OOMKilled (với RAM) hoặc throttled (với CPU).
Đối với mô hình Python/Scikit-Learn nhẹ:
- CPU Request: 500m (0.5 core) thường đủ cho 1 request đơn.
- Memory Request: 1Gi để load model vào RAM.
Đối với mô hình Deep Learning (PyTorch/TensorFlow):
- Memory Request có thể lên 4Gi - 16Gi tùy model.
- Cần xem xét GPU nếu có.
Để kiểm tra mức sử dụng tài nguyên thực tế của Pod đang chạy.
kubectl top pods -l app=ai-inference
Kết quả mong đợi: Hiển thị cột CPU(cores) và MEMORY(bytes) đang sử dụng thực tế.
Nếu CPU usage thường xuyên > 80% của limit, hãy tăng limits.cpu trong deployment.yaml lên 2000m (2 core).
Nếu Memory usage > 90% của limit, hãy tăng limits.memory để tránh bị OOMKilled.
Cập nhật lại Deployment sau khi thay đổi config.
kubectl apply -f k8s/deployment.yaml
Kết quả mong đợi: Kubernetes thực hiện rolling update, các Pod cũ bị terminate và Pod mới với resource cao hơn được tạo ra.
Để tự động mở rộng số lượng Pod khi tải tăng (Horizontal Pod Autoscaler - HPA).
Tạo file k8s/hpa.yaml.
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: ai-inference-hpa
namespace: default
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: ai-inference-deployment
minReplicas: 2
maxReplicas: 10
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 70
Kết quả mong đợi: File HPA được tạo, thiết lập ngưỡng tự động scale khi CPU trung bình > 70%.
Apply HPA.
kubectl apply -f k8s/hpa.yaml
Kết quả mong đợi: horizontalpodautoscaler.autoscaling/ai-inference-hpa created.
Verify HPA đang hoạt động.
kubectl get hpa ai-inference-hpa -w
Kết quả mong đợi: Thấy cột REPLICAS thay đổi nếu tải CPU tăng, và CPU% hiển thị giá trị hiện tại.
Đ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 6: Triển khai mô hình AI lên Kubernetes
Phần 7: Tự động hóa quy trình CI/CD cho DataOps »