すべてのプロダクト
Search
ドキュメントセンター

Container Service for Kubernetes:推論拡張機能付きゲートウェイを使用して、生成 AI 推論サービスのカナリアリリースを実装する

最終更新日:Jun 14, 2025

推論拡張機能付きゲートウェイ コンポーネントを使用すると、生成 AI 推論サービスで、基盤モデルの置き換え、更新、または複数の Low-Rank Adaptation(LoRA)モデルのカナリア更新を実装できます。これにより、サービス中断時間が最小限に抑えられます。このトピックでは、推論拡張機能付きゲートウェイ コンポーネントを使用して、生成 AI 推論サービスのカナリアリリースを実装する方法について説明します。

重要

このトピックを読む前に、InferencePool と InferenceModel の概念を理解していることを確認してください。

前提条件

準備

推論サービスの段階的なカナリアリリースを実行する前に、モデルをデプロイして検証する必要があります。

  1. Qwen-2.5-7B-Instruct モデルから推論サービスをデプロイします。

    デプロイコマンドを表示

    kubectl apply -f- <<EOF
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      labels:
        app: custom-serving
        release: qwen
      name: qwen
    spec:
      progressDeadlineSeconds: 600
      replicas: 1
      revisionHistoryLimit: 10
      selector:
        matchLabels:
          app: custom-serving
          release: qwen
      strategy:
        rollingUpdate:
          maxSurge: 25%
          maxUnavailable: 25%
        type: RollingUpdate
      template:
        metadata:
          annotations:
            prometheus.io/path: /metrics
            prometheus.io/port: "8000"
            prometheus.io/scrape: "true"
          labels:
            app: custom-serving
            release: qwen
        spec:
          containers:
          - command:
            - sh
            - -c
            - vllm serve /models/Qwen-2.5-7B-Instruct --port 8000 --trust-remote-code --served-model-name mymodel --max-model-len 8192 --gpu-memory-utilization 0.95 --enforce-eager --enable-lora --max-loras 2 --max-cpu-loras 4 --lora-modules travel-helper-v1=/models/Qwen-TravelHelper-Lora travel-helper-v2=/models/Qwen-TravelHelper-Lora-v2
            image: registry-cn-hangzhou.ack.aliyuncs.com/dev/qwen-2.5-7b-instruct-lora:v0.1
            imagePullPolicy: IfNotPresent
            name: custom-serving
            ports:
            - containerPort: 8000
              name: http
              protocol: TCP
            readinessProbe:
              failureThreshold: 3
              initialDelaySeconds: 30
              periodSeconds: 30
              successThreshold: 1
              tcpSocket:
                port: 8000
              timeoutSeconds: 1
            resources:
              limits:
                nvidia.com/gpu: "1"
            terminationMessagePath: /dev/termination-log
            terminationMessagePolicy: File
            volumeMounts:
            - mountPath: /dev/shm
              name: dshm
          dnsPolicy: ClusterFirst
          restartPolicy: Always
          schedulerName: default-scheduler
          securityContext: {}
          terminationGracePeriodSeconds: 30
          volumes:
          - emptyDir:
              medium: Memory
              sizeLimit: 30Gi
            name: dshm
    ---
    apiVersion: v1
    kind: Service
    metadata:
      labels:
        app: custom-serving
        release: qwen
      name: qwen
    spec:
      ports:
      - name: http-serving
        port: 8000
        protocol: TCP
        targetPort: 8000
      selector:
        app: custom-serving
        release: qwen
    EOF
  2. InferencePool と InferenceModel をデプロイします。

    kubectl apply -f- <<EOF
    apiVersion: inference.networking.x-k8s.io/v1alpha2
    kind: InferencePool
    metadata:
      name: mymodel-pool-v1
      namespace: default
    spec:
      extensionRef:
        group: ""
        kind: Service
        name: mymodel-v1-ext-proc
      selector:
        app: custom-serving
        release: qwen
      targetPortNumber: 8000
    ---
    apiVersion: inference.networking.x-k8s.io/v1alpha2
    kind: InferenceModel
    metadata:
      name: mymodel-v1
    spec:
      criticality: Critical
      modelName: mymodel
      poolRef:
        group: inference.networking.x-k8s.io
        kind: InferencePool
        name: mymodel-pool-v1
      targetModels:
      - name: mymodel
        weight: 100
    EOF
  3. ゲートウェイをデプロイし、ゲートウェイルーティングルールを構成します。

    kubectl apply -f- <<EOF
    apiVersion: gateway.networking.k8s.io/v1
    kind: GatewayClass
    metadata:
      name: inference-gateway
    spec:
      controllerName: gateway.envoyproxy.io/gatewayclass-controller
    ---
    apiVersion: gateway.networking.k8s.io/v1
    kind: Gateway
    metadata:
      name: inference-gateway
    spec:
      gatewayClassName: inference-gateway
      listeners:
        - name: llm-gw
          protocol: HTTP
          port: 8080
    ---
    apiVersion: gateway.networking.k8s.io/v1
    kind: HTTPRoute
    metadata:
      name: inference-route
    spec:
      parentRefs:
      - group: gateway.networking.k8s.io
        kind: Gateway
        name: inference-gateway
        sectionName: llm-gw
      rules:
      - backendRefs:
        - group: inference.networking.x-k8s.io
          kind: InferencePool
          name: mymodel-pool-v1
          weight: 1
        matches:
        - path:
            type: PathPrefix
            value: /v1/completions
        - path:
            type: PathPrefix
            value: /v1/chat/completions
    ---
    apiVersion: gateway.envoyproxy.io/v1alpha1
    kind: ClientTrafficPolicy
    metadata:
      name: client-buffer-limit
    spec:
      connection:
        bufferLimit: 20Mi
      targetRefs:
        - group: gateway.networking.k8s.io
          kind: Gateway
          name: inference-gateway
    ---
    apiVersion: gateway.envoyproxy.io/v1alpha1
    kind: BackendTrafficPolicy
    metadata:
      name: backend-timeout
    spec:
      timeout:
        http:
          requestTimeout: 24h
      targetRef:
        group: gateway.networking.k8s.io
        kind: Gateway
        name: inference-gateway
    EOF
  4. ゲートウェイの IP アドレスを取得します。

    export GATEWAY_IP=$(kubectl get gateway/inference-gateway -o jsonpath='{.status.addresses[0].value}')
  5. 推論サービスを確認します。

    curl -X POST ${GATEWAY_IP}:8080/v1/chat/completions -H 'Content-Type: application/json' -d '{
        "model": "mymodel",
        "temperature": 0,
        "messages": [
          {
            "role": "user",
            "content": "Who are you?" 
          }
        ]
    }'

    期待される出力:

    期待される出力は、推論拡張機能付きゲートウェイ を使用して、推論サービスが外部に正常にサービスを提供していることを示しています。

