4.3 生产部署前的环境与安全检查清单


文档摘要

4.3 生产部署前的环境与安全检查清单 4.1 和 4.2 讲的是「怎么把单机和集群跑起来」,但「能跑」和「能上生产」之间隔着一整道检查清单。我见过太多团队调通了 demo 就急着上线,结果生产第一天就出事:驱动版本不够导致偶发 NaN、API 端口裸奔被人扫到、模型权重权限没收紧被越权读取、日志没接监控事故后查无此案。这些坑每一个都不是技术难题,但每一个都足以让一次「成功部署」变成「线上事故」。 这一节我把生产部署前必须过的检查项整理成一份可执行的清单。它不只是「环境依赖基线」的扩写,而是覆盖硬件、软件、网络、安全、监控、可观测性、容量六个维度的完整 production-readiness 检查表。每一项我都会说清楚「为什么必须查」「怎么查」「不查会怎样」,而不是干巴巴列条目。

4.3 生产部署前的环境与安全检查清单

4.1 和 4.2 讲的是「怎么把单机和集群跑起来」,但「能跑」和「能上生产」之间隔着一整道检查清单。我见过太多团队调通了 demo 就急着上线,结果生产第一天就出事:驱动版本不够导致偶发 NaN、API 端口裸奔被人扫到、模型权重权限没收紧被越权读取、日志没接监控事故后查无此案。这些坑每一个都不是技术难题,但每一个都足以让一次「成功部署」变成「线上事故」。

这一节我把生产部署前必须过的检查项整理成一份可执行的清单。它不只是「环境依赖基线」的扩写,而是覆盖硬件、软件、网络、安全、监控、可观测性、容量六个维度的完整 production-readiness 检查表。每一项我都会说清楚「为什么必须查」「怎么查」「不查会怎样」,而不是干巴巴列条目。这份清单我在团队里用了两年,每次新服务上线都过一遍,拦下来的潜在事故不少于两位数。

检查清单的使用方式

在展开具体条目之前,先说清楚这份清单怎么用:

第一,它不是上线当天才跑的。它应该在压测通过、准备切流之前的一周就开始走,因为有些项(比如驱动升级、网络策略审批)需要时间窗口,临时发现根本来不及改。

第二,每一项都要有「责任人 + 验证证据」。光勾「已检查」没用,要能拿出证据(截图、日志、命令输出)。我在团队里用一张共享表格,每项要求附验证证据链接,否则视为未完成。

第三,分级处理。清单里标 [Block] 的是阻断项——任何一项不过都不允许切流;标 [Warn] 的是警告项——可以带病上线但必须有缓解措施和修复计划。

```mermaid flowchart TD A[压测通过] --> B[部署前 1 周: 跑检查清单] B --> C{所有 Block 项通过?} C -->|否| D[修复后重跑] C -->|是| E[Warn 项记录缓解措施] E --> F[切流量灰度] F --> G[观察 24-48h 监控] G --> H{稳定?} H -->|是| I[全量上线] H -->|否| J[回滚 + 复盘] ```

下面六个维度,逐项展开。

维度一:硬件与驱动基线 [Block]

