3. 环境准备:搭建模型部署所需的开发环境、容器化技术(Docker)和编排工具(Kubernetes)基础

在开始灰度发布与回滚实战之前,必须先搭建一套可复现、可扩展的模型部署环境。本章节聚焦于三个核心层次:开发环境(本地代码与模型管理)、容器化技术(Docker 镜像打包与运行时隔离)、编排工具(Kubernetes 集群调度与流量管理)。这三者构成了现代 AI 模型服务从“单机脚本”走向“生产级高可用系统”的基石。

3.1 开发环境:从 Python 虚拟环境到模型仓库

开发环境的核心目标是保证“代码-依赖-模型版本”三者的一致性。推荐使用 conda 或 venv 创建隔离的 Python 环境,并通过 requirements.txt 或 pyproject.toml 锁定依赖版本。对于模型文件,建议使用 MLflow 或 DVC 进行版本管理,避免将大文件直接放入 Git 仓库。

# 创建并激活虚拟环境(Python 3.10+)
conda create -n ai-deploy python=3.10 -y
conda activate ai-deploy

# 安装核心依赖(示例)
pip install torch==2.1.0 transformers==4.36.0 fastapi==0.109.0 uvicorn[standard]
pip install mlflow==2.9.0 dvc==3.30.0

# 导出依赖清单
pip freeze > requirements.txt
关键点:开发环境必须与生产环境保持“最小差异”。建议在开发阶段就使用 Docker 容器进行编码,而不是等到部署时才编写 Dockerfile。这样能提前暴露依赖冲突和系统库缺失问题。

3.2 Docker 基础:将模型服务封装为可移植镜像

Docker 将模型、代码、运行库和系统依赖打包成一个只读镜像。对于 AI 模型部署,镜像设计需关注三点:镜像体积(影响拉取速度)、启动速度(影响弹性伸缩)、非 root 运行(安全性)。

以下是一个典型的 FastAPI 模型服务 Dockerfile:

# 使用官方 Python 3.10-slim 作为基础镜像
FROM python:3.10-slim

# 设置工作目录和环境变量
WORKDIR /app
ENV PYTHONDONTWRITEBYTECODE=1 \
    PYTHONUNBUFFERED=1

