はじめに
ゲーム用として使っていた 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
を実行すればよく、生成された .service を enable する必要はありません。
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環境を活用できる構成になりました。