Khi agent cần thời gian chạy dài, giữ kết nối streaming, dùng thư viện nặng, hoặc bạn muốn kiểm soát môi trường tuyệt đối — container là lựa chọn. Bài này chỉ cách đóng gói và vận hành agent bằng Docker + orchestrator.
Vì sao container hợp với agent
- Không giới hạn timeout cứng như serverless đồng bộ: worker chạy nền bao lâu tùy bạn.
- Giữ ấm sẵn: không cold start nạp model mỗi lần.
- Môi trường nhất quán: cùng một image chạy local, staging, prod — hết cảnh "trên máy tôi chạy được".
- Kết nối bền: hợp với WebSocket streaming hoặc long-poll queue.
Dockerfile gọn cho agent
FROM python:3.11-slim
WORKDIR /app
# Cài dependency trước để tận dụng cache layer
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
# Chạy bằng user không phải root
RUN useradd -m appuser
USER appuser
# Health check để orchestrator biết container còn sống
HEALTHCHECK --interval=30s --timeout=5s \
CMD python -c "import urllib.request; urllib.request.urlopen('http://localhost:8080/health')"
CMD ["python", "worker.py"]
Nguyên tắc: copy requirements trước để layer cài đặt được cache, build nhanh; chạy non-root cho an toàn; có HEALTHCHECK để tự phục hồi khi agent treo.
Hai kiểu chạy container
- Service kiểu web (nhận HTTP đồng bộ): giống serverless nhưng luôn ấm. Hợp streaming.
- Worker kiểu consumer: vòng lặp kéo job từ queue, xử lý, ack. Đây là mô hình chủ lực cho tác vụ dài (nối với Bài 4).
Cấu hình vận hành quan trọng
- Resource limits: đặt CPU/memory request và limit. Agent parse JSON lớn có thể ngốn RAM → tránh bị OOM-killed.
- Graceful shutdown: bắt tín hiệu
SIGTERM, ngừng nhận job mới, hoàn tất job đang chạy rồi mới thoát. Nếu không, agent bị giết giữa chừng khi scale-down. - Autoscaling theo độ sâu queue: scale số worker theo số job đang chờ, không chỉ theo CPU (agent chờ I/O nên CPU thấp mà vẫn tồn đọng job).
- Liveness vs readiness: readiness fail khi chưa nạp xong model để orchestrator chưa gửi traffic.
import signal, sys
_running = True
def _stop(signum, frame):
global _running
_running = False # ngừng nhận job mới, để vòng lặp thoát êm
signal.signal(signal.SIGTERM, _stop)
while _running:
job = queue.pull(timeout=5)
if job:
process(job) # job đang chạy được để chạy nốt
Khung tư duy: Serverless hay Container?
Cần streaming dài / model nặng / >15 phút / kiểm soát môi trường sâu?
-> Container
Traffic thưa, tác vụ ngắn, muốn về 0 chi phí lúc rảnh?
-> Serverless
Lượng lớn ổn định + tác vụ dài?
-> Container worker + Queue (kết hợp)
Các bước triển khai
- Viết Dockerfile multi-stage/slim, cache layer dependency, chạy non-root.
- Thêm endpoint
/healthvà HEALTHCHECK. - Cài đặt graceful shutdown bắt SIGTERM.
- Đặt resource request/limit dựa trên đo thực tế (không đoán).
- Cấu hình autoscaling theo độ sâu queue, đặt min replicas hợp lý.
- Test scale-down: đảm bảo không mất job đang chạy.
Sai lầm thường gặp
- Không xử lý SIGTERM: mỗi lần deploy hoặc scale-down làm rớt job đang chạy.
- Không đặt memory limit: một agent ngốn RAM có thể kéo sập cả node.
- Autoscale chỉ theo CPU: agent chờ I/O nên CPU thấp, queue tồn đọng mà không scale.
- Image khổng lồ: copy cả
.git, cache, model không cần → build chậm, deploy chậm. Dùng.dockerignore. - Chạy migration/khởi tạo nặng trong mỗi container: nên tách thành job khởi tạo riêng.
- Không có health check: agent treo mà orchestrator vẫn tưởng khỏe, gửi thêm traffic vào.
Học xong bài này rồi?
Tạo tài khoản miễn phí để lưu lại — lần sau vào là biết ngay đang dở ở đâu,
và học hết khóa thì có chứng chỉ.
Lưu tiến độ của tôi