0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Bazzite + Radeon RX 7900 XTX で vLLM / ROCm のローカルLLMサーバーを構築する

0
Posted at

はじめに

ゲーム用として使っていた Bazzite PC をローカルLLMサーバーとして再利用しました。
下記内容は ChatGPT を使って設定した一部始終を ChatGPT にまとめてもらったものです。結果的には 24G の VRAM だと小さいモデルを動かすのが精一杯で求めていたクオリティにはならなかったので、24GB じゃだめか・・・という形にはなってしましたが、参考までに。

環境は以下です。

  • OS: Bazzite 44.20260629.0 (Kinoite)
  • GPU: AMD Radeon RX 7900 XTX
  • VRAM: 24GB
  • GPUドライバー: Bazzite標準の amdgpu
  • コンテナ: rootless Podman
  • 推論サーバー: vLLM ROCm
  • API: OpenAI互換API
  • モデル: google/gemma-4-12B-it-qat-w4a16-ct

Bazziteホスト側へROCm一式を直接インストールするのではなく、

Bazzite
  ├─ amdgpu
  ├─ RX 7900 XTX
  └─ rootless Podman
       └─ vLLM ROCm
            └─ Gemma 4 12B
                 └─ OpenAI Compatible API :8000

という構成にします。

GPU自体はコンテナ内で仮想化するのではなく、ホストの /dev/kfd/dev/dri を直接渡します。


1. GPUがBazziteから認識されていることを確認

まず変更を加えず、現在の状態を確認します。

cat /etc/os-release
uname -r
lspci -nnk | grep -A3 -E 'VGA|Display'
ls -l /dev/kfd
ls -l /dev/dri

今回の環境では以下のようになりました。

AMD Radeon RX 7900 XTX
Kernel driver in use: amdgpu

/dev/kfd
/dev/dri/renderD128

/dev/kfd/dev/dri/renderD128 が存在していることを確認します。


2. Podmanを確認

BazziteにはPodmanが入っているので確認します。

podman --version
podman info --format '{{.Host.Security.Rootless}}'

今回の環境では、

podman version 5.8.3
true

でした。

つまりrootless Podmanです。


3. SELinuxからコンテナのGPUアクセスを許可

BazziteではSELinuxが有効になっています。

確認します。

getenforce
getsebool container_use_devices

今回の初期状態は、

Enforcing
container_use_devices --> off

でした。

rootless PodmanからGPUデバイスへアクセスするため、次を実行します。

sudo setsebool -P container_use_devices true

確認します。

getsebool container_use_devices

次のようになればOKです。

container_use_devices --> on

元に戻す場合は、

sudo setsebool -P container_use_devices false

です。


4. Quadlet用ディレクトリを作成

Bazziteでは、常駐コンテナをrootless Podman + Quadletで管理できます。

mkdir -p ~/.config/containers/systemd

5. Hugging Faceモデルキャッシュを永続化

コンテナを再作成するたびにモデルをダウンロードし直さないように、Podman named volumeを作ります。

cat > ~/.config/containers/systemd/vllm-hf-cache.volume <<'EOF'
[Volume]
EOF

この定義から、

systemd-vllm-hf-cache

というPodman volumeが作成されます。


6. Gemma 4 12B用のQuadletを作成

以下をそのまま作成します。

cat > ~/.config/containers/systemd/vllm-gemma4-12b.container <<'EOF'
[Unit]
Description=vLLM Gemma 4 12B on RX 7900 XTX

[Container]
Image=docker.io/vllm/vllm-openai-rocm:latest

AddDevice=/dev/kfd
AddDevice=/dev/dri/renderD128

SeccompProfile=unconfined

PublishPort=0.0.0.0:8000:8000

Volume=vllm-hf-cache.volume:/root/.cache/huggingface

PodmanArgs=--ipc=host

Exec=google/gemma-4-12B-it-qat-w4a16-ct --max-model-len 32768 --gpu-memory-utilization 0.90 --kv-cache-dtype fp8