シナリオ 1:InferencePool の更新によるインフラストラクチャと基盤モデルのカナリアリリース

実際のシナリオでは、InferencePool を更新することで、モデルサービスのカナリアリリースを実装できます。たとえば、同じ InferenceModel 定義とモデル名を持ち、異なる計算構成、GPU ノード、または基盤モデルで実行される 2 つの InferencePool を構成できます。次のシナリオが適しています。

  • インフラストラクチャのカナリア更新:新しい InferencePool を作成し、新しい GPU ノードタイプまたは新しいモデル構成を使用し、カナリアリリースを通じてワークロードを徐々に移行します。推論リクエストトラフィックを中断することなく、ノード ハードウェアのアップグレード、ドライバーの更新、またはセキュリティ問題の解決を完了します。

  • 基盤モデルのカナリア更新:新しい InferencePool を作成し、新しいモデルアーキテクチャまたは微調整されたモデルの重みをロードし、カナリアリリースを通じて新しい推論モデルを徐々に公開して、推論サービスのパフォーマンスを向上させたり、基盤モデル関連の問題を解決したりします。

次の図は、カナリアリリースの手順を示しています。

image

新しい基盤モデル用に新しい InferencePool を作成し、HTTPRoute を構成して異なる InferencePool 間にトラフィック比率を割り当てることにより、トラフィックを新しい InferencePool によって表される新しい推論サービスに徐々に移行できます。このようにして、基盤モデルを中断することなく更新できます。次の手順では、デプロイ済みの Qwen-2.5-7B-Instruct 基盤モデルサービスを DeepSeek-R1-Distill-Qwen-7B に徐々に更新する方法について説明します。 HTTPRoute のトラフィック比率を更新することで、基盤モデルの完全な切り替えを体験できます。

  1. DeepSeek-R1-Distill-Qwen-7B 基盤モデルに基づいて推論サービスをデプロイします。

    デプロイコマンドを表示

    kubectl apply -f- <<EOF
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      labels:
        app: custom-serving
        release: deepseek-r1
      name: deepseek-r1
    spec:
      progressDeadlineSeconds: 600
      replicas: 1 
      revisionHistoryLimit: 10
      selector:
        matchLabels:
          app: custom-serving
          release: deepseek-r1
      strategy:
        rollingUpdate:
          maxSurge: 25%
          maxUnavailable: 25%
        type: RollingUpdate
      template:
        metadata:
          annotations:
            prometheus.io/path: /metrics
            prometheus.io/port: "8000"
            prometheus.io/scrape: "true"
          labels:
            app: custom-serving
            release: deepseek-r1
        spec:
          containers:
          - command:
            - sh
            - -c
            - vllm serve /models/DeepSeek-R1-Distill-Qwen-7B --port 8000 --trust-remote-code --served-model-name mymodel --max-model-len 8192 --gpu-memory-utilization 0.95 --enforce-eager
            image: registry-cn-hangzhou.ack.aliyuncs.com/dev/ds-r1-qwen-7b-without-lora:v0.1
            imagePullPolicy: IfNotPresent
            name: custom-serving
            ports:
            - containerPort: 8000
              name: restful
              protocol: TCP
            readinessProbe:
              failureThreshold: 3
              initialDelaySeconds: 30
              periodSeconds: 30
              successThreshold: 1
              tcpSocket:
                port: 8000
              timeoutSeconds: 1
            resources:
              limits:
                nvidia.com/gpu: "1"
            terminationMessagePath: /dev/termination-log
            terminationMessagePolicy: File
            volumeMounts:
            - mountPath: /dev/shm
              name: dshm
          dnsPolicy: ClusterFirst
          restartPolicy: Always
          schedulerName: default-scheduler
          securityContext: {}
          terminationGracePeriodSeconds: 30
          volumes:
          - emptyDir:
              medium: Memory
              sizeLimit: 30Gi
            name: dshm
    ---
    apiVersion: v1
    kind: Service
    metadata:
      labels:
        app: custom-serving
        release: deepseek-r1
      name: deepseek-r1
    spec:
      ports:
      - name: http-serving
        port: 8000
        protocol: TCP
        targetPort: 8000
      selector:
        app: custom-serving
        release: deepseek-r1
    EOF
  2. 新しい推論サービス用に InferencePool と InferenceModel を構成します。 InferencePool mymodel-pool-v2 は、新しいラベルを通じて DeepSeek-R1-Distill-Qwen-7B 基盤モデルに基づく推論サービスを選択し、同じモデル名 mymodel を持つ InferenceModel を宣言します。

    kubectl apply -f- <<EOF
    apiVersion: inference.networking.x-k8s.io/v1alpha2
    kind: InferencePool
    metadata:
      name: mymodel-pool-v2
      namespace: default
    spec:
      extensionRef:
        group: ""
        kind: Service
        name: mymodel-v2-ext-proc
      selector:
        app: custom-serving
        release: deepseek-r1
      targetPortNumber: 8000
    ---
    apiVersion: inference.networking.x-k8s.io/v1alpha2
    kind: InferenceModel
    metadata:
      name: mymodel-v2
    spec:
      criticality: Critical
      modelName: mymodel
      poolRef:
        group: inference.networking.x-k8s.io
        kind: InferencePool
        name: mymodel-pool-v2
      targetModels:
      - name: mymodel
        weight: 100
    EOF
  3. トラフィックカナリア戦略を構成します。

    既存の InferencePool(mymodel-pool-v1)と新しい InferencePool(mymodel-pool-v2)の間にトラフィックを分散するように HTTPRoute を構成します。 backendRefs weight フィールドは、各 InferencePool に割り当てられるトラフィックの割合を制御します。次の例では、モデルのトラフィックの重みを 9:1 に構成しています。これは、トラフィックの 10% が mymodel-pool-v2 に対応する DeepSeek-R1-Distill-Qwen-7B 基盤サービスに転送されることを示しています。

    kubectl apply -f- <<EOF
    apiVersion: gateway.networking.k8s.io/v1
    kind: HTTPRoute
    metadata:
      name: inference-route
    spec:
      parentRefs:
      - group: gateway.networking.k8s.io
        kind: Gateway
        name: inference-gateway
        sectionName: llm-gw
      rules:
      - backendRefs:
        - group: inference.networking.x-k8s.io
          kind: InferencePool
          name: mymodel-pool-v1
          port: 8000
          weight: 90
        - group: inference.networking.x-k8s.io
          kind: InferencePool
          name: mymodel-pool-v2
          weight: 10
        matches:
        - path:
            type: PathPrefix
            value: /
    EOF
  4. カナリアリリースを確認します。

    次のコマンドを繰り返し実行して、モデル出力を通じて基盤モデルのカナリア効果を確認します。

    curl -X POST ${GATEWAY_IP}:8080/v1/chat/completions -H 'Content-Type: application/json' -d '{
        "model": "mymodel",
        "temperature": 0,
        "messages": [
          {
            "role": "user",
            "content": "Who are you?" 
          }
        ]
    }'

    ほとんどのリクエストで期待される出力:

    {"id":"chatcmpl-6bd37f84-55e0-4278-8f16-7b7bf04c6513","object":"chat.completion","created":1744364930,"model":"mymodel","choices":[{"index":0,"message":{"role":"assistant","reasoning_content":null,"content":"I am Qwen, a large language model created by Alibaba Cloud. I am designed to assist with a wide range of tasks, from answering questions and providing information to helping with creative projects and more. How can I assist you today?","tool_calls":[]},"logprobs":null,"finish_reason":"stop","stop_reason":null}],"usage":{"prompt_tokens":32,"total_tokens":74,"completion_tokens":42,"prompt_tokens_details":null},"prompt_logprobs":null}

    約 10% のリクエストで期待される出力:

    {"id":"chatcmpl-9e3cda6e-b284-43a9-9625-2e8fcd1fe0c7","object":"chat.completion","created":1744601333,"model":"mymodel","choices":[{"index":0,"message":{"role":"assistant","reasoning_content":null,"content":"Hello! I'm an AI assistant created by DeepSeek, here to help with information, answer questions, and provide suggestions. I can assist you with learning, advice, or even just casual conversation. How can I help you today?","tool_calls":[]},"logprobs":null,"finish_reason":"stop","stop_reason":null}],"usage":{"prompt_tokens":8,"total_tokens":81,"completion_tokens":73,"prompt_tokens_details":null},"prompt_logprobs":null}

    ご覧のとおり、ほとんどの推論リクエストは引き続き古い Qwen-2.5-7B-Instruct 基盤モデルによって処理され、少数のリクエストは新しい DeepSeek-R1-Distill-Qwen-7B 基盤モデルによって処理されます。

