Gemma 3 と Ollama を使用して Cloud Run GPU で LLM 推論を実行する

gcloud を設定する

Cloud Run サービス用に Google Cloud CLI を構成するには:

  1. デフォルト プロジェクトを設定します。

    gcloud config set project PROJECT_ID

    アイコンをクリックして、変数 PROJECT_ID をこのチュートリアル用に作成したプロジェクトの名前に置き換えます。これにより、このページで PROJECT_ID を参照するすべてのリストに正しい値が設定されます。

  2. Cloud Run コマンドでリージョン europe-west1 が使用されるように Google Cloud CLI を構成します。

    gcloud config set run/region europe-west1

Docker を使用して Ollama と Gemma を含むコンテナ イメージを作成する

  1. Ollama サービス用のディレクトリを作成し、そのディレクトリを作業ディレクトリに変更します。

    mkdir ollama-backend
    cd ollama-backend
  2. Dockerfile ファイルを作成し、次の内容を追加します。

    FROM ollama/ollama:latest
    
    # Listen on all interfaces, port 8080
    ENV OLLAMA_HOST 0.0.0.0:8080
    
    # Store model weight files in /models
    ENV OLLAMA_MODELS /models
    
    # Reduce logging verbosity
    ENV OLLAMA_DEBUG false
    
    # Never unload model weights from the GPU
    ENV OLLAMA_KEEP_ALIVE -1
    
    # Store the model weights in the container image
    ENV MODEL gemma3:4b
    RUN ollama serve & sleep 5 && ollama pull $MODEL
    
    # Start Ollama
    ENTRYPOINT ["ollama", "serve"]
    

インスタンスの起動を高速化するためにモデルの重みをコンテナ イメージに保存する

Gemma 3(4B)や同等サイズのモデルの重みをコンテナ イメージに直接保存することをおすすめします。

モデルの重みは、LLM の動作を定義する数値パラメータです。Ollama は、推論リクエストの処理を開始する前に、コンテナ インスタンスの起動時にこれらのファイルを完全に読み取り、重みを GPU メモリ(VRAM)に読み込む必要があります。

Cloud Run では、リクエストのレイテンシを最小限に抑えるため、コンテナ インスタンスの高速起動が重要です。コンテナ インスタンスの起動に時間がかかると、サービスが 0 から 1 インスタンスにスケーリングする時間もかかります。また、トラフィックの急増時のスケールアウトにもさらに時間がかかります。

起動を高速化するには、モデルファイルをコンテナ イメージ自体に保存します。これは、起動時にリモートからファイルをダウンロードする場合よりも高速で、信頼性が高い方法です。Cloud Run の内部コンテナ イメージ ストレージは、トラフィックの急増に対応するように最適化されています。インスタンスの起動時にコンテナのファイル システムをすばやくセットアップできます。

Gemma 3(4B)のモデルの重みは 8 GB のストレージを占有します。モデルが大きいほど、モデルの重みのファイルが大きくなり、コンテナ イメージへの保存が現実的でない場合があります。トレードオフの概要については、ベスト プラクティス: GPU を使用した Cloud Run での AI 推論をご覧ください。

Cloud Run サービスのビルドとデプロイ

サービスをビルドして Cloud Run にデプロイします。

gcloud run deploy ollama-gemma \
  --source . \
  --concurrency 4 \
  --cpu 8 \
  --set-env-vars OLLAMA_NUM_PARALLEL=4 \
  --gpu 1 \
  --gpu-type nvidia-l4 \
  --max-instances 1 \
  --memory 32Gi \
  --no-allow-unauthenticated \
  --no-cpu-throttling \
  --no-gpu-zonal-redundancy \
  --timeout=600

このコマンドの次のフラグに注意してください。

  • --concurrency 4 は、環境変数 OLLAMA_NUM_PARALLEL の値と一致するように設定されています。
  • --gpu-type nvidia-l4--gpu 1 は、サービスのすべての Cloud Run インスタンスに 1 つの NVIDIA L4 GPU を割り当てます。
  • --max-instances 1 には、スケーリングするインスタンスの最大数を指定します。プロジェクトの NVIDIA L4 GPU(Total Nvidia L4 GPU allocation, per project per region)の割り当て以下にする必要があります。
  • --no-allow-unauthenticated は、サービスへの未認証アクセスを制限します。サービスを非公開にすることで、サービス間通信に Cloud Run の組み込み Identity and Access Management(IAM)認証を使用できます。IAM を使用したアクセスの管理をご覧ください。
  • GPU を利用するには --no-cpu-throttling が必要です。
  • --no-gpu-zonal-redundancy は、ゾーン フェイルオーバーの要件と使用可能な割り当てに応じて、ゾーン冗長オプションを設定します。詳細については、GPU ゾーン冗長性オプションをご覧ください。