[Service]
Restart=on-failure
RestartSec=10
TimeoutStartSec=900

[Install]
WantedBy=default.target
EOF

主な設定は次のとおりです。

モデル:
google/gemma-4-12B-it-qat-w4a16-ct

Context:
32768

GPU memory utilization:
0.90

KV cache:
FP8

API:
0.0.0.0:8000

0.0.0.0:8000 なので、Bazzite自身だけでなくLAN上の別PCからもアクセスできます。


7. Quadletの構文を確認

systemctl --user daemon-reload

続いて、

systemd-analyze --user --generators=true verify vllm-gemma4-12b.service

何もエラーが出なければ次へ進みます。


8. ログインしていなくてもrootless Podmanを起動可能にする

Bazzite起動後、ユーザーがSSHやGUIでログインする前からサービスを起動できるようにします。

loginctl enable-linger $USER

確認します。

loginctl show-user $USER -p Linger

次のようになればOKです。

Linger=yes

9. vLLMを起動

systemctl --user start vllm-gemma4-12b.service

初回はモデルのダウンロードがあるため時間がかかります。

ログを見るには、

journalctl --user -u vllm-gemma4-12b.service -f

を使います。

最終的に、

Application startup complete.

まで進めば起動完了です。


10. モデルが公開されていることを確認

別のSSHセッションで実行します。

curl -4 http://127.0.0.1:8000/v1/models

以下のモデル名が返れば成功です。

google/gemma-4-12B-it-qat-w4a16-ct

11. OpenAI互換APIで実際に推論する

curl -4 http://127.0.0.1:8000/v1/chat/completions \
  -H 'Content-Type: application/json' \
  -d '{
    "model": "google/gemma-4-12B-it-qat-w4a16-ct",
    "messages": [
      {
        "role": "user",
        "content": "こんにちは。短く自己紹介してください。"
      }
    ],
    "max_tokens": 256,
    "temperature": 0.2
  }'

レスポンスの choices に回答が返れば、

RX 7900 XTX
  ↓
ROCm
  ↓
vLLM
  ↓
Gemma 4 12B
  ↓
OpenAI Compatible API

まで正常に動作しています。


12. LAN上の別マシンから確認

Bazzite PCのLAN側IPv4アドレスを確認します。

ip -4 addr

別のMacやPCのブラウザ、またはcurlから、

http://Bazzite-PCのIPv4アドレス:8000/v1/models

へアクセスします。

モデル情報のJSONが返ればLAN公開も成功です。


13. 日常的な操作

起動:

systemctl --user start vllm-gemma4-12b.service

停止:

systemctl --user stop vllm-gemma4-12b.service

再起動:

systemctl --user restart vllm-gemma4-12b.service

状態確認:

systemctl --user status vllm-gemma4-12b.service

ログ確認:

journalctl --user -u vllm-gemma4-12b.service -f

現在動作中のコンテナ確認:

podman ps

保存されているイメージ:

podman images

永続volume:

podman volume ls

14. Quadletでは systemctl enable しない

通常のsystemd serviceとは異なり、Quadletから生成されたserviceに、

systemctl --user enable vllm-gemma4-12b.service

を実行すると、

Failed to enable unit:
Unit ... is transient or generated

となります。

これは異常ではありません。

Quadletでは .container 内の、

[Install]
WantedBy=default.target

が自動起動設定に相当します。

そのため、

systemctl --user daemon-reload

を実行すればよく、生成された .serviceenable する必要はありません。


15. localhost でcurlすると接続がresetされる場合

今回の環境では、

curl http://localhost:8000/v1/models

を実行すると、localhost がIPv6の ::1 に解決され、

Recv failure: 接続が相手からリセットされました

となりました。

IPv4を明示すると正常に動きます。

curl -4 http://127.0.0.1:8000/v1/models

または、