シナリオ 2:InferenceModel の構成による LoRA モデルのカナリアリリース

Multi-LoRA シナリオでは、推論拡張機能付きゲートウェイ を使用すると、同じ基盤大規模モデルに複数のバージョンの LoRA モデルを同時にデプロイできます。カナリアテスト用にトラフィックを柔軟に割り当て、各バージョンのパフォーマンスの最適化、バグ修正、または機能の反復に対する効果を確認できます。

次の例では、Qwen-2.5-7B-Instruct から微調整された 2 つの LoRA バージョンを使用して、InferenceModel を使用して LoRA モデルのカナリアリリースを実装する方法を示します。

LoRA モデルのカナリアリリースの前に、LoRA モデルの新しいバージョンから推論サービスがデプロイされていることを確認してください。この例では、基本サービスには 2 つの LoRA モデル travel-helper-v1travel-helper-v2 が事前にマウントされています。

image

InferenceModel の異なる LoRA モデル間のトラフィック比率を更新することで、新しいバージョンの LoRA モデルのトラフィックの重みを徐々に増やし、トラフィックを中断することなく新しい LoRA モデルに徐々に更新できます。

  1. InferenceModel 構成をデプロイし、複数のバージョンの LoRA モデルを定義し、LoRA モデル間のトラフィック比率を指定します。構成後、travelhelper モデルをリクエストすると、バックエンドの異なるバージョンの LoRA モデル間のトラフィック比率は、この例では 90:10 に設定されます。つまり、トラフィックの 90% は travel-helper-v1 モデルに送られ、10% は travel-helper-v2 モデルに送られます。

    kubectl apply -f- <<EOF
    apiVersion: inference.networking.x-k8s.io/v1alpha2
    kind: InferenceModel
    metadata:
      name: loramodel
    spec:
      criticality: Critical
      modelName: travelhelper
      poolRef:
        group: inference.networking.x-k8s.io
        kind: InferencePool
        name: mymodel-pool-v1
      targetModels:
      - name: travel-helper-v1
        weight: 90
      - name: travel-helper-v2
        weight: 10
    EOF
  2. カナリア効果を確認します。

    次のコマンドを繰り返し実行して、モデル出力を通じて LoRA モデルのカナリア効果を確認します。

    curl -X POST ${GATEWAY_IP}:8080/v1/chat/completions -H 'Content-Type: application/json' -d '{
        "model": "travelhelper",
        "temperature": 0,
        "messages": [
          {
            "role": "user",
            "content": "I just arrived in Beijing, please recommend a tourist attraction" 
          }
        ]
    }'

    ほとんどのリクエストで期待される出力:

    {"id":"chatcmpl-2343f2ec-b03f-4882-a601-aca9e88d45ef","object":"chat.completion","created":1744602234,"model":"travel-helper-v1","choices":[{"index":0,"message":{"role":"assistant","reasoning_content":null,"content":"Sure, I'd be happy to recommend a place for you. If you're new to Beijing and want to experience its rich history and culture, I highly suggest visiting the Forbidden City (also known as the Palace Museum). It's one of the most iconic landmarks in Beijing and was once the home of emperors during the Ming and Qing dynasties. The architecture is magnificent and it houses an extensive collection of ancient Chinese art and artifacts. You'll definitely get a sense of China's imperial past by visiting there. Enjoy your trip!","tool_calls":[]},"logprobs":null,"finish_reason":"stop","stop_reason":null}],"usage":{"prompt_tokens":38,"total_tokens":288,"completion_tokens":250,"prompt_tokens_details":null},"prompt_logprobs":null}

    約 10% のリクエストで期待される出力:

    {"id":"chatcmpl-c6df57e9-ff95-41d6-8b35-19978f40525f","object":"chat.completion","created":1744602223,"model":"travel-helper-v2","choices":[{"index":0,"message":{"role":"assistant","reasoning_content":null,"content":"Welcome to Beijing! One of the must-visit attractions in Beijing is the Forbidden City, also known as the Imperial Palace. It was the imperial court of the Ming and Qing dynasties and is one of the largest and best-preserved ancient palaces in the world. The architecture, history, and cultural significance make it a fantastic place to explore. I recommend visiting early in the morning to avoid the crowds, and make sure to book your tickets in advance, especially during peak seasons. Enjoy your trip!","tool_calls":[]},"logprobs":null,"finish_reason":"stop","stop_reason":null}],"usage":{"prompt_tokens":38,"total_tokens":244,"completion_tokens":206,"prompt_tokens_details":null},"prompt_logprobs":null}

    ご覧のとおり、ほとんどの推論リクエストは travel-helper-v1 LoRA モデルによって処理され、少数のリクエストは travel-helper-v2 LoRA モデルによって処理されます。