2
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?

ConoHa L4 GPU に OpenAI 互換 vLLM サーバーをデプロイ — conoha-cli と Claude Code でのエンドツーエンド検証記

2
Posted at

はじめに

「OpenAI 互換 API をセルフホストで動かしたい」というニーズに対する一番素直な答えが vLLM です。OpenAI SDK の base_url を差し替えるだけで叩けて、PagedAttention のおかげで ollama 系より同時実行に強い、というのが採用理由です。

本記事では、vLLM (OpenAI 互換 LLM 推論サーバー) を ConoHa VPS3 の NVIDIA L4 GPU インスタンスに conoha-cli でほぼワンコマンドでデプロイし、ブラウザの Swagger UI で実機検証するまでを通しで紹介します。

ファイル一式は PR crowdy/conoha-cli-app-samples#93 にコミット済みで、本文中のコードはすべてそのまま動く現物の抜粋です。完全版が必要な場合は vllm-gpu/ を参照してください。

構成

2 コンテナ構成です。

サービス 公開ポート 役割
vllm 8000 (内部のみ) OpenAI 互換推論サーバー
caddy 80 / 443 (ホスト直結) リバースプロキシ + 自動 TLS

L4 24GB に対し、デフォルトモデルは Qwen/Qwen2.5-7B-Instruct-AWQ (AWQ INT4 で約 9GB)。MAX_MODEL_LEN=8192 + --gpu-memory-utilization 0.90 で KV キャッシュにも余裕があります。

クライアント → Caddy(:80, :443) → vLLM(:8000) → NVIDIA L4

compose.yml の押さえどころ

完全版は vllm-gpu/compose.yml にあります。要は以下の形です。

services:
  vllm:
    image: vllm/vllm-openai:v0.20.1
    command:
      - --model
      - ${MODEL_NAME:-Qwen/Qwen2.5-7B-Instruct-AWQ}
      - --gpu-memory-utilization
      - "${GPU_MEMORY_UTILIZATION:-0.90}"
      - --quantization
      - ${QUANTIZATION:-awq_marlin}
      - --served-model-name
      - default
      - --api-key
      - ${VLLM_API_KEY:-}
    deploy:
      resources:
        reservations:
          devices:
            - driver: nvidia
              count: all
              capabilities: [gpu]
    healthcheck:
      test: ["CMD", "curl", "-fsS", "http://localhost:8000/health"]
      start_period: 1200s    # 初回モデル DL 猶予

  caddy:
    image: caddy:2-alpine
    ports: ["80:80", "443:443"]
    depends_on:
      vllm: { condition: service_healthy }

押さえどころ:

  • vllm はホストにポートを公開しない (外向きは Caddy のみ)
  • --api-key は空文字なら認証 OFF (vLLM が空文字を falsy と判定)
  • --served-model-name default で固定。OpenAI SDK からは model="default" で叩く
  • start_period: 1200s (= 20 分) は必須。9GB の Qwen 7B AWQ をダウンロード中に healthcheck が走り出すと再起動ループに入る
  • image: ...:v0.20.1 のようにタグを切る (:latest は再現性が壊れる)

Caddyfile

{$DOMAIN_NAME} {
	reverse_proxy vllm:8000 {
		flush_interval -1
	}

	# stream=true 時のみ Accept: text/event-stream を見て gzip を外す
	@no_sse {
		not header Accept *text/event-stream*
	}
	encode @no_sse gzip
}

stream=true の SSE 配信を壊さないために、

  1. flush_interval -1 で reverse_proxy のレスポンスバッファを切る (write 即 flush)
  2. Accept: text/event-stream リクエストには gzip を外す

encode の名前付きマッチャはレスポンスではなく リクエストヘッダ側に効きます。レスポンス側の Content-Type で振り分けたくなりますが、Caddyfile では混同しやすい挙動なので、Accept ヘッダで判定するのが素直です。

DOMAIN_NAME:80 のままにすれば HTTP-only、vllm.example.com のような実 FQDN を入れれば Caddy が Let's Encrypt の証明書を自動発行します。

.env (主な変数)

