GPUStack を v0.7.1 から v2.1.1 へ移行した話

GPUStack を v0.7.1 から v2.1.1 へ移行した話

2 min read

 
Tech Blog
GPUStack
Docker Migration
NFS Shared Cache

GPU クラスタ運用メモ

GPUStack を v0.7.1 から v2.1.1 へ移行した話
共有 NFS モデルキャッシュ構成を壊さずにアップグレードする #

旧 installation script ベースで運用していた GPUStack 環境を、Docker ベースの v2 系へ移行した記録です。
管理ノードと NFS を兼ねる構成は維持しつつ、GPU ワーカーノードを 2 台ぶん段階的に移行し、
モデルキャッシュ共有・ワーカー再接続・デプロイ時の backend/CUDA 整合確認までを整理しました。

公開向けにホスト名・IP・トークンは抽象化
Ubuntu / Docker / NVIDIA GPU / NFS
対象: GPUStack v0.7.1 → v2.1.1

この記事の前提 #

実環境では管理ノード 1 台と GPU ワーカー 2 台で構成し、モデルキャッシュを
/models に集約して NFS 共有しています。この記事では、実ホスト名、
プライベート IP、ワーカートークンなどの機微情報はすべて伏せ、公開可能な粒度まで抽象化しています。

もともとの構成は「管理ノードに GPUStack Server と NFS を集約し、GPU ワーカーノード群が
共通の /models を参照する」シンプルなものです。モデルファイルのダウンロードを
1 回で済ませられるので、ワーカー追加時のディスク使用量とネットワーク転送量を抑えられるのが利点でした。
この思想は v2 系へ移行しても変えず、運用だけを現行のやり方に合わせて整理することにしました。

アップグレード前後の考え方 #

Before #

旧 installation script で導入した GPUStack を、systemd サービスとして運用。

Transition #

管理ノードを先に Docker ベースの v2.1.1 へ移行し、続いて GPU ワーカーを段階的に切り替え。

After #

管理ノードは Server + NFS 専任、推論は GPU ワーカー 2 台に集約。/models は引き続き共有。

管理ノード

GPUStack Server + NFS #

Docker 版 GPUStack Server を起動し、モデルキャッシュの実体を保持。

  • Server only で運用
  • embedded worker は無効化
  • NFS export として /models を提供
共有

GPU ワーカー A / B

GPUStack Worker #

NFS 共有された /models をマウントし、推論コンテナを起動。

  • Docker + NVIDIA runtime
  • --cache-dir /models を統一
  • worker ごとに名前と IP を明示

v2 系へ上げる前に押さえておきたいポイント #

1. 移行は Docker 前提 #

旧バージョンで installation script や pip ベースで入れていた環境は、
v2 系への移行時に Docker ベースへ寄せるのが公式の migration パスです。

2. 管理 DB も変わる #

v0.7 系以前で既定だった SQLite から、v2.0 以降は embedded PostgreSQL へ移行します。
つまり「バイナリだけ差し替える更新」ではなく、データ移行を意識した作業になります。

3. embedded worker を整理する #

旧構成では管理ノードが worker としても見えていました。今回はこれを機に、
管理ノードは Server 専任、GPU ワーカーだけを Workers 一覧に残す方針へ切り替えました。

最初にやってよかったこと #

Server を触る前に、旧データディレクトリのバックアップを取りました。
v2 系では新しいコンポーネントが legacy data dir を読むため、権限調整とバックアップはかなり大事です。

実施したアップグレード手順 #

01

legacy data dir を特定し、先にバックアップを取る #

旧構成の systemd 定義を確認し、Server / Worker がそれぞれどの data dir を使っているかを明確化しました。
そのうえでサービス停止 → 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
02

管理ノードを先に v2.1.1 へ移行する #

管理ノードは GPU を使わない前提だったため、Server 起動時の --runtime nvidia は外しました。
ここを付けたままだと、Docker 側に NVIDIA runtime が登録されていないサーバーでは
unknown or invalid runtime name: nvidia で起動に失敗します。

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 を明示したのは、管理ノード上の old embedded worker を
きれいに役割分離したかったからです。今回の移行では「管理ノードは管理に専念」がテーマでした。

03

GPU ワーカーを Docker 版 worker として順次切り替える #

ワーカーは既存の data dir を引き継ぎつつ、Docker 版 worker として再接続しました。
共有キャッシュのパスを合わせるため、コンテナにも /models:/models を bind し、
起動引数に --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 の「ワーカーを追加」をそのまま“登録作業”だと思わないことでした。
実際には GUI は token や実行コマンドを得るための入口で、Ready になるのはワーカーノード側で
実コマンドを流したあとです。

04

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
05

Workers 一覧を「実際に推論するノードだけ」に整理する #

旧環境では管理ノードが worker として残っており、一覧上は Not Ready に見えて混乱の元でした。
GPU ワーカー 2 台が Ready になったタイミングで、管理ノード由来の stale worker は整理対象にしました。
こうしておくと、運用チームが見ても役割が直感的になります。

今回ハマったポイント #

管理ノードで unknown or invalid runtime name: nvidia #

Server ノードに GPU を載せていない、あるいは NVIDIA runtime を入れていないのに
--runtime nvidia を付けたまま起動していました。管理ノードを Server 専任にするなら、
ここは素直に外すのがよかったです。

Worker は Ready なのにモデルが Pending #

ワーカーの状態とモデルデプロイ可否は別問題でした。特に v2 移行直後は、
backend version の持ち越しや CUDA 世代との整合で Pending になることがあります。
「worker が Ready になったら終わり」ではなく、実際に 1 本デプロイして確認するところまでが移行です。

デプロイ時の学び #

今回は worker 側の OS アップデートも入っており、結果として CUDA 系パッケージが 12.9 世代に揃いました。
その状態で GPUStack 側の built-in backend version と deployment 設定を見直す必要がありました。
移行後は、Inference BackendsDeployment の backend/version 指定
セットで確認するのが安全です。

チェックリスト #

  • 旧環境の data dir と systemd 定義を先に把握する
  • Server バックアップを取ってから移行を始める
  • 管理ノードは先、GPU ワーカーは後の順で上げる
  • NFS 共有キャッシュを使うなら /models を host / container / worker で統一する
  • Server 専任ノードなら embedded worker を切り、Workers 一覧をシンプルにする
  • ワーカー接続後は、必ず 1 本デプロイして backend/CUDA の整合まで確認する

まとめ #

今回のアップグレードでいちばん効いたのは、バージョンを上げること自体よりも
「ノードの役割を整理して、画面上の見え方を分かりやすくしたこと」でした。
管理ノードは Server + NFS、推論は GPU ワーカーだけ、と役割がはっきりしたことで、
以後の運用判断がずっとしやすくなっています。

もし同じように v0.7 系以前から使っていて、shared cache 構成を維持しながら v2 系へ上げたい場合は、
Server 先行・Worker 後追い・deployment まで実検証 の 3 点を強くおすすめします。
「起動できた」で終わらせず、実際にモデルが立ち上がるところまで見れば、移行の品質はかなり安定します。

参考にした公式情報 #

本記事は特定の社内環境を題材にした実践メモです。実運用へ適用する際は、利用中の GPU、ドライバ、
CUDA 世代、backend version の組み合わせを必ず最新の公式情報で再確認してください。

Updated on 2026年4月2日

What are your feelings

  • Happy
  • Normal
  • Sad