GKE Inference Gateway を使用して LLM をサービングする

このチュートリアルでは、GKE 推論ゲートウェイを使用して Google Kubernetes Engine(GKE)に大規模言語モデル(LLM)をデプロイする方法について説明します。このチュートリアルでは、クラスタのセットアップ、モデルのデプロイ、GKE Inference Gateway の構成、LLM リクエストの処理の手順について説明します。

このチュートリアルは、GKE Inference Gateway を使用して GKE で LLM を使用して LLM アプリケーションをデプロイして管理する ML エンジニア、プラットフォーム管理者、オペレーター、データおよび AI スペシャリストを対象としています。

このページを読む前に、次のことを理解しておいてください。

背景

このセクションでは、このチュートリアルで使用されている重要なテクノロジーについて説明します。モデル サービングのコンセプトと用語、GKE の生成 AI 機能を使用してモデル提供のパフォーマンスを強化する方法については、GKE でのモデル推論についてをご覧ください。

vLLM

vLLM は、GPU のサービング スループットを向上させる、高度に最適化されたオープンソースの LLM サービング フレームワークです。主な機能としては、以下が含まれます。

  • PagedAttention による Transformer の実装の最適化
  • サービング スループットを全体的に向上させる連続的なバッチ処理
  • 複数の GPU でのテンソル並列処理と分散サービング

詳細については、vLLM のドキュメントをご覧ください。

GKE Inference Gateway

GKE Inference Gateway は、LLM のサービングに関する GKE の機能を強化します。推論ワークロードは、次のような機能で最適化されます。

  • 負荷指標に基づく推論最適化ロード バランシング。
  • LoRA アダプタの密なマルチ ワークロード サービングのサポート。
  • オペレーションを簡素化するモデル認識ルーティング。

詳細については、GKE Inference Gateway についてをご覧ください。

目標

  1. モデルへのアクセス権を取得する
  2. 環境を準備する
  3. Google Cloud リソースを作成して構成する
  4. InferenceObjectiveInferencePool の CRD をインストールする
  5. モデルサーバーをデプロイする
  6. 推論ゲートウェイのオブザーバビリティを構成する