MODEL_NAME=Qwen/Qwen2.5-7B-Instruct-AWQ
QUANTIZATION=awq_marlin    # MODEL_NAME に揃える (FP16 モデルなら none)
VLLM_API_KEY=              # 空なら認証 OFF。本番では必ず設定
HF_TOKEN=                  # Llama 系などゲートモデル時のみ
DOMAIN_NAME=:80            # 実 FQDN を入れると Caddy が自動 TLS

MODEL_NAME を非 AWQ モデル (Llama 3.1 8B FP16 など) に切り替える時は QUANTIZATION=none必ず変えますawq_marlin のままだと vLLM 起動時にコケます。

デプロイ手順

1. セキュリティグループ

ConoHa VPS3 の default SG は 22 番もデフォルトでは開いていないので、22 と 80 だけ通したグループを作ります。

SG_ID=$(conoha network sg create --name vllm-gpu-test-sg --no-input \
  --format json | jq -r '.id')

for port in 22 80; do
  conoha network sgr create --security-group-id $SG_ID \
    --direction ingress --protocol tcp \
    --port-min $port --port-max $port --remote-ip 0.0.0.0/0 --no-input
done

2. cloud-init で NVIDIA セットアップ

vmi-docker-29.2-ubuntu-24.04-amd64 イメージは Docker は入っていますが NVIDIA driver と Container Toolkit は入っていません。--user-data に渡す cloud-init で初回ブート時にまとめて済ませます。要点は 4 行です。

apt-get install -y nvidia-container-toolkit ubuntu-drivers-common
ubuntu-drivers install --gpgpu              # headless GPU driver
nvidia-ctk runtime configure --runtime=docker
shutdown -r +1                              # kernel module 反映のため再起動

3. サーバー作成

conoha server create \
  --name vllm-gpu-test \
  --flavor 1ff846c5-... \    # g2l-t-c4m16g1-l4 (4 vCPU / 16GB / L4)
  --image  722c231f-... \    # vmi-docker-29.2-ubuntu-24.04-amd64
  --key-name tkim-cli-test-key \
  --security-group vllm-gpu-test-sg \
  --user-data /tmp/vllm-gpu-cloudinit.sh \
  --no-input --wait

L4 GPU の小さいフレーバーで Qwen 7B AWQ なら十分動きます。

4. アプリデプロイ

cloud-init 完了後、compose.yml のあるディレクトリで:

conoha app deploy <SERVER_ID> --app-name vllm-gpu \
  --no-proxy --no-input --insecure

このとき --no-proxy必須 です。詳細は後述のハマりポイントで。

ログに vllm-gpu-vllm-1 Healthy が出れば OK。start_period: 1200s のため、初回はここまで 5–15 分かかります。

ハマりポイント

実機で踏んだ落とし穴 3 つ。

1. L4 GPU 在庫切れ → --volume で既存ボリュームを再利用

ConoHa3 の L4 GPU は人気が高く、時間帯によって HTTP 500: No compute resource in stock で蹴られます。困るのは API の仕様上、ブートボリュームはサーバー作成 API 呼び出しの前に作られる ため、失敗時はボリュームだけ orphan として残る点です。

boot volume 3a156cca-... was created but server creation failed.
You can delete it with: conoha volume delete 3a156cca-...
API error (HTTP 500): {"code": 500, "error": "No compute resource in stock."}

conoha server create --help を見直すと --volume <既存ボリューム ID> フラグがありました。リトライ時はこれを付けるだけで残った orphan を再利用でき、別フレーバーでも attach 可能でした。L4 の小さい方が在庫切れなら大きい方 (g2l-t-c20m128g1-l4) で同じボリュームを使い回せます。

conoha server create --name vllm-gpu-test \
  --flavor b5d0e377-... \   # 別フレーバー
  --image  722c231f-... \   # 元と同じ image (CLI 上必須)
  --volume 3a156cca-... \   # ← orphan を再利用
  --key-name tkim-cli-test-key --security-group vllm-gpu-test-sg \
  --user-data /tmp/vllm-gpu-cloudinit.sh --no-input --wait

なお --volume 指定時も --image は CLI のバリデーション上必須です。同パターンを SKILL に追記する issue #13conoha-cli-skill に立てています。

2. cloud-init 後に nvidia-smi が見つからない

ubuntu-drivers install --gpgpu が入れる nvidia-headless-no-dkms-595-server-open には nvidia-smi が同梱されていません。確認用には別途 nvidia-utils-XXX-server をインストールします (XXX は driver シリーズ番号、検証時は 595)。

