runpod-deployment について
RunPod上のGPUワークロードのデプロイと運用を支援するClaudeスキルです。サーバーレスワーカー、vLLMエンドポイント、専用Podに加え、GPU選定やコスト管理、監視の手順を扱います。
主な機能
- 01サーバーレスハンドラーのパターン
- 02vLLMエンドポイントのデプロイ
- 03GPUとPodの選定
- 04コストとスケーリングの指針
- 05ヘルスチェックとメトリクス
活用シーン
- 01サーバーレス推論エンドポイントのデプロイ
- 02vLLM APIによるモデル提供
- 03予算に合わせたGPU選定
- 04エンドポイントの状態とスケーリングの監視
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ scientiacapital/ skills --skill runpod-deploymentインストール後、Claude Code で/runpod-deploymentを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
config.jsonreference/cicd.mdcost-optimization.mdmodel-deployment.mdmonitoring.mdpod-management.mdproject-configs.mdserverless-workers.mdtemplates.mdtroubleshooting.mdvllm-setup.mdtemplates/runpod-worker.py詳細
- サーバーレスワーカー - 秒単位の課金でゼロにスケールするハンドラー
- vLLM エンドポイント - 2〜3倍のスループットを実現する OpenAI 互換の LLM サービング
- Pod 管理 - 開発・トレーニング用の専用 GPU インスタンス
- コスト最適化 - GPU の選択、スポットインスタンス、予算管理
主な成果物:
- ストリーミング対応の本番環境対応サーバーレスハンドラー
- OpenAI API 互換の vLLM デプロイ
- あらゆるモデルサイズに対応するコスト最適化された GPU の選択
- ヘルスモニタリングと自動スケーリングの構成
<quick_start> 最小構成のサーバーレスハンドラー(v1.8.1):
import runpod
def handler(job):
"""Basic handler - receives job, returns result."""
job_input = job["input"]
prompt = job_input.get("prompt", "")
# Your inference logic here
result = process(prompt)
return {"output": result}
runpod.serverless.start({"handler": handler})
ストリーミングハンドラー:
import runpod
def streaming_handler(job):
"""Generator for streaming responses."""
for chunk in generate_chunks(job["input"]):
yield {"token": chunk, "finished": False}
yield {"token": "", "finished": True}
runpod.serverless.start({
"handler": streaming_handler,
"return_aggregate_stream": True
})
vLLM OpenAI 互換クライアント:
from openai import OpenAI
client = OpenAI(
api_key="RUNPOD_API_KEY",
base_url="https://api.runpod.ai/v2/ENDPOINT_ID/openai/v1",
)
response = client.chat.completions.create(
model="meta-llama/Llama-3.1-8B-Instruct",
messages=[{"role": "user", "content": "Hello!"}],
max_tokens=100,
)
</quick_start>
<success_criteria> RunPod のデプロイは、次の条件を満たす場合に成功です:
- ハンドラーがエラーなくリクエストを処理する
- エンドポイントが適切にスケールする(0 → N ワーカー)
- コールドスタート時間がユースケースに対して許容範囲である
- コストが予算の見積もり内に収まる
- ヘルスチェックが継続的に成功する </success_criteria>
<m1_mac_critical>
M1/M2 Mac:ローカルで Docker をビルドできない
ARM アーキテクチャは RunPod の x86 GPU と互換性がありません。
解決策:GitHub Actions が代わりにビルドします:
# Push code - Actions builds x86 image
git add . && git commit -m "Deploy" && git push
完全な GitHub Actions ワークフローについては
reference/cicd.mdを参照してください。
Apple Silicon で RunPod 用にローカルで docker build を実行しないでください。
</m1_mac_critical>
<gpu_selection>
GPU 選択マトリクス(2025年1月)
| GPU | VRAM | Secure $/時 | Spot $/時 | 最適な用途 |
|---|---|---|---|---|
| RTX A4000 | 16GB | $0.36 | $0.18 | 埋め込み、小規模モデル |
| RTX 4090 | 24GB | $0.44 | $0.22 | 7B〜8B 推論 |
| A40 | 48GB | $0.65 | $0.39 | 13B〜30B、ファインチューニング |
| A100 80GB | 80GB | $1.89 | $0.89 | 70B モデル、本番環境 |
| H100 80GB | 80GB | $4.69 | $1.88 | 70B+ トレーニング |
クイック選択:
def select_gpu(model_params_b: float, quantized: bool = False) -> str:
effective = model_params_b * (0.5 if quantized else 1.0)
if effective <= 3: return "RTX_A4000" # $0.36/hr
if effective <= 8: return "RTX_4090" # $0.44/hr
if effective <= 30: return "A40" # $0.65/hr
if effective <= 70: return "A100_80GB" # $1.89/hr
return "H100_80GB" # $4.69/hr
詳細な料金と予算管理については
reference/cost-optimization.mdを参照してください。 </gpu_selection>
<handler_patterns>
ハンドラーパターン
進捗の更新(長時間実行タスク)
import runpod
def long_task_handler(job):
total_steps = job["input"].get("steps", 10)
for step in range(total_steps):
process_step(step)
runpod.serverless.progress_update(
job_id=job["id"],
progress=int((step + 1) / total_steps * 100)
)
return {"status": "complete", "steps": total_steps}
runpod.serverless.start({"handler": long_task_handler})
エラーハンドリング
import runpod
import traceback
def safe_handler(job):
try:
# Validate input
if "prompt" not in job["input"]:
return {"error": "Missing required field: prompt"}
result = process(job["input"])
return {"output": result}
except torch.cuda.OutOfMemoryError:
return {"error": "GPU OOM - reduce input size", "retry": False}
except Exception as e:
return {"error": str(e), "traceback": traceback.format_exc()}
runpod.serverless.start({"handler": safe_handler})
非同期パターン、バッチ処理、高度なハンドラーについては
reference/serverless-workers.mdを参照してください。 </handler_patterns>
<vllm_deployment>
vLLM デプロイ
注記: vLLM は OpenAI 互換の API フォーマットを使用しますが、接続先はあなたの RunPod エンドポイントであり、 OpenAI のサーバーではありません。モデルはあなたの GPU 上で実行されます(Llama、Qwen、Mistral など)。
環境設定
vllm_env = {
"MODEL_NAME": "meta-llama/Llama-3.1-70B-Instruct",
"HF_TOKEN": "${HF_TOKEN}",
"TENSOR_PARALLEL_SIZE": "2", # Multi-GPU
"MAX_MODEL_LEN": "16384",
"GPU_MEMORY_UTILIZATION": "0.95",
"QUANTIZATION": "awq", # Optional: awq, gptq
}
OpenAI 互換ストリーミング
from openai import OpenAI
client = OpenAI(
api_key="RUNPOD_API_KEY",
base_url="https://api.runpod.ai/v2/ENDPOINT_ID/openai/v1",
)
stream = client.chat.completions.create(
model="meta-llama/Llama-3.1-8B-Instruct",
messages=[{"role": "user", "content": "Write a poem"}],
stream=True,
)
for chunk in stream:
if chunk.choices[0].delta.content:
print(chunk.choices[0].delta.content, end="", flush=True)
RunPod 直接ストリーミング
import requests
url = "https://api.runpod.ai/v2/ENDPOINT_ID/run"
headers = {"Authorization": "Bearer RUNPOD_API_KEY"}
response = requests.post(url, headers=headers, json={
"input": {"prompt": "Hello", "stream": True}
})
job_id = response.json()["id"]
# Stream results
stream_url = f"https://api.runpod.ai/v2/ENDPOINT_ID/stream/{job_id}"
with requests.get(stream_url, headers=headers, stream=True) as r:
for line in r.iter_lines():
if line: print(line.decode())
HuggingFace、TGI、カスタムモデルのパターンについては
reference/model-deployment.mdを参照してください。 </vllm_deployment>
<auto_scaling>
自動スケーリング構成
スケーラーの種類
| 種類 | 最適な用途 | 構成 |
|---|---|---|
| QUEUE_DELAY | 変動するトラフィック | scaler_value=2(2秒を目標) |
| REQUEST_COUNT | 予測可能な負荷 | scaler_value=5(ワーカーあたり5リクエスト) |
構成パターン
configs = {
"interactive_api": {
"workers_min": 1, # Always warm
"workers_max": 5,
"idle_timeout": 120,
"scaler_type": "QUEUE_DELAY",
"scaler_value": 1, # 1s latency target
},
"batch_processing": {
"workers_min": 0,
"workers_max": 20,
"idle_timeout": 30,
"scaler_type": "REQUEST_COUNT",
"scaler_value": 5,
},
"cost_optimized": {
"workers_min": 0,
"workers_max": 3,
"idle_timeout": 15, # Aggressive scale-down
"scaler_type": "QUEUE_DELAY",
"scaler_value": 5,
},
}
Pod のライフサイクルとスケーリングの詳細については
reference/pod-management.mdを参照してください。 </auto_scaling>
<health_monitoring>
ヘルスとモニタリング
クイックヘルスチェック
import runpod
async def check_health(endpoint_id: str):
endpoint = runpod.Endpoint(endpoint_id)
health = await endpoint.health()
return {
"status": health.status,
"workers_ready": health.workers.ready,
"queue_depth": health.queue.in_queue,
"avg_latency_ms": health.metrics.avg_execution_time,
}
GraphQL メトリクスクエリ
query GetEndpoint($id: String!) {
endpoint(id: $id) {
status
workers { ready running pending throttled }
queue { inQueue inProgress completed failed }
metrics {
requestsPerMinute
avgExecutionTimeMs
p95ExecutionTimeMs
successRate
}
}
}
構造化ログ、アラート、ダッシュボードについては
reference/monitoring.mdを参照してください。 </health_monitoring>
<dockerfile_pattern>
Dockerfile テンプレート
FROM runpod/pytorch:2.1.0-py3.10-cuda12.1.1-devel-ubuntu22.04
WORKDIR /app
# Install dependencies (cached layer)
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
# Copy application
COPY . .
# RunPod entrypoint
CMD ["python", "-u", "handler.py"]
runpod.toml、requirements.txt のパターンについては
reference/templates.mdを参照してください。 </dockerfile_pattern>
<file_locations>
参照ファイル
コアパターン:
reference/serverless-workers.md- ハンドラーパターン、ストリーミング、非同期処理reference/model-deployment.md- vLLM、TGI、HuggingFace のデプロイreference/pod-management.md- GPU タイプ、スケーリング、ライフサイクル
運用:
reference/cost-optimization.md- 予算管理、適正なリソース選定reference/monitoring.md- ヘルスチェック、ロギング、GraphQLreference/troubleshooting.md- よくある問題と解決策
DevOps:
reference/cicd.md- M1 Mac ビルド向けの GitHub Actionsreference/templates.md- Dockerfile、runpod.toml の設定templates/runpod-worker.py- 本番環境向けハンドラーテンプレート </file_locations>
ユーザーがサーバーレスデプロイを希望している場合:
→ ハンドラーパターン、Dockerfile、デプロイ手順を提示します
→ 参照先:reference/serverless-workers.md
ユーザーが vLLM エンドポイントを希望している場合:
→ vLLM の環境設定、OpenAI クライアントのセットアップを提示します
→ 参照先:reference/model-deployment.md
ユーザーがコスト最適化を希望している場合:
→ GPU 選択マトリックス、スポット価格、予算管理を提示します
→ 参照先:reference/cost-optimization.md
ユーザーが M1/M2 Mac を使用している場合:
→ 重要:ビルドには GitHub Actions を必ず使用する必要があります
→ 参照先:reference/cicd.md
ユーザーにデプロイの問題がある場合:
→ ヘルスエンドポイントを確認し、ログを確認します
→ 参照先:reference/troubleshooting.md
<cost_quick_ref>
コスト早見表
ストレージコスト:
- コンテナディスク:$0.10/GB/月(5 分単位で課金)
- ネットワークボリューム:最初の 1TB は $0.07/GB/月、その後は $0.05/GB
コスト見積もり:
def estimate_monthly_cost(gpu_type, daily_requests, avg_time_s):
rates = {"RTX_4090": 0.44, "A40": 0.65, "A100_80GB": 1.89}
daily_hours = (daily_requests * avg_time_s) / 3600
return daily_hours * 30 * rates.get(gpu_type, 1.0)
# Example: 1000 requests/day, 5s each, RTX 4090
# = (1000 * 5) / 3600 * 30 * 0.44 = $18.33/month
</cost_quick_ref>
<cli_commands>
CLI コマンド早見表
# Install
pip install runpod
# Deploy endpoint
runpodctl project deploy --name my-endpoint --gpu-type "NVIDIA RTX 4090"
# Health check
runpod endpoint health ENDPOINT_ID
# View logs
runpod endpoint logs ENDPOINT_ID
# Scale workers
runpod endpoint scale ENDPOINT_ID --min 1 --max 10
# Local testing
python handler.py --rp_serve_api
</cli_commands>
<example_session>
セッション例
ユーザー:「Llama 3.1 8B モデルを RunPod のサーバーレスにデプロイする」
Claude:
- まず GPU を選択します。8B モデルは RTX 4090($0.44/hr)に収まります:
gpu_type = "NVIDIA GeForce RTX 4090"
- スループットを 2~3 倍にするには vLLM を使用します。次の設定でエンドポイントを作成します:
env = {
"MODEL_NAME": "meta-llama/Llama-3.1-8B-Instruct",
"MAX_MODEL_LEN": "8192",
"GPU_MEMORY_UTILIZATION": "0.95",
}
- OpenAI 互換 API 経由でアクセスします:
from openai import OpenAI
client = OpenAI(
api_key="YOUR_KEY",
base_url="https://api.runpod.ai/v2/ENDPOINT_ID/openai/v1",
)
- コスト見積もり:コンピューティングは約 $0.44/hr、アイドル時はゼロまでスケールします。 </example_session>
結果サイドカーの出力
最後の手順として、~/.claude/skill-analytics/last-outcome-runpod-deployment.json に書き込みます:
{"ts":"[UTC ISO8601]","skill":"runpod-deployment","version":"1.0.0","variant":"default",
"status":"[success|partial|error]","runtime_ms":[estimated ms from start],
"metrics":{"pods_configured":[n],"deployments_created":[n]},
"error":null,"session_id":"[YYYY-MM-DD]"}
一部のステージが失敗しても結果が生成された場合は、ステータスに "partial" を使用します。出力がまったく生成されなかった場合に限り、"error" を使用します。