GPUStack
Docker 迁移
NFS 共享缓存
GPU 集群运维笔记
将 GPUStack 从 v0.7.1 迁移至 v2.1.1
在不破坏共享 NFS 模型缓存配置的前提下完成升级 #
本文记录了将基于旧版安装脚本运行的 GPUStack 环境迁移至基于 Docker 的 v2 系列的过程。
在保留管理节点兼作 NFS 的配置的同时,我们逐步迁移了 2 个 GPU 工作节点,
并在部署时整理了模型缓存共享、工作节点重新连接以及后端/CUDA 一致性验证等内容。
Ubuntu / Docker / NVIDIA GPU / NFS
目标:GPUStack v0.7.1 → v2.1.1
本文的前提条件 #
在生产环境中,我们采用 1 个管理节点加 2 个 GPU 工作节点的配置,模型缓存
统一存放于 /models 并通过 NFS 共享。本文中,实际主机名、
私有 IP、工作节点令牌等敏感信息均已省略,并抽象化至适合公开发布的程度。
原有配置十分简单:即“管理节点整合 GPUStack Server 与 NFS,GPU 工作节点
引用共同的 /models”。其优点在于只需下载一次模型文件,即可在新增工作节点时
减少磁盘占用与网络传输量。即使迁移到 v2 系列,我们也决定沿用这一理念,
只是将运维方式调整为与当前做法相匹配。
升级前后的思路 #
升级到 v2 系列前需要理解的要点 #
1. 迁移以 Docker 为前提 #
以旧版安装脚本或基于 pip 方式部署的环境,需要以
基于 Docker 的基础架构作为迁移到 v2 系列的官方迁移路径。
2. 管理数据库也会变化 #
从 v0.7 系列及更早版本默认使用的 SQLite,到 v2.0 及以后版本迁移到内嵌的 PostgreSQL。
也就是说,这并非单纯替换二进制文件,而是需要意识到数据迁移的操作。
3. 明确内置 worker 的定位 #
在旧有配置中,管理节点本身也会作为 worker 出现。此次迁移中,
我们决定改为让管理节点仅承担 Server 角色的方针,
使 Workers 列表中只保留 GPU 工作节点。
事先做好这件事非常关键 #
在动手改造 Server 之前,我们先对旧版数据目录进行了备份。
在 v2 系列中,新组件会读取旧版数据目录,因此权限调整与备份都非常重要。
实施的升级步骤 #
确认旧版数据目录并优先备份 #
我们确认了旧版 systemd 定义,以明确 Server 与 Worker 各自使用哪个数据目录。
随后依次执行了停止服务 → tar 备份 → 权限调整。
sudo systemctl cat gpustack | sed -n '/ExecStart/p'
sudo systemctl stop gpustack
sudo systemctl disable gpustack
sudo tar -C / -cpf /root/backup/gpustack-server.tar var/lib/gpustack优先将管理节点迁移至 v2.1.1 #
由于假定管理节点不使用 GPU,我们在启动 Server 时省略了 --runtime nvidia。
若保留该参数,启动会因unknown or invalid runtime name: nvidia 而失败,
这种情况会出现在 Docker 中未注册 NVIDIA runtime 的服务器上。
sudo docker run -d --name gpustack \
--restart=unless-stopped \
--privileged \
--network=host \
--env GPUSTACK_DATA_MIGRATION=true \
--volume /var/run/docker.sock:/var/run/docker.sock \
--volume /var/lib/gpustack:/var/lib/gpustack \
--volume /models:/models \
gpustack/gpustack:v2.1.1 \
--disable-worker \
--cache-dir /models我们明确指定了 --disable-worker,是为了将管理节点与原有的内置 worker
角色彻底分离。此次迁移的主旨是“管理节点专注于管理”。
逐步将 GPU 工作节点切换为基于 Docker 的 worker #
各工作节点在继承现有数据目录的同时,以基于 Docker 的 worker 身份重新接入。
为了匹配共享缓存路径,我们同样将 /models:/models 绑定到容器,
并在启动参数中追加 --cache-dir /models。
sudo docker run -d --name gpustack-worker \
--restart=unless-stopped \
--privileged \
--network=host \
--volume /var/lib/gpustack-data:/var/lib/gpustack \
--volume /var/run/docker.sock:/var/run/docker.sock \
--volume /models:/models \
--runtime nvidia \
gpustack/gpustack:v2.1.1 \
--server-url http://<SERVER_IP> \
--token <JOIN_TOKEN> \
--worker-name <WORKER_NAME> \
--worker-ip <WORKER_IP> \
--cache-dir /models关键之处在于,不要把 GUI 中的“Add Worker”单纯当作一次“注册操作”。
实际上,GUI 只是用于获取令牌和执行命令的入口;
只有在工作节点上实际执行该命令之后,才会进入 Ready 状态。
验证 NVIDIA Container Toolkit #
GPU 工作节点需要 --runtime nvidia。如果 Docker 不识别该 runtime,
可能是 NVIDIA Container Toolkit 的配置未生效。请按照官方步骤,
使用 nvidia-ctk 配置 Docker runtime 并重启 Docker。
sudo nvidia-ctk runtime configure --runtime=docker
sudo systemctl restart docker将 Workers 列表整理为“仅保留实际执行推理的节点” #
在旧环境中,管理节点始终作为 worker 保留,并在列表中显示为 Not Ready,成为混乱的根源。
在 2 个 GPU 工作节点都变为 Ready 之后,我们从管理节点开始清理这些残留的旧 worker。
这样一来,即便对运维团队来说,各节点的角色也更加一目了然。
本次遇到的坑 #
管理节点:unknown or invalid runtime name: nvidia #
尽管 Server 节点没有 GPU,或尚未安装 NVIDIA runtime,我们仍然以 --runtime nvidia 启动了它,
若要让管理节点专用于 Server,
最好直接去掉这个参数。
Worker 已 Ready,但模型状态为 Pending #
Worker 的状态与模型能否成功部署是两码事。尤其是在刚完成 v2 迁移之后,
由于沿用了旧的后端版本或 CUDA 代际不匹配,可能会出现 Pending 的情况。
“Worker 变为 Ready 就算完成”并不是终点;真正的迁移应包含部署 1 个模型进行验证。
此次部署得到的经验 #
此次由于工作节点侧同时进行了操作系统更新,导致与 CUDA 相关的软件包统一为 12.9 代。
在这种状态下,我们需要重新审视 GPUStack 一侧内置的后端版本及部署设置。
升级之后,最好将 Inference Backends 与 Deployment 的后端/版本指定
一并检查确认。
检查清单 #
- 首先理解旧环境各数据目录及 systemd 定义
- 开始迁移前先对 Server 进行备份
- 先启动管理节点,最后再处理 GPU 工作节点
- 如果使用 NFS 共享缓存,需在主机 / 容器 / 工作节点之间统一
/models - 若为仅承担 Server 角色的节点,需禁用内置 worker 并简化 Workers 列表
- 工作节点连接完成后,务必部署 1 个模型以验证后端/CUDA 的一致性
总结 #
此次升级中带来最大差异的,并非版本本身的升级,
而是“明确各节点的角色,让画面上呈现的内容更易于理解”这一点。
通过明确划分——管理节点承担 Server + NFS,推理仅在 GPU 工作节点上进行——
之后的运维决策也变得容易了许多。
如果您同样在使用 v0.7 系列及更早版本,并希望在保留共享缓存配置的
前提下升级到 v2 系列,我们强烈建议遵循以下 3 点:先 Server、后 Workers、部署时全面验证。
不要止步于“启动成功”,实际查看模型是否能正常启动,能让迁移的质量更加稳定可靠。
参考的官方资料 #
本文是基于特定内部环境撰写的实践笔记。在应用于实际生产环境时,
请务必根据最新的官方信息,重新核实所使用的 GPU、驱动、CUDA 代际以及后端版本等组合。