从“测试环境全绿、生产环境雪崩”说起
去年我负责一条 AI 推理服务上线,当时所有单元测试、接口压测全过,结果生产流量一进来,GPU 显存直接被打满,容器被 OOM Killer 杀掉,重启后模型加载又要 40 多秒,期间健康检查失败,又被调度器反复重启——典型的“冷启动雪崩”。排查下来根本不是模型效果问题,而是推理部署流程里几个非常基础的环节没有自动化兜底:模型文件没有做启动前校验、镜像里的 CUDA 运行时和宿主机驱动不兼容、探针配置不适合推理服务的加载特性。
从那之后我认真梳理了一遍“AI 模型推理自动化部署”这件事。它和普通 Web 后端部署的最大区别在于:推理服务是有状态的、计算密集的、加载代价高昂的进程。自动化不能只解决“把代码打包发布”的问题,而要覆盖模型产物校验、GPU 资源匹配、预热、灰度验证、弹性伸缩和故障恢复一整条链路。
这篇文章我把整套流程拆开来讲,适合正在做 AI 应用开发、平台工程、推理服务运维,或者准备把模型从实验环境推向生产环境的朋友参考。里面包含架构设计、流水线实现、Kubernetes 编排策略,以及我实际踩过的坑和排查过程。
1. 推理服务部署与普通后端部署的本质差异
1.1 一个推理进程的生命周期远比 Web 服务复杂
普通 Web 服务进程启动后,监听端口、接受请求、返回响应,整个过程通常毫秒级完成。容器探针就算检测失败,重启成本也很低。
推理服务完全不同。以我常用的大语言模型场景为例,一个 7B 参数的模型权重文件大约 14GB,加载到显存并完成初始化需要 30 秒到数分钟。在加载完成之前,服务无法处理任何推理请求。如果部署系统只看“进程是否存活、端口是否监听”来判断健康状态,就会在模型加载期间反复发出重启指令,导致永远无法进入就绪状态。
推理进程在运行时也不像 Web 服务那样“无状态”。显存里常驻模型权重、KV Cache、CUDA Context。一旦进程异常退出,这些状态全部丢失,恢复成本极高。因此部署策略必须尽量避免重启,同时在必须重启时告知调度系统“这个服务需要较长启动时间”。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
1.2 传统 CI/CD 模板直接套用的三个翻车点
很多团队第一次做模型部署,直接把 Java 或者 Node.js 服务的那套 Jenkins 流水线拿过来用,通常会在三个地方出问题。
第一个是镜像体积和构建时长。模型推理镜像动辄几个 GB 到几十 GB,包含 CUDA 运行时、推理引擎、模型文件。镜像推送、拉取、解压的时间比普通应用多一个数量级,流水线超时配置若还是默认的 10 分钟,必挂。
第二个是健康检查设计。普通服务存活探针直接检测 TCP 端口或 HTTP 接口即可,但推理服务在模型加载完成前,HTTP 端口即便已经监听,也无法真正处理请求。如果探针把“端口通了”当成“服务可用”,流量进来后全部超时;如果存活探针失败阈值设得太低,启动过程中就会被杀掉。
第三个是版本关联关系。代码有版本,模型有版本,推理引擎和 CUDA 也有版本。任何一个组件不匹配,整个服务就跑不起来。传统 CI/CD 流水线通常只管理代码版本,模型和推理引擎的匹配关系全靠人工记录,生产环境一出问题很难回滚。
我在项目里列过一张对比表,用来向团队解释为什么不能照搬普通部署流程:
| 对比维度 | 传统 Web 服务 | AI 推理服务 |
|---|---|---|
| 启动时间 | 秒级 | 秒到分钟级(模型加载) |
| 计算资源 | CPU 为主 | GPU 为主,显存敏感 |
| 状态特性 | 基本无状态,可随意重启 | 显存缓存 + 模型常驻,重启代价高 |
| 依赖关系 | 代码 + 依赖包 | 代码 + 模型文件 + 推理引擎 + CUDA/驱动 |
| 容量瓶颈 | CPU、内存、连接数 | 显存、GPU 利用率、推理并发度 |
| 健康检查 | 端口/接口通即可 | 需确认模型加载完成、显存分配正常、可处理推理请求 |
如果你想做一套真正可用的推理自动化部署,第一步不是写流水线,而是让你的部署系统理解上面这些差异。后面的所有设计都是围绕这些差异展开的。
2. 整体架构设计:从训练产物到对外服务
2.1 基础设施选型
我这次采用的架构以 Kubernetes 为底座,核心组件包括:
- 容器运行时与 GPU 调度:Docker + NVIDIA Container Toolkit,配合 Kubernetes 的 NVIDIA Device Plugin,让 Pod 能声明并独占 GPU 资源。
- 镜像仓库:Harbor,用于存放推理服务镜像和推理引擎镜像。Harbor 自带镜像签名和漏洞扫描,生产环境很有用。
- 模型仓库:MinIO(S3 协议),用于存放模型文件。MinIO 部署简单,和 Kubernetes 集成方便。也可以直接用云厂商的对象存储或 Hugging Face Hub 的私有化版本。
- CI/CD:Jenkins + Pipeline as Code。选 Jenkins 不是因为它是技术上的最优解,而是它在我当时的团队里落地成本最低、插件生态成熟,这个选型逻辑后面专门说。
- 推理引擎:根据模型类型选。大语言模型我用 vLLM 或 Triton Inference Server,CV 模型用 Triton 或 ONNX Runtime。核心思路是让引擎层支持动态 Batch、并发请求队列和指标暴露,这些能力对弹性伸缩至关重要。
一个比较关键的设计决策是:模型文件不打包进镜像,而是从模型仓库动态拉取。原因有三个:大模型文件容易超过镜像层大小限制,每次构建镜像都会把几百 MB 到几十 GB 的模型文件重复传输,极慢;模型迭代比代码频繁,一旦模型文件进镜像,每次模型更新都要重新走一遍镜像构建流程;模型版本的回滚和灰度必须能独立于代码进行,把模型文件放对象存储后,部署时通过环境变量指定模型版本即可。
2.2 服务链路与组件职责
整个推理服务的调用链路分为四层:
code复制入口网关(Ingress/API Gateway)
↓
推理服务容器(FastAPI 或 gRPC 服务)
↓
模型加载器(负责从模型仓库拉取并加载)
↓
推理引擎(vLLM / Triton / ONNX Runtime)
- 入口网关负责路由、限流、认证和灰度流量切换。推理请求通常需要长连接和流式响应,网关要支持相应的协议。
- 推理服务容器是模型和上层业务之间的适配层。它负责将业务请求转换为模型输入、调用推理引擎、解析结果。如果后续要接入多种模型,适配层的价值会非常明显。
- 模型加载器不是一个独立服务,而是推理服务进程内的一个模块。启动时按环境变量中的模型版本从模型仓库下载模型到本地缓存,再加载到显存。下载和加载都要有详细的日志和指标。
- 推理引擎是真正吃 GPU 的部分。它要支持并发请求排队、动态 Batch(把多个请求合并成一个 Batch 推理以提高吞吐),并暴露 Prometheus 指标,包括排队长度、Batch 大小、推理延迟、GPU 利用率等。
2.3 模型仓库的目录规范和版本约定
自动化部署要做得好,规范必须先定。我用的模型仓库目录结构如下:
code复制s3://model-repo/
├── llm-chat/
│ ├── 7b-v2.1/
│ │ ├── config.json
│ │ ├── model.safetensors
│ │ ├── tokenizer.json
│ │ └── metadata.json
│ └── 7b-v2.2/
│ ├─