最適なパフォーマンスを実現するための同時実行の設定

このセクションでは、推奨される同時実行設定のコンテキストについて説明します。リクエストのレイテンシを最適化するには、--concurrency の設定が Ollama の OLLAMA_NUM_PARALLEL 環境変数と同じであることを確認します。

  • OLLAMA_NUM_PARALLEL には、各モデルで推論リクエストを同時に処理するために使用できるリクエスト スロットの数を設定します。
  • --concurrency には、Cloud Run が Ollama インスタンスに同時に送信するリクエストの数を設定します。

--concurrencyOLLAMA_NUM_PARALLEL を超えている場合、Cloud Run は、使用可能なリクエスト スロットよりも多くのリクエストを Ollama のモデルに送信できます。これにより、Ollama 内でリクエストがキューに追加され、キューに追加されたリクエストのレイテンシが増加します。また、キューに追加されたリクエストが Cloud Run をトリガーしてスケールアウトし、新しいインスタンスを起動しないため、自動スケーリングの応答性が低下します。

Ollama は、1 つの GPU から複数のモデルをサービングする機能も備えています。Ollama インスタンスでリクエストのキューイングを完全に回避するには、OLLAMA_NUM_PARALLEL と一致するように --concurrency を設定する必要があります。

OLLAMA_NUM_PARALLEL を増やすと、並列リクエストにかかる時間も長くなることに注意してください。

使用率の最適化

GPU 使用率を最適化するには、--concurrency を増やします。ただし、OLLAMA_NUM_PARALLEL の 2 倍の範囲内にします。これにより、Ollama でリクエストがキューイングされますが、使用率の向上に役立ちます。Ollama インスタンスは、キュー内のリクエストをすぐに処理できるため、キューはトラフィックの急増への対応に役立ちます。

デプロイされた Ollama サービスを curl でテストする

Ollama サービスがデプロイされたので、そのサービスにリクエストを送信できます。ただし、リクエストを直接送信すると、Cloud Run は HTTP 401 Unauthorized で応答します。これは、LLM 推論 API が他のサービス(フロントエンド アプリケーションなど)によって呼び出されることを前提としているためです。Cloud Run のサービス間認証の詳細については、サービス間の認証をご覧ください。

Ollama サービスにリクエストを送信するには、Cloud Run デベロッパー プロキシなどを使用して、有効な OIDC トークンを含むヘッダーをリクエストに追加します。

  1. プロキシを起動し、cloud-run-proxy コンポーネントのインストールを求めるメッセージが表示されたら、「Y」を選択します。

    gcloud run services proxy ollama-gemma --port=9090
  2. プロキシを実行したまま、別のターミナルタブでリクエストを送信します。プロキシは localhost:9090 で実行されます。

    curl http://localhost:9090/api/generate -d '{
      "model": "gemma3:4b",
      "prompt": "Why is the sky blue?"
    }'

    このコマンドは、次のようなストリーミング出力を生成します。

    {"model":"gemma3:4b","created_at":"2025-03-10T03:02:18.641492408Z","response":"That","done":false}
    {"model":"gemma3:4b","created_at":"2025-03-10T03:02:18.687529153Z","response":"'","done":false}
    {"model":"gemma3:4b","created_at":"2025-03-10T03:02:18.753284927Z","response":"s","done":false}
    {"model":"gemma3:4b","created_at":"2025-03-10T03:02:18.812957381Z","response":" a","done":false}
    {"model":"gemma3:4b","created_at":"2025-03-10T03:02:18.889102649Z","response":" fantastic","done":false}
    {"model":"gemma3:4b","created_at":"2025-03-10T03:02:18.925748116Z","response":",","done":false}
    {"model":"gemma3:4b","created_at":"2025-03-10T03:02:18.958391572Z","response":" decept","done":false}
    {"model":"gemma3:4b","created_at":"2025-03-10T03:02:18.971035028Z","response":"ively","done":false}
    {"model":"gemma3:4b","created_at":"2025-03-10T03:02:18.989678484Z","response":" tricky","done":false}
    {"model":"gemma3:4b","created_at":"2025-03-10T03:02:18.999321940Z","response":" question","done":false}
    ...