curl http://127.0.0.1:8000/v1/models

を使用します。


16. Address already in use が出る場合

別のvLLMコンテナなどがTCP/8000を使用している可能性があります。

確認:

ss -ltnp | grep ':8000'

Podman側も確認します。

podman ps

例えば別モデルが、

0.0.0.0:8000->8000/tcp

で動いていれば、そのサービスを停止してから新しいモデルを起動します。


17. 初回だけ応答が遅い場合

vLLMでは初回推論時にTriton kernelのJIT compilationが発生することがあります。

ログに、

Triton kernel JIT compilation during inference

のような表示が出ることがあります。

その場合、2回目以降はコンパイル済みkernelが使われるため高速になります。

初回の1リクエストだけを見て性能を判断しない方がよいです。


18. モデルを変更する場合

基本的にはQuadlet内の Exec= のモデル名を変更します。

ただし、複数のvLLMサービスを同じ 8000 番ポートで同時起動することはできません。

現在のモデルを停止してから別モデルを起動します。

systemctl --user stop vllm-gemma4-12b.service

8000番が空いたことを確認:

ss -ltnp | grep ':8000'

何も返らなければ別サービスを起動できます。


19. モデルキャッシュについて

Hugging Faceのキャッシュは、

systemd-vllm-hf-cache

というPodman volumeへ保存されています。

確認:

podman volume ls

このvolumeを残している限り、コンテナを作り直してもモデルを毎回ダウンロードし直す必要はありません。

volume自体を削除する場合は、

podman volume rm systemd-vllm-hf-cache

です。

注意:

このコマンドを実行すると、ダウンロード済みモデルも削除されます。


20. 完全に削除する場合

まずサービスを停止します。

systemctl --user stop vllm-gemma4-12b.service

Quadletを削除します。

rm ~/.config/containers/systemd/vllm-gemma4-12b.container
rm ~/.config/containers/systemd/vllm-hf-cache.volume
systemctl --user daemon-reload

モデルキャッシュも不要なら、

podman volume rm systemd-vllm-hf-cache

vLLMイメージも不要なら、

podman image rm docker.io/vllm/vllm-openai-rocm:latest

SELinux設定まで元に戻す場合は、

sudo setsebool -P container_use_devices false

です。


まとめ

BazziteのRX 7900 XTXでローカルLLMを動かす場合、ホストへROCmを直接インストールしなくても、

Bazzite
+ amdgpu
+ rootless Podman
+ vLLM ROCm container

で動作させることができました。

Bazzite側では既にGPUドライバーが正常に動いていたため、その環境を崩さず、ROCm / PyTorch / vLLMだけをコンテナ側に閉じ込められるのがこの構成の利点です。

最終的な構成は、

RX 7900 XTX 24GB
       ↓
Bazzite / amdgpu
       ↓
rootless Podman
       ↓
vLLM ROCm
       ↓
Gemma 4 12B W4A16
       ↓
OpenAI Compatible API :8000

となりました。

OpenAI互換APIなので、Open WebUIや自作アプリなどから通常の /v1/models/v1/chat/completions として利用できます。

今回確認できた注意点

  • BazziteホストへROCmを直接導入しなくてもよい
  • rootless PodmanからGPUを使うにはSELinux設定が必要だった
  • /dev/kfd/dev/dri が重要
  • Quadlet生成serviceには systemctl enable を実行しない
  • 自動起動は .container[Install] で設定する
  • localhost がIPv6へ解決される場合は 127.0.0.1 を使う
  • 同じTCP/8000を複数モデルで同時使用できない
  • 初回推論はJIT compilationで遅くなる場合がある
  • Hugging Faceキャッシュはnamed volumeへ永続化しておくと再ダウンロードを防げる

Bazziteをゲーム用途からローカルLLM用途へ転用したい場合でも、OSをUbuntu等へ入れ替えずに既存のGPU環境を活用できる構成になりました。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?