3. 环境准备
在开始灰度发布与回滚实战之前,必须先搭建一套可复现、可扩展的模型部署环境。本章节聚焦于三个核心层次:开发环境(本地代码与模型管理)、容器化技术(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
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 服务暴露的完整链路,以及灰度发布时流量切分的核心组件关系:
上图展示了从开发环境到 Kubernetes 集群的完整链路。其中 Service selector 是灰度发布的核心控制点——通过修改 selector 中匹配的 Pod 标签(如 version: v1.1.0),即可控制进入新版本的流量比例。
3.4 方法流程:本地验证 → 镜像构建 → 集群部署
标准化的部署流程能显著降低人为失误。推荐遵循以下步骤:
- 本地启动容器:
docker run -p 8000:8000 my-registry.com/ai-team/sentiment-model:v1.0.0,使用curl发送测试请求验证模型推理正常。 - 推送镜像:确保镜像标签包含版本号和提交哈希(如
v1.1.0-3f2a9c1),便于追溯。 - 创建命名空间:
kubectl create namespace ai-prod,避免与其他团队资源冲突。 - 编写 Deployment YAML:声明资源请求(CPU/内存)、存活探针(
livenessProbe)和就绪探针(readinessProbe)。 - 应用并观察:
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 误区与复盘:环境不一致导致的“灵异问题”
--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。