# 安装系统依赖(如 libgomp 用于 PyTorch)
RUN apt-get update && apt-get install -y --no-install-recommends \
    libgomp1 \
    curl \
    && rm -rf /var/lib/apt/lists/*

# 复制依赖清单并安装 Python 包
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt

# 复制模型文件和代码
COPY model/ ./model/
COPY app/ ./app/

# 创建非 root 用户
RUN useradd -m -u 1000 appuser && chown -R appuser:appuser /app
USER appuser

# 暴露服务端口
EXPOSE 8000

# 启动命令
CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "8000"]

构建镜像并推送到私有仓库(如 Harbor 或 AWS ECR):

docker build -t my-registry.com/ai-team/sentiment-model:v1.0.0 .
docker push my-registry.com/ai-team/sentiment-model:v1.0.0
常见误区:不要将 __pycache__、.git 或本地测试数据复制进镜像。应使用 .dockerignore 文件排除这些内容,否则镜像会变得臃肿且可能泄露敏感信息。

3.3 Kubernetes 核心概念:Pod、Deployment 与 Service

Kubernetes(K8s)负责容器的编排与调度。对于模型部署,最核心的三个抽象是:

  • Pod:最小的调度单元,通常包含一个主容器(模型服务)和可选辅助容器(如日志收集器)。
  • Deployment:声明期望的副本数,支持滚动更新和回滚。灰度发布主要操作对象。
  • Service:提供稳定的虚拟 IP 和 DNS 名称,将流量负载均衡到后端的 Pod 集合。

下图展示了从 Docker 镜像到 Kubernetes 服务暴露的完整链路,以及灰度发布时流量切分的核心组件关系:

模型部署环境与灰度发布链路 开发环境 Python 虚拟环境 MLflow 模型注册 FastAPI 服务代码 requirements.txt 锁定 打包 Docker 镜像仓库 基础镜像 python:3.10 模型权重 + 代码层 标签: v1.0.0 / v1.1.0 不可变,可追溯 拉取 Kubernetes 集群 Service (ClusterIP) Deployment: v1.0.0 Pod A (replica=3) 承载 90% 流量 Deployment: v1.1.0 Pod B (replica=1) 承载 10% 流量 Ingress Controller (域名/TLS 终结) 外部客户端请求 灰度发布关键操作点 1. 创建新版本 Deployment 副本数=1,镜像标签 v1.1.0 2. 调整 Service selector 按权重分配流量(如 90/10) 3. 验证并逐步切流量 健康检查通过后扩大权重 回滚机制:kubectl rollout undo deployment/v1.1.0 自动将 Service selector 切回 v1.0.0,并终止异常 Pod

上图展示了从开发环境到 Kubernetes 集群的完整链路。其中 Service selector 是灰度发布的核心控制点——通过修改 selector 中匹配的 Pod 标签(如 version: v1.1.0),即可控制进入新版本的流量比例。

3.4 方法流程:本地验证 → 镜像构建 → 集群部署

标准化的部署流程能显著降低人为失误。推荐遵循以下步骤:

  1. 本地启动容器:docker run -p 8000:8000 my-registry.com/ai-team/sentiment-model:v1.0.0,使用 curl 发送测试请求验证模型推理正常。
  2. 推送镜像:确保镜像标签包含版本号和提交哈希(如 v1.1.0-3f2a9c1),便于追溯。
  3. 创建命名空间:kubectl create namespace ai-prod,避免与其他团队资源冲突。
  4. 编写 Deployment YAML:声明资源请求(CPU/内存)、存活探针(livenessProbe)和就绪探针(readinessProbe)。
  5. 应用并观察:kubectl apply -f deployment.yaml,使用 kubectl get pods -w 监控滚动状态。

3.5 案例:基于 FastAPI + PyTorch 的文本分类服务

假设我们要部署一个情感分析模型。开发完成后,在 Kubernetes 中创建如下 Deployment:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: sentiment-model-v1
  namespace: ai-prod
  labels:
    app: sentiment-model
    version: v1.0.0
spec:
  replicas: 3
  selector:
    matchLabels:
      app: sentiment-model
      version: v1.0.0
  template:
    metadata:
      labels:
        app: sentiment-model
        version: v1.0.0
    spec:
      containers:
      - name: model-server
        image: my-registry.com/ai-team/sentiment-model:v1.0.0
        ports:
        - containerPort: 8000
        resources:
          requests:
            cpu: "1"
            memory: "2Gi"
          limits:
            cpu: "2"
            memory: "4Gi"
        readinessProbe:
          httpGet:
            path: /health
            port: 8000
          initialDelaySeconds: 10
          periodSeconds: 5

对应的 Service 使用标签选择器将流量分发到所有 version=v1.0.0 的 Pod:

apiVersion: v1
kind: Service
metadata:
  name: sentiment-svc
  namespace: ai-prod
spec:
  selector:
    app: sentiment-model
    version: v1.0.0
  ports:
  - port: 80
    targetPort: 8000
  type: ClusterIP

3.6 误区与复盘:环境不一致导致的“灵异问题”

典型故障:某团队在本地测试通过后直接部署到 K8s,结果模型推理速度下降 10 倍。排查发现:本地开发机 CPU 支持 AVX-512 指令集,而集群节点为较老的 Intel CPU,导致 PyTorch 回退到基础指令集。复盘结论:必须在 Dockerfile 中明确指定 CPU 架构(如 --platform=linux/amd64),并在 CI 流水线中增加“镜像架构兼容性测试”步骤。

另一个高频误区是探针配置不当。若 readinessProbe 的 initialDelaySeconds 设置过短(如 3 秒),模型加载尚未完成,K8s 会不断重启容器,导致 CrashLoopBackOff。建议根据模型加载时间实测值,将初始延迟设为 15~30 秒,并设置合理的 failureThreshold。

最后,务必在部署前确认 镜像仓库的访问凭证(imagePullSecrets)已正确配置。私有仓库未认证时,Pod 会一直处于 ImagePullBackOff 状态,且事件日志中不会显示明确原因,容易让人误判为网络问题。

环境准备检查清单:
  • Python 虚拟环境已激活,requirements.txt 已提交至 Git。
  • Dockerfile 使用非 root 用户,且已通过 .dockerignore 排除缓存文件。
  • 镜像已推送至私有仓库,并验证 docker run 可正常启动服务。
  • K8s 集群可访问,kubectl get nodes 返回 Ready 状态。
  • 命名空间、Service、Deployment YAML 已通过 kubectl apply --dry-run=client 校验。
  • 探针路径(如 /health)在本地容器中已测试返回 200。