apt-get install -y nvidia-utils-595-server
nvidia-smi
# NVIDIA-SMI 595.58.03   Driver Version: 595.58.03   CUDA Version: 13.2
# 0  NVIDIA L4   23034 MiB / 23034 MiB

3. conoha app deploy--no-proxy

compose.yml だけのレシピで conoha.yml を持たないものは、明示的に --no-proxy を付けないと

read conoha.yml: open conoha.yml: no such file or directory

で蹴られます。本サンプルは Caddy が直接 80/443 を握る構成のため conoha.yml を持たず、conoha-proxy の blue/green 配置にも乗りません。--no-proxy で「flat single-slot 模式」に切り替わり、docker compose up -d だけが実行されます。hunyuan3d-gpu のような GPU + 内蔵 reverse proxy 構成のレシピでは、今後もこのパターンが続くはずです。

動作確認 — Swagger UI でブラウザ検証

CI 用の smoke-test.sh (/v1/models, /v1/chat/completions, /v1/completions への 3 アサーション) は当然パスしますが、ブラウザでも触れます。vLLM は内部で FastAPI を使っており、Swagger UI が /docs に自動マウントされているからです。

$ curl -s -o /dev/null -w "HTTP %{http_code} (%{content_type})\n" \
    http://160.251.238.117/docs
HTTP 200 (text/html; charset=utf-8)

ブラウザで http://<サーバー IP>/docs を開くと、いつもの Swagger UI が出ます。

認証

VLLM_API_KEY を設定している場合、画面右上の Authorize ボタンに値を入れます。Bearer プレフィックスは Swagger 側が自動付与するので、トークン本体だけで OK。これで /v1/* の各エンドポイントを 「Try it out」 で対話的に試せます。

/v1/chat/completions を叩く

リクエストボディ:

{
  "model": "default",
  "messages": [{"role": "user", "content": "こんにちは。あなたは何ができますか?"}],
  "max_tokens": 200,
  "stream": false
}

Execute でちゃんと OpenAI 互換のフォーマットが返ります (choices[0].message.content, usage.prompt_tokens / completion_tokens 付き)。

SSE ストリーミングの確認

streamtrue にすると、Server-Sent Events で逐次 chunk が返ります。Swagger UI 上で chunk が連続して表示されれば OK — 前述の Caddyfile の flush_interval -1@no_sse マッチャが効いている証拠です。逆に chunk が一気にまとめて出てきた場合は、reverse_proxy のバッファか gzip のいずれかが残ってしまっています。

このように smoke-test (CI 用) と Swagger UI (人間の検証用) の二段で動作確認できるのは、FastAPI ベースの vLLM ならではのメリットです。

認証なしで開いている公開エンドポイント

パス 認証 用途
/health 不要 liveness probe
/docs UI 表示は不要 / 呼び出しは要 Swagger UI
/openapi.json 不要 OpenAPI 3.1 スキーマ
/v1/* 必要 (Bearer) 推論エンドポイント

/openapi.json は LangChain や TypeScript の OpenAPI クライアント生成にそのまま流せるので、フロントや別サービスから vLLM を呼ぶ場合の手間が減ります。

後片付け

conoha server delete   <SERVER_ID> --yes
conoha volume delete   <VOLUME_ID> --yes
conoha network sg delete <SG_ID>   --yes

L4 は単価が高いので、検証で立てたら必ず畳みます。server delete だけでは volume / SG は別 API リソースとして残るので、それぞれ消す必要があります。

まとめ

  • vLLM は OpenAI 互換 API + PagedAttention の LLM 推論サーバー
  • ConoHa L4 GPU + conoha-cli で 1 セッションでデプロイ可能
  • compose.yml + Caddyfile の 2 ファイルで HTTPS 終端 + SSE 配慮も済む
  • --volume フラグは在庫切れ時の orphan ボリューム再利用に効く地味な切り札
  • conoha app deployconoha.yml 不在のレシピで --no-proxy 必須
  • vLLM は FastAPI ベースなので /docs でブラウザから対話検証できる

サンプル一式は crowdy/conoha-cli-app-samples の vllm-gpu にあります。

参考

2
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
2
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?