容器化部署
Docker/K8s 训练与推理。
30 分钟
容器化部署
这一课你将能做到
- 写出生产级 Dockerfile:层缓存友好的依赖安装、非 root 用户、健康检查、小体积
- 用 docker compose 一键拉起本地 ML 栈(推理服务 + MLflow),服务按别名动态加载模型
- 编写 K8s Deployment + Service + HPA + 探针清单,理解资源配额与弹性伸缩
为什么要学
「在我机器上能跑」是部署事故的头号台词。scikit-learn 版本差一个小版本、CUDA 驱动不匹配、系统缺一个 C 库,都可能让服务在别人的机器上起不来。容器把「代码 + 依赖 + 系统库」打包成不可变镜像,任何环境运行结果一致。
人话:模型文件只是「程序」,镜像才是「可以发货的整机」。CI/CD 发布的产物、K8s 调度的单位、回滚的粒度,全都是镜像。本课把第 5 课的超时预测服务装进集装箱。
先建立图像
Dockerfile(配方)──docker build──▶ 镜像(不可变)──docker run──▶ 容器(进程)
镜像分层(自下而上,越常变的越靠后):
┌──────────────────────────┐ ◀─ 变化最频繁:src/ 代码
│ COPY src/ . │
├──────────────────────────┤ ◀─ 偶尔变:requirements.txt
│ RUN pip install -r ... │
├──────────────────────────┤ ◀─ 几乎不变:系统基础
│ FROM python:3.11-slim │
└──────────────────────────┘
层可复用缓存:基础层没变就不重装依赖,build 秒级完成
K8s 视角:Deployment(期望副本数)→ Pod(容器)→ Service(稳定入口)→ HPA(按负载扩缩)
跟着做
步骤 1:写生产级 Dockerfile
# Dockerfile
FROM python:3.11-slim
WORKDIR /app
# 依赖层在前:代码改动不会触发重装依赖
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY src/ src/
# 安全:不用 root 跑服务
RUN useradd -m appuser
USER appuser
EXPOSE 8000
HEALTHCHECK --interval=30s --timeout=3s --retries=3 \
CMD python -c "import urllib.request as u; u.urlopen('http://127.0.0.1:8000/health')"
CMD ["uvicorn", "src.serve:app", "--host", "0.0.0.0", "--port", "8000", "--workers", "2"]
配套 .dockerignore,防止把垃圾打进构建上下文:
# .dockerignore
data/
models/
.venv/
.git/
mlruns/
mlflow.db
__pycache__/
构建并运行:
docker build -t timeout-api:v1 .
docker run -d --name timeout-api -p 8000:8000 \
-e MLFLOW_TRACKING_URI=http://host.docker.internal:5000 \
timeout-api:v1
curl http://127.0.0.1:8000/health
curl -X POST "http://127.0.0.1:8000/predict?code_lines=180&loop_depth=3&lang_java=1&problem_rank=4"
步骤 2:compose 拉起本地 ML 栈
# docker-compose.yml
services:
mlflow:
image: ghcr.io/mlflow/mlflow:v2.17.2
command: >
mlflow server --host 0.0.0.0 --port 5000
--backend-store-uri sqlite:///mlflow.db
--artifacts-destination /artifacts
ports: ["5000:5000"]
volumes: ["./mlartifacts:/artifacts"]
api:
build: .
ports: ["8000:8000"]
environment:
MLFLOW_TRACKING_URI: http://mlflow:5000
depends_on: [mlflow]