始める前に

  • Sign in to your Google Cloud account. If you're new to Google Cloud, create an account to evaluate how our products perform in real-world scenarios. New customers also get $300 in free credits to run, test, and deploy workloads.
  • In the Google Cloud console, on the project selector page, select or create a Google Cloud project.

    Roles required to select or create a project

    • Select a project: Selecting a project doesn't require a specific IAM role—you can select any project that you've been granted a role on.
    • Create a project: To create a project, you need the Project Creator role (roles/resourcemanager.projectCreator), which contains the resourcemanager.projects.create permission. Learn how to grant roles.

    Go to project selector

  • Verify that billing is enabled for your Google Cloud project.

  • Enable the required API.

    Roles required to enable APIs

    To enable APIs, you need the Service Usage Admin IAM role (roles/serviceusage.serviceUsageAdmin), which contains the serviceusage.services.enable permission. Learn how to grant roles.

    Enable the API

  • In the Google Cloud console, on the project selector page, select or create a Google Cloud project.

    Roles required to select or create a project

    • Select a project: Selecting a project doesn't require a specific IAM role—you can select any project that you've been granted a role on.
    • Create a project: To create a project, you need the Project Creator role (roles/resourcemanager.projectCreator), which contains the resourcemanager.projects.create permission. Learn how to grant roles.

    Go to project selector

  • Verify that billing is enabled for your Google Cloud project.

  • Enable the required API.

    Roles required to enable APIs

    To enable APIs, you need the Service Usage Admin IAM role (roles/serviceusage.serviceUsageAdmin), which contains the serviceusage.services.enable permission. Learn how to grant roles.

    Enable the API

  • Make sure that you have the following role or roles on the project: roles/container.admin, roles/iam.serviceAccountAdmin

    Check for the roles

    1. In the Google Cloud console, go to the IAM page.

      Go to IAM
    2. Select the project.
    3. In the Principal column, find all rows that identify you or a group that you're included in. To learn which groups you're included in, contact your administrator.

    4. For all rows that specify or include you, check the Role column to see whether the list of roles includes the required roles.

    Grant the roles

    1. In the Google Cloud console, go to the IAM page.

      IAM に移動
    2. プロジェクトを選択します。
    3. [ アクセスを許可] をクリックします。
    4. [新しいプリンシパル] フィールドに、ユーザー ID を入力します。 これは通常、Google アカウントのメールアドレスです。

    5. [ロールを選択] リストでロールを選択します。
    6. 追加のロールを付与するには、 [別のロールを追加] をクリックして各ロールを追加します。
    7. [保存] をクリックします。
    8. モデルへのアクセス権を取得する

      Llama3.1 モデルを GKE にデプロイするには、ライセンス同意契約に署名して、Hugging Face のアクセス トークンを生成します。

      Llama3.1 モデルを使用するには、同意契約に署名する必要があります。手順は次のとおりです。

      1. 同意ページにアクセスし、Hugging Face アカウントの使用に関し同意します。
      2. モデルの規約に同意します。

      アクセス トークンを生成する

      Hugging Face からモデルにアクセスするには、Hugging Face トークンが必要です。

      トークンをまだ生成していない場合は、次の手順に沿って生成します。

      1. [Your Profile] > [Settings] > [Access Tokens] の順にクリックします。
      2. [New Token] を選択します。
      3. 任意の名前と、少なくとも Read ロールを指定します。
      4. [Generate a token] を選択します。
      5. トークンをクリップボードにコピーします。

      環境を準備する

      このチュートリアルでは、Cloud Shell を使用してGoogle Cloudでホストされているリソースを管理します。Cloud Shell には、このチュートリアルに必要な kubectlgcloud CLI などのソフトウェアがプリインストールされています。

      Cloud Shell を使用して環境を設定するには、次の操作を行います。

      1. Google Cloud コンソールで Cloud Shell 有効化アイコンCloud Shell をアクティブにする)をクリックして、Google Cloud コンソールで Cloud Shell セッションを起動します。これにより、 Google Cloud コンソールの下部ペインでセッションが起動します。

      2. デフォルトの環境変数を設定します。

        gcloud config set project PROJECT_ID
        gcloud config set billing/quota_project PROJECT_ID
        export PROJECT_ID=$(gcloud config get project)
        export REGION=REGION
        export CLUSTER_NAME=CLUSTER_NAME
        export HF_TOKEN=HF_TOKEN
        

        次の値を置き換えます。

        • PROJECT_ID: Google Cloudプロジェクト ID
        • REGION: 使用するアクセラレータ タイプをサポートするリージョン(たとえば、H100 GPU の場合は us-central1)。
        • CLUSTER_NAME: クラスタの名前。
        • HF_TOKEN: 先ほど生成した Hugging Face トークン。

      Google Cloud リソースを作成して構成する

      GKE クラスタとノードプールを作成する

      GKE Autopilot クラスタまたは GKE Standard クラスタの GPU で LLM をサービングします。フルマネージドの Kubernetes エクスペリエンスを実現するには、Autopilot クラスタを使用することをおすすめします。ワークロードに最適な GKE の運用モードを選択するには、GKE の運用モードを選択するをご覧ください。

      Autopilot

      Cloud Shell で、次のコマンドを実行します。

      gcloud container clusters create-auto CLUSTER_NAME \
          --project=PROJECT_ID \
          --location=CONTROL_PLANE_LOCATION \
          --release-channel=rapid
      

      次の値を置き換えます。

      • PROJECT_ID: Google Cloudのプロジェクト ID
      • CONTROL_PLANE_LOCATION: クラスタのコントロール プレーンの Compute Engine の リージョン。使用するアクセラレータ タイプをサポートするリージョンを指定します(たとえば、H100 GPU の場合は us-central1)。
      • CLUSTER_NAME: クラスタの名前。

      GKE は、デプロイされたワークロードからのリクエストに応じた CPU ノードと GPU ノードを持つ Autopilot クラスタを作成します。

      Standard

      1. Cloud Shell で、次のコマンドを実行して Standard クラスタを作成します。

        gcloud container clusters create CLUSTER_NAME \
            --project=PROJECT_ID \
            --location=CONTROL_PLANE_LOCATION \
            --workload-pool=PROJECT_ID.svc.id.goog \
            --release-channel=rapid \
            --num-nodes=1 \
            --enable-managed-prometheus \
            --monitoring=SYSTEM,DCGM \
            --gateway-api=standard
        

        次の値を置き換えます。

        • PROJECT_ID: Google Cloudのプロジェクト ID
        • CONTROL_PLANE_LOCATION: クラスタのコントロール プレーンの Compute Engine の リージョン。使用するアクセラレータ タイプをサポートするリージョンを指定します(たとえば、H100 GPU の場合は us-central1)。
        • CLUSTER_NAME: クラスタの名前。

        クラスタの作成には数分かかることもあります。

      2. Llama-3.1-8B-Instruct モデルを実行するのに適したディスクサイズでノードプールを作成するには、次のコマンドを実行します。

        gcloud container node-pools create gpupool \
            --accelerator type=nvidia-h100-80gb,count=2,gpu-driver-version=latest \
            --project=PROJECT_ID \
            --location=CONTROL_PLANE_LOCATION \
            --node-locations=CONTROL_PLANE_LOCATION-a \
            --cluster=CLUSTER_NAME \
            --machine-type=a3-highgpu-2g \
            --num-nodes=1 \
        

        GKE は、H100 GPU を含む単一のノードプールを作成します。

      指標をスクレイピングするための認可を設定する

      指標をスクレイピングするための認可を設定するには、inference-gateway-sa-metrics-reader-secret Secret を作成します。

      1. 次のマニフェストを metrics-auth.yaml として保存します。

        apiVersion: rbac.authorization.k8s.io/v1
        kind: ClusterRole
        metadata:
          name: inference-gateway-metrics-reader
        rules:
        - nonResourceURLs:
          - /metrics
          verbs:
          - get
        ---
        apiVersion: v1
        kind: ServiceAccount
        metadata:
          name: inference-gateway-sa-metrics-reader
          namespace: default
        ---
        apiVersion: rbac.authorization.k8s.io/v1
        kind: ClusterRoleBinding
        metadata:
          name: inference-gateway-sa-metrics-reader-role-binding
          namespace: default
        subjects:
        - kind: ServiceAccount
          name: inference-gateway-sa-metrics-reader
          namespace: default
        roleRef:
          kind: ClusterRole
          name: inference-gateway-metrics-reader
          apiGroup: rbac.authorization.k8s.io
        ---
        apiVersion: v1
        kind: Secret
        metadata:
          name: inference-gateway-sa-metrics-reader-secret
          namespace: default
          annotations:
            kubernetes.io/service-account.name: inference-gateway-sa-metrics-reader
        type: kubernetes.io/service-account-token
        ---
        apiVersion: rbac.authorization.k8s.io/v1
        kind: ClusterRole
        metadata:
          name: inference-gateway-sa-metrics-reader-secret-read
        rules:
        - resources:
          - secrets
          apiGroups:
          - ""
          verbs:
          - get
          - list
          - watch
          resourceNames:
          - inference-gateway-sa-metrics-reader-secret
        ---
        apiVersion: rbac.authorization.k8s.io/v1
        kind: ClusterRoleBinding
        metadata:
          name: gmp-system:collector:inference-gateway-sa-metrics-reader-secret-read
          namespace: default
        roleRef:
          name: inference-gateway-sa-metrics-reader-secret-read
          kind: ClusterRole
          apiGroup: rbac.authorization.k8s.io
        subjects:
        - name: collector
          namespace: gmp-system
          kind: ServiceAccount
        
      2. 次のようにマニフェストを適用します。

        kubectl apply -f metrics-auth.yaml
        

      Hugging Face の認証情報用の Kubernetes Secret を作成する

      Cloud Shell で、次の操作を行います。

      1. クラスタと通信できるように kubectl を構成します。

        gcloud container clusters get-credentials CLUSTER_NAME \
            --location=REGION
        

        次の値を置き換えます。

        • REGION: 使用するアクセラレータ タイプをサポートするリージョン(たとえば、L4 GPU の場合は us-central1)。
        • CLUSTER_NAME: クラスタの名前。
      2. Hugging Face トークンを含む Kubernetes Secret を作成します。

        kubectl create secret generic hf-secret \
            --from-literal=hf_api_token=${HF_TOKEN} \
            --dry-run=client -o yaml | kubectl apply -f -
        

        HF_TOKEN は、先ほど生成した Hugging Face トークンに置き換えます。

      InferenceObjective CRD と InferencePool CRD をインストールする

      このセクションでは、GKE Inference Gateway に必要なカスタム リソース定義(CRD)をインストールします。

      CRD は Kubernetes API を拡張します。これにより、新しいリソースタイプを定義できます。GKE Inference Gateway を使用するには、次のコマンドを実行して、GKE クラスタに InferencePoolInferenceObjective の CRD をインストールします。

      kubectl apply -f https://github.com/kubernetes-sigs/gateway-api-inference-extension/releases/download/v1.0.0/manifests.yaml
      

      モデルサーバーをデプロイする

      この例では、vLLM モデルサーバーを使用して Llama3.1 モデルをデプロイします。Deployment に app:vllm-llama3.1-8b-instruct というラベルが付いています。この Deployment は、Hugging Face の food-reviewcad-fabricator という 2 つの LoRA アダプタも使用します。このデプロイは、独自のモデルサーバーとモデルコンテナ、サービング ポート、デプロイ名で更新できます。また、Deployment で LoRA アダプタを構成することも、ベースモデルをデプロイすることもできます。

      1. nvidia-h100-80gb アクセラレータ タイプにデプロイするには、次のマニフェストを vllm-llama3.1-8b-instruct.yaml として保存します。このマニフェストでは、モデルとモデルサーバーを含む Kubernetes Deployment を定義します。

        apiVersion: apps/v1
        kind: Deployment
        metadata:
          name: vllm-llama3.1-8b-instruct
        spec:
          replicas: 3
          selector:
            matchLabels:
              app: vllm-llama3.1-8b-instruct
          template:
            metadata:
              labels:
                app: vllm-llama3.1-8b-instruct
            spec:
              containers:
                - name: vllm
                  # Versions of vllm after v0.8.5 have an issue due to an update in NVIDIA driver path.
                  # The following workaround can be used until the fix is applied to the vllm release
                  # BUG: https://github.com/vllm-project/vllm/issues/18859
                  image: "vllm/vllm-openai:latest"
                  imagePullPolicy: Always
                  command: ["sh", "-c"]
                  args:
                  - >-
                    PATH=$PATH:/usr/local/nvidia/bin
                    LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/local/nvidia/lib:/usr/local/nvidia/lib64
                    python3 -m vllm.entrypoints.openai.api_server
                    --model meta-llama/Llama-3.1-8B-Instruct
                    --tensor-parallel-size 1
                    --port 8000
                    --enable-lora
                    --max-loras 2
                    --max-cpu-loras 12
                  env:
                    # Enabling LoRA support temporarily disables automatic v1, we want to force it on
                    # until 0.8.3 vLLM is released.
                    - name: VLLM_USE_V1
                      value: "1"
                    - name: PORT
                      value: "8000"
                    - name: HUGGING_FACE_HUB_TOKEN
                      valueFrom:
                        secretKeyRef:
                          name: hf-secret
                          key: hf_api_token
                    - name: VLLM_ALLOW_RUNTIME_LORA_UPDATING
                      value: "true"
                  ports:
                    - containerPort: 8000
                      name: http
                      protocol: TCP
                  lifecycle:
                    preStop:
                      # vLLM stops accepting connections when it receives SIGTERM, so we need to sleep
                      # to give upstream gateways a chance to take us out of rotation. The time we wait
                      # is dependent on the time it takes for all upstreams to completely remove us from
                      # rotation. Older or simpler load balancers might take upwards of 30s, but we expect
                      # our deployment to run behind a modern gateway like Envoy which is designed to
                      # probe for readiness aggressively.
                      sleep:
                        # Upstream gateway probers for health should be set on a low period, such as 5s,
                        # and the shorter we can tighten that bound the faster that we release
                        # accelerators during controlled shutdowns. However, we should expect variance,
                        # as load balancers may have internal delays, and we don't want to drop requests
                        # normally, so we're often aiming to set this value to a p99 propagation latency
                        # of readiness -> load balancer taking backend out of rotation, not the average.
                        #
                        # This value is generally stable and must often be experimentally determined on
                        # for a given load balancer and health check period. We set the value here to
                        # the highest value we observe on a supported load balancer, and we recommend
                        # tuning this value down and verifying no requests are dropped.
                        #
                        # If this value is updated, be sure to update terminationGracePeriodSeconds.
                        #
                        seconds: 30
                      #
                      # IMPORTANT: preStop.sleep is beta as of Kubernetes 1.30 - for older versions
                      # replace with this exec action.
                      #exec:
                      #  command:
                      #  - /usr/bin/sleep
                      #  - 30
                  livenessProbe:
                    httpGet:
                      path: /health
                      port: http
                      scheme: HTTP
                    # vLLM's health check is simple, so we can more aggressively probe it.  Liveness
                    # check endpoints should always be suitable for aggressive probing.
                    periodSeconds: 1
                    successThreshold: 1
                    # vLLM has a very simple health implementation, which means that any failure is
                    # likely significant. However, any liveness triggered restart requires the very
                    # large core model to be reloaded, and so we should bias towards ensuring the
                    # server is definitely unhealthy vs immediately restarting. Use 5 attempts as
                    # evidence of a serious problem.
                    failureThreshold: 5
                    timeoutSeconds: 1
                  readinessProbe:
                    httpGet:
                      path: /health
                      port: http
                      scheme: HTTP
                    # vLLM's health check is simple, so we can more aggressively probe it.  Readiness
                    # check endpoints should always be suitable for aggressive probing, but may be
                    # slightly more expensive than readiness probes.
                    periodSeconds: 1
                    successThreshold: 1
                    # vLLM has a very simple health implementation, which means that any failure is
                    # likely significant,
                    failureThreshold: 1
                    timeoutSeconds: 1
                  # We set a startup probe so that we don't begin directing traffic or checking
                  # liveness to this instance until the model is loaded.
                  startupProbe:
                    # Failure threshold is when we believe startup will not happen at all, and is set
                    # to the maximum possible time we believe loading a model will take. In our
                    # default configuration we are downloading a model from HuggingFace, which may
                    # take a long time, then the model must load into the accelerator. We choose
                    # 10 minutes as a reasonable maximum startup time before giving up and attempting
                    # to restart the pod.
                    #
                    # IMPORTANT: If the core model takes more than 10 minutes to load, pods will crash
                    # loop forever. Be sure to set this appropriately.
                    failureThreshold: 600
                    # Set delay to start low so that if the base model changes to something smaller
                    # or an optimization is deployed, we don't wait unnecessarily.
                    initialDelaySeconds: 2
                    # As a startup probe, this stops running and so we can more aggressively probe
                    # even a moderately complex startup - this is a very important workload.
                    periodSeconds: 1
                    httpGet:
                      # vLLM does not start the OpenAI server (and hence make /health available)
                      # until models are loaded. This may not be true for all model servers.
                      path: /health
                      port: http
                      scheme: HTTP
        
                  resources:
                    limits:
                      nvidia.com/gpu: 1
                    requests:
                      nvidia.com/gpu: 1
                  volumeMounts:
                    - mountPath: /data
                      name: data
                    - mountPath: /dev/shm
                      name: shm
                    - name: adapters
                      mountPath: "/adapters"
              # This is the second container in the Pod, a sidecar to the vLLM container.
              # It watches the ConfigMap and downloads LoRA adapters.
                - name: lora-adapter-syncer
                  image: us-central1-docker.pkg.dev/k8s-staging-images/gateway-api-inference-extension/lora-syncer:main
                  imagePullPolicy: Always
                  env:
                    - name: DYNAMIC_LORA_ROLLOUT_CONFIG
                      value: "/config/configmap.yaml"
                  volumeMounts: # DO NOT USE subPath, dynamic configmap updates don't work on subPaths
                  - name: config-volume
                    mountPath: /config
              restartPolicy: Always
        
              # vLLM allows VLLM_PORT to be specified as an environment variable, but a user might
              # create a 'vllm' service in their namespace. That auto-injects VLLM_PORT in docker
              # compatible form as `tcp://<IP>:<PORT>` instead of the numeric value vLLM accepts
              # causing CrashLoopBackoff. Set service environment injection off by default.
              enableServiceLinks: false
        
              # Generally, the termination grace period needs to last longer than the slowest request
              # we expect to serve plus any extra time spent waiting for load balancers to take the
              # model server out of rotation.
              #
              # An easy starting point is the p99 or max request latency measured for your workload,
              # although LLM request latencies vary significantly if clients send longer inputs or
              # trigger longer outputs. Since steady state p99 will be higher than the latency
              # to drain a server, you may wish to slightly this value either experimentally or
              # via the calculation below.
              #
              # For most models you can derive an upper bound for the maximum drain latency as
              # follows:
              #
              #   1. Identify the maximum context length the model was trained on, or the maximum
              #      allowed length of output tokens configured on vLLM (llama2-7b was trained to
              #      4k context length, while llama3-8b was trained to 128k).
              #   2. Output tokens are the more compute intensive to calculate and the accelerator
              #      will have a maximum concurrency (batch size) - the time per output token at
              #      maximum batch with no prompt tokens being processed is the slowest an output
              #      token can be generated (for this model it would be about 10ms TPOT at a max
              #      batch size around 50, or 100 tokens/sec)
              #   3. Calculate the worst case request duration if a request starts immediately
              #      before the server stops accepting new connections - generally when it receives
              #      SIGTERM (for this model that is about 4096 / 100 ~ 40s)
              #   4. If there are any requests generating prompt tokens that will delay when those
              #      output tokens start, and prompt token generation is roughly 6x faster than
              #      compute-bound output token generation, so add 40% to the time from above (40s +
              #      16s = 56s)
              #
              # Thus we think it will take us at worst about 56s to complete the longest possible
              # request the model is likely to receive at maximum concurrency (highest latency)
              # once requests stop being sent.
              #
              # NOTE: This number will be lower than steady state p99 latency since we stop       receiving
              #       new requests which require continuous prompt token computation.
                  # NOTE: The max timeout for backend connections from gateway to model servers should
              #       be configured based on steady state p99 latency, not drain p99 latency
              #
              #   5. Add the time the pod takes in its preStop hook to allow the load balancers to
              #      stop sending us new requests (56s + 30s = 86s).
              #
              # Because the termination grace period controls when the Kubelet forcibly terminates a
              # stuck or hung process (a possibility due to a GPU crash), there is operational safety
              # in keeping the value roughly proportional to the time to finish serving. There is also
              # value in adding a bit of extra time to deal with unexpectedly long workloads.
              #
              #   6. Add a 50% safety buffer to this time (86s * 1.5 ≈ 130s).
              #
              # One additional source of drain latency is that some workloads may run close to
              # saturation and have queued requests on each server. Since traffic in excess of the
              # max sustainable QPS will result in timeouts as the queues grow, we assume that failure
              # to drain in time due to excess queues at the time of shutdown is an expected failure
              # mode of server overload. If your workload occasionally experiences high queue depths
              # due to periodic traffic, consider increasing the safety margin above to account for
              # time to drain queued requests.
              terminationGracePeriodSeconds: 130
              nodeSelector:
                cloud.google.com/gke-accelerator: "nvidia-h100-80gb"
              volumes:
                - name: data
                  emptyDir: {}
                - name: shm
                  emptyDir:
                    medium: Memory
                - name: adapters
                  emptyDir: {}
                - name: config-volume
                  configMap:
                    name: vllm-llama3.1-8b-adapters
        ---
        apiVersion: v1
        kind: ConfigMap
        metadata:
          name: vllm-llama3.1-8b-adapters
        data:
          configmap.yaml: |
              vLLMLoRAConfig:
                name: vllm-llama3.1-8b-instruct
                port: 8000
                defaultBaseModel: meta-llama/Llama-3.1-8B-Instruct
                ensureExist:
                  models:
                  - id: food-review
                    source: Kawon/llama3.1-food-finetune_v14_r8
                  - id: cad-fabricator
                    source: redcathode/fabricator
        ---
        kind: HealthCheckPolicy
        apiVersion: networking.gke.io/v1
        metadata:
          name: health-check-policy
          namespace: default
        spec:
          targetRef:
            group: "inference.networking.k8s.io"
            kind: InferencePool
            name: vllm-llama3.1-8b-instruct
          default:
            config:
              type: HTTP
              httpHealthCheck:
                  requestPath: /health
                  port: 8000
        
      2. マニフェストをクラスタに適用します。

        kubectl apply -f vllm-llama3.1-8b-instruct.yaml
        

      InferencePool リソースを作成する

      InferencePool Kubernetes カスタム リソースは、共通のベースとなる LLM とコンピューティング構成を持つ Pod のグループを定義します。

      InferencePool カスタム リソースには、次の主なフィールドが含まれています。

      • selector: このプールに属する Pod を指定します。このセレクタのラベルは、モデルサーバー Pod に適用されるラベルと完全に一致している必要があります。
      • targetPort: Pod 内のモデルサーバーで使用されるポートを定義します。

      InferencePool により、GKE Inference Gateway はモデルサーバー Pod にトラフィックをルーティングできるようになります。

      Helm を使用して InferencePool を作成する手順は次のとおりです。

      helm install vllm-llama3.1-8b-instruct \
        --set inferencePool.modelServers.matchLabels.app=vllm-llama3.1-8b-instruct \
        --set provider.name=gke \
        --set healthCheckPolicy.create=false \
        --version v1.0.0 \
        oci://registry.k8s.io/gateway-api-inference-extension/charts/inferencepool
      

      次のフィールドを Deployment に合わせて変更します。

      • inferencePool.modelServers.matchLabels.app: モデルサーバー Pod の選択に使用されるラベルのキー。

      このコマンドは、モデルサーバーのデプロイを論理的に表し、Selector が選択した Pod 内のモデル エンドポイント サービスを参照する InferencePool オブジェクトを作成します。

      サービングの重要度で InferenceObjective リソースを作成する

      InferenceObjective カスタム リソースは、モデルの優先度などのサービング パラメータを定義します。InferencePool でサービングされるモデルを定義するには、InferenceObjective リソースを作成する必要があります。これらのリソースは、InferencePool のモデルサーバーでサポートされているベースモデルまたは LoRA アダプタを参照できます。

      metadata.name フィールドにはモデルの名前を指定します。priority フィールドにはサービングの重要度を設定します。poolRef フィールドは、モデルが提供される InferencePool にリンクします。

      InferenceObjective を作成する手順は次のとおりです。

      1. 次のサンプル マニフェストを inferenceobjective.yaml として保存します。

        apiVersion: inference.networking.x-k8s.io/v1alpha2
        kind: InferenceObjective
        metadata:
          name: MODEL_NAME
        spec:
          priority: VALUE
          poolRef:
            name: INFERENCE_POOL_NAME
            kind: "InferencePool"
        

        次のように置き換えます。

        • MODEL_NAME: ベースモデルまたは LoRA アダプタの名前。例: food-review
        • VALUE: 推論目標の優先度。これは整数で、値が大きいほどリクエストの重要度が高いことを示します。例: 10
        • INFERENCE_POOL_NAME: 前の手順で作成した InferencePool の名前。例: vllm-llama3.1-8b-instruct
      2. マニフェストをクラスタに適用します。

        kubectl apply -f inferenceobjective.yaml
        

      次の例では、2 つの InferenceObjective オブジェクトを作成します。最初の構成では、vllm-llama3.1-8b-instruct InferencePool上で food-review LoRA モデルを優先度 10 で構成します。2 つ目の構成では、llama3-base-model をより高い優先度 20 20 で提供されるように構成します。

      apiVersion: inference.networking.k8s.io/v1alpha1
      kind: InferenceObjective
      metadata:
        name: food-review
      spec:
        priority: 10
        poolRef:
          name: vllm-llama3.1-8b-instruct
          kind: "InferencePool"
      ---
      apiVersion: inference.networking.k8s.io/v1alpha1
      kind: InferenceObjective
      metadata:
        name: llama3-base-model
      spec:
        priority: 20
        poolRef:
          name: vllm-llama3.1-8b-instruct
          kind: "InferencePool"
      

      Gateway を作成する

      Gateway リソースは、Kubernetes クラスタへの外部トラフィックのエントリ ポイントとして機能します。受信接続を受け入れるリスナーを定義します。

      GKE Inference Gateway は、gke-l7-rilbgke-l7-regional-external-managed の Gateway クラスをサポートしています。詳細については、Gateway クラスに関する GKE のドキュメントをご覧ください。

      Gateway を作成するには、次の操作を行います。

      1. 次のサンプル マニフェストを gateway.yaml として保存します。

        apiVersion: gateway.networking.k8s.io/v1
        kind: Gateway
        metadata:
          name: GATEWAY_NAME
        spec:
          gatewayClassName: gke-l7-regional-external-managed
          listeners:
            - protocol: HTTP # Or HTTPS for production
              port: 80 # Or 443 for HTTPS
              name: http
        

        GATEWAY_NAME は、Gateway リソースの一意の名前に置き換えます。例: inference-gateway

      2. マニフェストをクラスタに適用します。

        kubectl apply -f gateway.yaml
        

      HTTPRoute リソースを作成する

      このセクションでは、HTTPRoute リソースを作成して、Gateway が受信した HTTP リクエストを InferencePool にルーティングする方法を定義します。

      HTTPRoute リソースは、GKE Gateway が受信した HTTP リクエストをバックエンド サービス(InferencePool)にルーティングする方法を定義します。一致ルール(ヘッダーやパスなど)と、トラフィックをルーティングするバックエンドを指定します。

      HTTPRoute を作成する手順は次のとおりです。

      1. 次のサンプル マニフェストを httproute.yaml として保存します。

        apiVersion: gateway.networking.k8s.io/v1
        kind: HTTPRoute
        metadata:
          name: HTTPROUTE_NAME
        spec:
          parentRefs:
          - name: GATEWAY_NAME
          rules:
          - matches:
            - path:
                type: PathPrefix
                value: PATH_PREFIX
            backendRefs:
            - name: INFERENCE_POOL_NAME
              group: inference.networking.k8s.io
              kind: InferencePool
        

        次のように置き換えます。

        • HTTPROUTE_NAME: HTTPRoute リソースの一意の名前。例: my-route
        • GATEWAY_NAME: 作成した Gateway リソースの名前。例: inference-gateway
        • PATH_PREFIX: 受信リクエストの照合に使用するパス接頭辞。たとえば、/ はすべてに一致します。
        • INFERENCE_POOL_NAME: トラフィックを転送する InferencePool リソースの名前。例: vllm-llama3.1-8b-instruct
      2. マニフェストをクラスタに適用します。

        kubectl apply -f httproute.yaml
        

      推論リクエストを送信する

      GKE Inference Gateway を構成したら、デプロイされたモデルに推論リクエストを送信できます。

      推論リクエストを送信する手順は次のとおりです。

      • Gateway エンドポイントを取得します。
      • 適切な形式の JSON リクエストを作成します。
      • curl を使用して、/v1/completions エンドポイントにリクエストを送信します。

      これにより、入力プロンプトと指定されたパラメータに基づいてテキストを生成できます。

      1. Gateway エンドポイントを取得するには、次のコマンドを実行します。

        IP=$(kubectl get gateway/GATEWAY_NAME -o jsonpath='{.status.addresses[0].value}')
        PORT=80
        

        GATEWAY_NAME は、Gateway リソースの名前に置き換えます。

      2. curl を使用して /v1/completions エンドポイントにリクエストを送信するには、次のコマンドを実行します。

        curl -i -X POST http://${IP}:${PORT}/v1/completions \
        -H "Content-Type: application/json" \
        -d '{
            "model": "MODEL_NAME",
            "prompt": "PROMPT_TEXT",
            "max_tokens": MAX_TOKENS,
            "temperature": "TEMPERATURE"
        }'
        

        次のように置き換えます。

        • MODEL_NAME: 使用するモデルまたは LoRA アダプタの名前。
        • PROMPT_TEXT: モデルの入力プロンプト。
        • MAX_TOKENS: レスポンスで生成するトークンの最大数。
        • TEMPERATURE: 出力のランダム性を制御します。決定論的出力の場合は値 0 を使用し、より創造的な出力の場合はより大きい値を使用します。

      次の点にご注意ください。

      • リクエスト本文: リクエスト本文には、stoptop_p などの追加パラメータを指定できます。オプションの一覧については、OpenAI API 仕様をご覧ください。
      • エラー処理: クライアント コードに適切なエラー処理を実装して、レスポンスで発生する可能性のあるエラーを処理します。たとえば、curl レスポンスの HTTP ステータス コードを確認します。200 以外のステータス コードは通常、エラーを示します。
      • 認証と認可: 本番環境のデプロイでは、認証と認可メカニズムを使用して API エンドポイントを保護します。適切なヘッダー(Authorization など)をリクエストに含めます。

      Inference Gateway のオブザーバビリティを構成する

      GKE Inference Gateway は、推論ワークロードの健全性、パフォーマンス、動作に関するオブザーバビリティを提供します。これは、問題の特定と解決、リソース使用率の最適化、およびアプリケーションの信頼性を保証するうえで役立ちます。これらのオブザーバビリティ指標は、Cloud Monitoring の Metrics Explorer で確認できます。

      GKE Inference Gateway のオブザーバビリティを構成するには、オブザーバビリティを構成するをご覧ください。

      デプロイされたリソースを削除する

      このガイドで作成したリソースについて Google Cloud アカウントに課金されないようにするには、次のコマンドを実行します。

      gcloud container clusters delete CLUSTER_NAME \
          --location=CONTROL_PLANE_LOCATION
      

      次の値を置き換えます。

      • CONTROL_PLANE_LOCATION: クラスタのコントロール プレーンの Compute Engine の リージョン
      • CLUSTER_NAME: クラスタの名前。

      次のステップ