这是最底层的一层,错了上面全是空中楼阁。

  • [Block] NVIDIA 驱动版本 ≥ 535(CUDA 12.x 的最低驱动要求)。低于此版本会出现偶发 NaN、kernel 崩溃、内存泄漏。验证:nvidia-smiDriver Version 字段。:驱动版本和 CUDA Runtime 是两个东西,驱动 535 跑 CUDA 12.1 没问题,但驱动 525 跑 CUDA 12.1 会偶发诡异错误。
  • [Block] CUDA Runtime 与 vLLM 版本匹配。vLLM 0.6+ 要求 CUDA 12.1+,部分新版本要 12.4。验证:nvcc --versionpython -c "import torch; print(torch.version.cuda)":PyTorch 自带的 CUDA Runtime 和系统 CUDA 是分开的,两者版本要协调,否则编译扩展时炸。
  • [Block] GPU 算力 ≥ 7.0(V100/Turing 及以上,A100/H100 推荐)。算力低于此 vLLM 的部分 kernel 不支持。验证:python -c "import torch; print(torch.cuda.get_device_capability())"
  • [Block] GPU 健康。卡有硬件故障(ECC 错误累积、过热降频)会引发随机崩溃。验证:nvidia-smi -q | grep -A5 "ECC" 看 ECC 错误计数,nvidia-smi -q | grep "GPU Current Temp" 看温度(持续 >85°C 说明散热有问题)。:二手卡、矿卡 ECC 错误率高,采购时必须查。
  • [Block] NVLink/PCIe 拓扑符合预期。多卡部署依赖节点内互联,TP=8 走 NVLink 和走 PCIe 性能差 3~5 倍。验证:nvidia-smi nvlink -s 看 NVLink 状态,nvidia-smi topo -m 看拓扑图(理想是 NV#,最差是 SYS 跨 NUMA)。
# 一行命令快速核对硬件基线 nvidia-smi --query-gpu=driver_version,name,memory.total,temperature.gpu,clocks_event_reasons.active --format=csv nvidia-smi topo -m python -c "import torch; print('CUDA:', torch.version.cuda, 'cap:', torch.cuda.get_device_capability())"

维度二:软件栈与依赖 [Block]

  • [Block] Python 版本。vLLM 官方支持 3.9~3.11,3.12 部分依赖(xformers 等)未跟进。验证:python --version:用 conda 环境时基础 Python 版本和实际跑的 Python 可能不一致,要用 which python 确认。
  • [Block] PyTorch ≥ 2.1。vLLM 依赖 torch.compile,低版本不支持。验证:python -c "import torch; print(torch.__version__)"
  • [Block] vLLM 版本固定为某个稳定 release,不要用 main 分支。生产环境追 main 等于自残——某次 main 提交引入回归,线上直接挂。验证:python -c "import vllm; print(vllm.__version__)",且这个版本要在团队的「已验证版本」清单里。
  • [Block] FlashAttention 版本与 vLLM 匹配。vLLM 默认调用 FA v2/v3,版本不对会 fallback 到慢实现或报错。验证:启动日志里搜 flash_attn,确认实际用的是哪个版本。
  • [Block] 依赖锁定pip freeze 的输出必须有版本管理(requirements.txt 锁定 + 镜像固化),不能在线装最新版。:今天装的 transformers==4.44 下周可能是 4.44.1 引入了 breaking change,必须锁死。
  • [Warn] 推理镜像可重建。生产镜像要能从 Dockerfile 重新构建,不要在容器里手动装包然后 commit。镜像构建有可重现性,手动 commit 的镜像出问题时无法回滚重建。
# 启动前自检三连 nvidia-smi python -c "import torch; print('cuda avail:', torch.cuda.is_available(), 'cap:', torch.cuda.get_device_capability())" python -c "import vllm, transformers, flash_attn; print('vllm:', vllm.__version__, 'transformers:', transformers.__version__)"

这三条命令全绿,才算环境基线通过。任何一条异常,先解决再继续——这是避免后续「玄学报错」的最低成本手段。

维度三:网络与端口 [Block]

生产服务的网络暴露面是安全事故的主要来源,这一维度必须严查。

  • [Block] API 端口不直接暴露公网。vLLM 默认监听 0.0.0.0:8000,如果机器有公网 IP,等于裸奔——任何人都能调你的模型,烧你的 GPU。必须通过反向代理(Nginx/Envoy)或 API 网关暴露,且网关层做鉴权。验证:curl http://公网IP:8000/v1/models 应该 timeout 或 403,不是 200。
  • [Block] 监听地址收敛。如果不需要跨节点访问,启动参数绑 --host 127.0.0.1,只允许本机访问;需要跨节点则绑内网网卡 IP,绝不绑 0.0.0.0 暴露所有接口。
  • [Block] 防火墙/安全组规则。仅放行必要的源 IP(业务后端服务器网段),端口最小化。验证:从外部机器 nmap 扫描,确认只有必要端口开放。
  • [Block] 节点间通信(多机部署)走内网高带宽。NCCL 走的是 RDMA/RoCE 或 InfiniBand,绝不能走公网(延迟和带宽都不够,且不安全)。验证:nccl-test 工具测节点间带宽,应接近 NVLink 域外的网络上限。
  • [Warn] DNS 与超时。客户端到 vLLM 的连接超时、重试策略要在网关层定义清楚。流式接口的 idle timeout 要 ≥ 最长生成时间,否则长生成被网关掐断。

维度四:安全与权限 [Block]

模型权重是核心资产,权限不收紧会被越权读取甚至外泄。

  • [Block] 模型权重文件权限。权重目录权限 750,owner 为跑 vLLM 的专用账户,禁止其他用户读。:默认 644 意味着同机任何用户都能拷走权重——一次权限疏忽就是一次资产外泄。
  • [Block] 跑服务的账户非 root。vLLM 用 root 跑意味着任何 RCE 漏洞直接拿 root,事故升级。建立专用账户(如 vllm),仅赋予读权重、用 GPU 的最小权限。
  • [Block] API 鉴权。vLLM 原生不带鉴权,必须在网关层加 API key / JWT。验证:curl 不带 token 应返回 401。:很多人 demo 阶段图省事关掉鉴权,上线时忘了开——这是最常见的安全事故。
  • [Block] 镜像与依赖来源可信。pip 源用内网私服或公司可信镜像,不要装来路不明的包(供应链攻击)。HuggingFace 下载模型用组织账号 + token,不要用匿名拉取。
  • [Block] 敏感信息(API key、模型路径、数据库连接)走密钥管理(Vault/KMS),不要硬编码在启动脚本或环境变量明文。:把 OpenAI API key 或 HF token 写进 Dockerfile,镜像一推公网仓库就泄漏。
  • [Warn] 审计日志。API 调用要记录「谁、何时、调了什么、消耗多少 token」,用于计费、限流、事后追查。

维度五:监控与可观测性 [Block]

没有监控的服务等于盲飞,事故发生了你都不知道。

  • [Block] vLLM /metrics 端点接 Prometheus。vLLM 暴露了丰富的 Prometheus 格式指标,必须接抓取。关键指标至少监控这几个:
指标 含义 告警阈值建议
vllm:num_requests_running 在跑请求数 持续 = max-num-seqs 说明满载
vllm:num_requests_waiting 排队请求数 持续 >0 说明过载
vllm:gpu_cache_usage_perc KV 池占用率 >0.9 说明池将满
vllm:time_to_first_token_seconds TTFT 分布 P99 > 业务阈值告警
vllm:e2e_request_latency_seconds 端到端延迟 P99 监控
vllm:preemption_count 抢占次数 累计上涨说明池不够
  • [Block] GPU 层监控nvidia-smigpu_utilmemory_usedtemperaturepower_draw 必须接监控(DCGM exporter)。:很多人只监控 vLLM 指标不监控 GPU 层,结果 GPU 故障(降频、过热)发现不了。
  • [Block] 基础设施监控。CPU、内存、磁盘、网络 IO 用 node_exporter 接。:vLLM 进程 OOM 是先吃爆系统内存再被 kill,不监控 node 内存看不到前兆。
  • [Block] 日志采集。vLLM 的 stdout/stderr 要采到集中日志系统(ELK/Loki),保留至少 30 天。:默认容器日志会被 docker 自动 rotate 掉,事故后查无此证。
  • [Block] 告警规则。关键指标必须配告警(不仅看图),且告警要分级:P0(服务不可用,立刻打电话)、P1(性能降级,工单处理)、P2(趋势异常,定期复盘)。告警发到 oncall 值班,不要发到没人看的群。
  • [Warn] 分布式追踪。API 网关 → vLLM → 模型生成 的链路接 OpenTelemetry,便于定位慢请求的瓶颈环节。

维度六:容量与弹性 [Warn]

这一维度不是阻断项,但决定服务能不能扛住峰值和故障。

  • [Warn] 容量规划有书面依据。基于 4.5 节的压测结果,明确「单实例最大并发」「集群最大 QPS」「单请求平均/峰值资源消耗」。容量水位(实际负载/最大容量)持续监控,>70% 就要扩容。
  • [Warn] 水平扩缩容机制。多实例部署 + 负载均衡,扩缩容触发条件明确(如 waiting 数持续 >N 触发扩容)。:vLLM 实例启动慢(加载权重几十秒到几分钟),扩容不能等过载才触发,要提前量。
  • [Warn] 优雅降级与限流。过载时主动限流(返回 429 + Retry-After),不要让请求堆积拖垮整个集群。客户端要有熔断和退避重试。
  • [Warn] 容灾与备份。多可用区部署,单 AZ 故障不影响服务。模型权重有多地副本,权重源(HuggingFace/对象存储)有备份通道。
  • [Warn] 回滚预案。每次上线前明确「出问题怎么回滚」——回滚到上一版镜像、回滚到上一版配置、回滚到上一版模型权重。回滚操作要演练过,不能第一次用就是事故现场。
  • [Warn] 灾难恢复演练。定期(季度)做一次「杀掉一半实例」「断网一个 AZ」「权重文件损坏」的演练,验证监控告警和应急流程是否真的有效。没演练过的预案,事故现场往往是失效的。

一份「上线就绪」的最终核对

把六个维度压缩成上线前最后 5 分钟的核对(虽然前面都做过了,临门一脚再确认):

[ ] 驱动/CUDA/GPU 健康(nvidia-smi + ECC 检查) [ ] 监控大盘有数据,告警规则已生效 [ ] API 鉴权打开,匿名访问被拒(curl 不带 token = 401) [ ] 端口不暴露公网(外部 nmap 扫描确认) [ ] 权重文件权限 750,owner 正确 [ ] 日志在集中系统可查 [ ] 回滚命令准备好且可一键执行 [ ] Oncall 已知晓本次上线时间和影响面

这 8 条全绿,才可以切流。任何一条黄/红,停下来修——切流多花一天,事故回滚可能要多花一周。

关于检查清单本身的心态

最后说一句不算技术、但更重要的话:检查清单的价值不在条目本身,在于「强制暂停」的纪律

人在临上线时会有强烈的「赶紧上」冲动——前面调试已经累了,再多查一遍显得多余。这份清单的作用,就是用一个外部约束把你拉回「再确认一次」的状态。我团队里有一条不成文的规矩:上线前检查清单必须由「非本次部署的人」复核签字,因为部署者自己会下意识跳过自己认为没问题的项。多一双眼睛,多一道防线。

这份清单的每一项背后,都站着一次真实事故。把它们固化成清单、强制执行,是为了不让同一个坑被踩第二次。上线前多花一小时过清单,胜过事故后通宵救火。


作者与出处
来源:灏天文库
整理: 灏天文库整理
由灏天文库平台收录,内容或由平台用户上传,仅供学习交流
发布者: 作者: 运行报错的菜鸟的小龙虾 转发
评论区 (0)
U