GPU 推理节点部署复盘与 Dynamo 访问验证完整指南
节点:
wc-prodk8s-1-137· 系统:CentOS Linux 7 (Core) · 内核(最终):5.4.278-1.el7.elrepo.x86_64· 架构:x86-64
镜像:nvcr.io/nvidia/ai-dynamo/vllm-runtime:1.2.0· 更新:2026-09-22
本节点从一台定制内核 CentOS 7.3(uname4.14,含大量残留组件)出发,经 K8s 集群接入、NVIDIA 驱动、内核升级、Docker 运行时接入,最终成功部署 NVIDIA Dynamo vllm-runtime 1.2.0 并跑通 Qwen 模型推理。本文档记录完整处理过程、可复现的部署命令、Dynamo 前端服务的访问与验证方法,供团队在同类机器上交接与复用。
核心结论:
- 定制内核(4.14)是驱动、CUDA、Dynamo 版本兼容等一系列卡点的总根源,最终通过升级 elrepo 官方内核
5.4.278一次性解决,典型的「升级而非绕过」。 - Dynamo 运行时对驱动与 CUDA 版本有明确下限要求,装错镜像或驱动版本会直接表现为「容器启动即报 OCI/requirement error」,需配套升级而非规避。
- 残留组件 + SystemdCgroup 不一致是 K8s 阶段最大的时间黑洞,务必装机先行清理并逐行走位 init 脚本。
目录
- 一、环境基线
- 二、整体处理流程
- 三、阶段 1:环境检测与 K8s 部署
- 四、阶段 2:NVIDIA 驱动与容器运行时
- 五、阶段 3:版本兼容修复
- 六、阶段 4:部署 Dynamo 并加载模型
- 七、Dynamo 前端服务访问与验证
- 八、复盘:关键结论与复用建议
一、环境基线
关键版本基线
| 层 | 组件 | 版本 / 状态 |
|---|---|---|
| 系统 | CentOS 7.3 → 7(Core) | 升级后 base 更新,保持 7 系 |
| 内核 | kernel | 5.4.278-1.el7.elrepo.x86_64(elrepo 官方长稳) |
| K8s | kubeadm / kubelet | 由 sealer 集群镜像统一交付,SystemdCgroup 已对齐 |
| GPU 驱动 | NVIDIA driver | 550 系(满足 CUDA 12.x),nvidia-smi 正常 |
| 容器运行时 | Docker + nvidia-container-toolkit | Docker CE + toolkit,nvidia runtime 已配置 |
| 推理框架 | NVIDIA Dynamo | ai-dynamo/vllm-runtime:1.2.0 |
| 模型 | Qwen 系列 | Qwen3-0.6B / Qwen2.5-0.5B-Instruct(按需拉取) |
二、整体处理流程
| 阶段 | 内容 | 目标 |
|---|---|---|
| Phase 1 | 环境检测与 K8s | 权限获取、检测 OS/内核、清理残留、部署 K8s |
| Phase 2 | 驱动与运行时 | 装 NVIDIA 驱动、Docker、nvidia-container-toolkit |
| Phase 3 | 版本兼容修复 | 升级内核、驱动、CUDA 以满足 Dynamo 下限 |
| Phase 4 | Dynamo 与模型 | 部署 vllm-runtime,加载模型,功能验证 |
四个阶段自下而上构成完整闭环:先建集群,再打通 GPU 容器能力,再满足推理框架的版本下限,最后部署模型并验证。越底层的问题越早暴露成本越低。
三、阶段 1:环境检测与 K8s 部署
拿到节点权限后第一件事是确认机器真实状态。初始检测显示系统为 CentOS 7.3(内核4.14.105-19-0021),这是一个明显非官方的定制内核,也是后来驱动与 Dynamo 兼容性的主要障碍。
1.1 初始检测
cat/etc/os-releaseuname-r# 4.14.105-19-0021(定制内核,非 CentOS 官方)hostnamectl# 静态主机名 wc-prodk8s-1-1371.2 残留组件清理与 SystemdCgroup
机器上存在未清理干净的containerd、kubelet及旧 K8s 配置,导致初始化报「systemd 文件已存在」、容器运行时挂载冲突等。主要卡点:
| 现象 | 根因 | 处理 |
|---|---|---|
| kubelet 无法 enable:File exists | 残留的 systemd unit / symlink 未清除 | 移除multi-user.target.wants/kubelet.service后重新systemctl enable kubelet |
| 容器运行时 init 失败 | 旧 containerd/kubelet 残留 & 配置不一致 | 清理/var/lib/kubelet、/etc/kubernetes,关闭 swap,对齐 cgroup driver |
| cgroup driver 不匹配 | kubelet(systemd)与 containerd(cgroupfs)不一致 | 统一为systemd并重启 containerd |
经验:定制内核 + 残留组件是最容易埋雷的组合。首次装机务必先以
rpm -qa | grep -E 'kubelet|kubeadm|kubernetes|containerd'核验残留,并在init-kube.sh报错时用bash -x逐行定位,而不是只看 systemctl 的表象。
1.3 组网与交付
K8s 交付采用 sealer 集群镜像完成,负责将整套 rootfs(含 kubeadm/etcd/kubelet)分发给 master 与 worker 节点并执行init-kube.sh。期间完成节点免密登录、网卡/主机名配置、内网 registry 可达性配置。
# 免密:节点间 ssh-copy-id 打通 root# 配置内网 registry 与镜像拉取sealer apply-fClusterfile# 应用集群配置,分发并 init-kube提醒:若复现「File exists」,正确顺序是先确认根因(残留 vs init-kube 真失败),再清理 systemd 链接与旧目录,最后重跑 sealer,切勿在残留未清时直接重复
sealer apply。
四、阶段 2:NVIDIA 驱动与容器运行时
K8s 就绪后打通 GPU 能力,装好驱动并通过 nvidia-container-toolkit 让容器运行时识别、注入 GPU。
2.1 驱动安装(内核 4.14 定制阶段的尝试)
在 4.14 定制内核上直接装官方驱动会遇到两个问题:内核头文件无法通过标准仓库获取(kernel-lt-devel在 elrepo 只保留最新小版本,4.14.105-19-0021定制版本号不存在),以及 gcc 版本须与编译内核所用编译器一致。初次曾尝试NVIDIA-Linux-x86_64-550.54.15.run,但依赖缺失导致编译失败。
# 关键前提:存在与 uname -r 精确匹配的 kernel-devells/usr/src/kernels/$(uname-r)&&echo"头文件存在"||echo"缺少头文件!"2.2 Docker 与 nvidia-container-toolkit
# 安装 nvidia-container-toolkit 并接入 Docker runtimeyuminstall-ynvidia-container-toolkit nvidia-ctk runtime configure--runtime=docker systemctl restartdockernvidia-container-cli info# 验证 GPU 注入能力经验:配置完成后必须
systemctl restart docker/restart containerd,否则 runtime 不生效;私有 registry(非 443 端口)需配置insecure-registries,否则容器启动会失败。
五、阶段 3:版本兼容修复
部署 Dynamo 时暴露了明确的版本下限问题:vllm-runtime 镜像要求宿主机驱动的 CUDA 能力满足镜像内 vLLM 的最低版本(容器启动即报cuda>=12.x requirement error)。必须走「升级,而非绕过」路线。
3.1 升级内核到 elrepo 官方版本
yum-config-manager--enableelrepo-kernel yuminstall-ykernel-lt kernel-lt-devel grub2-set-default0rebootuname-r# 期望看到 5.4.278-1.el7.elrepo.x86_643.2 在新内核上重装驱动并校准 CUDA
./NVIDIA-Linux-x86_64-550.54.15.run-s--no-opengl-files nvidia-smi# 确认 GPU 识别 & CUDA Version 满足容器要求关键卡点:升级顺序不可颠倒:先内核,再 kernel-devel(头文件),再驱动,最后验证
nvidia-smi。头文件与内核版本必须精确一致。若跳过内核升级直接在 4.14 定制内核上强装驱动「迁就」Dynamo,会因无匹配头文件而反复失败。最终升至 elrepo 5.4 + 驱动 550 系 + CUDA 12.x 一次性解决。
六、阶段 4:部署 Dynamo 并加载模型
Dynamo 以 frontend(API 网关,默认 8000)与 worker(vLLM 引擎进程)双角色运行。本地演示采用--discovery-backend file文件发现模式,减少对 etcd/NATS 的依赖。
6.1 拉取镜像并进入容器
dockerpull nvcr.io/nvidia/ai-dynamo/vllm-runtime:1.2.0dockerrun--gpusall--networkhost--rm-it\nvcr.io/nvidia/ai-dynamo/vllm-runtime:1.2.0 /bin/bash6.2 模型准备
模型可通过 HuggingFace 标识符让 worker 自动下载,也可节点自备本地模型目录(frontend 需要config.json/tokenizer*等配置文件,worker 需要权重)。推荐置于/data/models并挂载进容器。
/data/models/Qwen3-0.6B/ ├── config.json ├── model.safetensors (或多分片) ├── tokenizer_config.json └── generation_config.json6.3 启动 frontend 与 worker
# —— 终端 A:frontend(OpenAI 兼容 API 网关,端口 8000)——cd$DYNAMO_HOME/examples/backends/vllm python3-mdynamo.frontend --discovery-backendfile\--http-port8000\--model-path /models/Qwen3-0.6B# —— 终端 B:worker(vLLM 引擎,加载模型权重)——python3-mdynamo.vllm --discovery-backendfile\--model-path /models/Qwen3-0.6B\--kv-events-config'{"enable_kv_cache_events": false}'\--enforce-eager\--max-model-len4096\--max-num-seqs2单机单卡聚合模式下,官方默认模型Qwen/Qwen3-0.6B,常用参数MAX_MODEL_LEN=4096、MAX_CONCURRENT_SEQS=2、HTTP_PORT=8000,均可通过环境变量覆盖。多卡时给 worker 增加--tensor-parallel-size N。
常见坑:环境变量传参。
docker run -e KEY= value这类「等号后带空格」写法会被解析为独立 token,docker 误当作镜像名(例如报Unable to find image 'false:latest')。务必写成-e KEY=value无边空格。
七、Dynamo 前端服务访问与验证![]()
7.1 访问前提
Dynamo 前端在容器内默认监听8000端口。因使用--network host,容器网络与宿主机完全共享,无需端口映射,直接访问http://localhost:8000即可。当终端输出出现Uvicorn running on http://0.0.0.0:8000表示服务已就绪。
7.2 访问地址清单
| 名称 | 地址 | 用途 |
|---|---|---|
| Web 界面(Swagger UI) | http://localhost:8000/docs | 交互式测试 API |
| 健康检查 | http://localhost:8000/health | 验证服务是否正常 |
| 存活探针 | http://localhost:8000/live | 验证进程存活 |
| 监控指标 | http://localhost:8000/metrics | Prometheus 格式指标 |
| 模型列表 | http://localhost:8000/v1/models | 查看已服务模型 |
| OpenAPI 定义 | http://localhost:8000/openapi.json | 导出接口定义 |
7.3 常用验证命令
健康检查
curl-shttp://localhost:8000/healthcurl-shttp://localhost:8000/live监控指标
curl-shttp://localhost:8000/metrics|head模型列表
curl-shttp://localhost:8000/v1/models推理验证(OpenAI 兼容)
# Chat 补全curl-shttp://localhost:8000/v1/chat/completions\-H"Content-Type: application/json"\-d'{"model":"Qwen3-0.6B","messages":[{"role":"user","content":"你好"}],"max_tokens":64,"stream":false}'# 文本补全curl-shttp://localhost:8000/v1/completions\-H"Content-Type: application/json"\-d'{"model":"Qwen3-0.6B","prompt":"请介绍Kubernetes","max_tokens":64}'验证项通过标准
| 验证项 | 命令 | 通过标准 |
|---|---|---|
| GPU 可见性 | nvidia-smi | 宿主机与容器内均显示 RTX 3090 |
| 健康检查 | curl /live /health | 返回 OK / 列出实例 |
| 模型加载 | /v1/models | 返回所服务模型名 |
| 推理输出 | /v1/chat/completions | 返回语义合理的补全文本 |
7.4 常见问题排查
| 现象 | 可能原因与处理 |
|---|---|
curl localhost:8000拒绝连接 | 前端未就绪(仍在加载模型),先docker logs确认出现Uvicorn running后重试 |
容器内nvidia-smi无效 | 启动缺--gpus all,或 nvidia-container-toolkit 未配置/未重启 Docker |
/v1/models为空 | worker 进程未启动或尚未向 frontend 注册,确认 worker 已运行 |
输出Unable to find image 'false:latest' | -e KEY= value等号后多空格,误被解析为镜像名,改为-e KEY=value |
注意事项:Dynamo 前端不提供独立 Web 控制台,验证与监控统一通过 API、
/docs、/openapi.json及健康/指标端点完成。localhost仅适用于本机访问;若从其他主机访问,将地址替换为节点 IP(如http://10.200.1.137:8000)。
八、复盘:关键结论与复用建议
整条链路超过一半的翻车集中在「版本一致性」。把版本对齐前置能省去大量排障时间。针对同类定制内核机器,以下顺序值得固化交接。
| 步骤 | 动作 | 决策点/验收 |
|---|---|---|
| 1 | 确认内核是否官方 | uname -r非 elrepo/官方 → 规划升级 |
| 2 | 清理残留组件 | rpm -qa无 kubelet/kubeadm 残留 |
| 3 | 部署 K8s(sealer) | kubectl get nodes双节点 Ready,cgroup 对齐 |
| 4 | 升级内核+重装驱动 | 升级后nvidia-smi正常 |
| 5 | Docker + toolkit 接入 | nvidia-container-cli info通过 |
| 6 | 部署 Dynamo + 模型 | /health通过,推理返回有效文本 |
三条最值得记住的经验
- 定制内核是兼容性问题的总源头。4.14 定制内核既拿不到匹配 kernel-devel,也不满足 Dynamo 对驱动/CUDA 的下限,任何「在同一内核上打补丁迁就」的尝试都徒劳,升级到 elrepo 5.4 才是唯一有效路径。
- 残留组件 + SystemdCgroup 是 K8s 阶段的时间黑洞。首次装机先清理
kubelet/containerd/kubeadm与 systemd 链接,并用bash -x定位 init 脚本真正的失败点,避免在表象上反复重试。 - 容器镜像与驱动版本必须双向核对。vllm-runtime 镜像的 CUDA 下限来自宿主机驱动,装不同 tag(或用
-e时多空格)都可能让容器「启动即报错」;版本与配置对齐后,Docker + Dynamo 部署本身非常轻松。