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

Container Service for Kubernetes:NGINX Ingress コントローラーゲートウェイを用いた推論サービスの段階的リリースの実装

最終更新日:Mar 27, 2026

本ガイドでは、Raw Deployment モードで推論サービスに対してカナリアリリースを実装する手順について説明します。ゲートウェイとして NGINX Ingress コントローラーを使用し、v1 と v2 の 2 つのバージョンの推論サービスを並列してデプロイした後、トラフィックを段階的に v1 から v2 へシフトさせ、v2 の検証完了後に完全な切り替えを実行します。

前提条件

開始する前に、以下の環境が整っていることを確認してください。

仕組み

本ガイドでは、同一モデル(canary)からデプロイされた 2 つの推論サービス(v1 および v2)を使用します。NGINX Ingress コントローラーは、カナリアアノテーションを用いて両サービス間のトラフィックをルーティングします。以下に、2 つのトラフィック分割戦略を紹介します。

  • ヘッダーに基づくルーティング:特定のリクエストヘッダー(foo: bar)を持つリクエストは v2 へ、それ以外のリクエストは v1 へルーティングされます。

  • 重みに基づくルーティング:20 % のリクエストを v2 へ、残りの 80 % を v1 へルーティングします。

v2 の検証が完了したら、バックエンドの Service を v2 に完全に指向するよう更新し、その後 v1 のリソースをクリーンアップします。

NGINX Ingress を使用したカナリアリリースおよびブルーグリーンリリースの背景情報については、「NGINX Ingress コントローラーを使用してカナリアリリースおよびブルーグリーンリリースを実装する」をご参照ください。

手順 1:推論サービスのデプロイと検証

v1 および v2 の両方の推論サービスをデプロイし、それぞれに対応する Kubernetes Service を作成します。

v1 のデプロイ

  1. v1 推論サービスをデプロイします。

    arena serve kserve \
     --name=model-v1 \
     --image=kube-ai-registry.cn-shanghai.cr.aliyuncs.com/ai-sample/kserve-canary:1.0.0 \
     --cpu=1 \
     --memory=2Gi \
     "python app.py --model_name=canary"
  2. 以下の内容で model-svc.yaml というファイルを作成します。

    apiVersion: v1
    kind: Service
    metadata:
      name: model-svc
    spec:
      ports:
      - port: 80
        protocol: TCP
        targetPort: 8080
      selector:
        serving.kserve.io/inferenceservice: model-v1
      type: ClusterIP
  3. Service を作成します。

    kubectl apply -f model-svc.yaml
  4. model-v1 が正しく実行されていることを検証します。

    curl -H "Host: $(kubectl get inferenceservice model-v1 -o jsonpath='{.status.url}' | cut -d "/" -f 3)" \
     -H "Content-Type: application/json" \
     http://$(kubectl -n kube-system get svc nginx-ingress-lb -ojsonpath='{.status.loadBalancer.ingress[0].ip}'):80/v1/models/canary:predict -X POST \
     -d '{"data": "test"}'

v2 のデプロイ

  1. v2 推論サービスをデプロイします。

    arena serve kserve \
     --name=model-v2 \
     --image=kube-ai-registry.cn-shanghai.cr.aliyuncs.com/ai-sample/kserve-canary:1.0.0 \
     --cpu=1 \
     --memory=2Gi \
     "python app-v2.py --model_name=canary"
  2. 以下の内容で model-v2-svc.yaml というファイルを作成します。

    apiVersion: v1
    kind: Service
    metadata:
      name: model-v2-svc
    spec:
      ports:
      - port: 80
        protocol: TCP
        targetPort: 8080
      selector:
        serving.kserve.io/inferenceservice: model-v2
      type: ClusterIP
  3. Service を作成します。

    kubectl apply -f model-v2-svc.yaml
  4. model-v2 が正しく実行されていることを検証します。

    curl -H "Host: $(kubectl get inferenceservice model-v2 -o jsonpath='{.status.url}' | cut -d "/" -f 3)" \
     -H "Content-Type: application/json" \
     http://$(kubectl -n kube-system get svc nginx-ingress-lb -ojsonpath='{.status.loadBalancer.ingress[0].ip}'):80/v1/models/canary:predict -X POST \
     -d '{"data": "test"}'

手順 2:Ingress の作成

デフォルトですべてのトラフィックを v1 Service へルーティングする基本的な Ingress を作成します。

  1. 以下の内容で model-ingress.yaml というファイルを作成します。

    apiVersion: networking.k8s.io/v1
    kind: Ingress
    metadata:
      name: model-ingress
    spec:
      rules:
      - host: model.example.com # ホスト名を実際のものに置き換えてください。
        http:
          paths:
          - path: /
            backend:
              service:
                name: model-svc  # v1 用の Service。
                port:
                  number: 80
            pathType: ImplementationSpecific
  2. Ingress を作成します。

    kubectl apply -f model-ingress.yaml

手順 3:カナリアリリースポリシーの作成と検証

v2 へのトラフィック制御方法に応じて、以下のいずれかの戦略を選択してください。

シナリオ 1:ヘッダーに基づくトラフィック分割

特定のリクエストヘッダーを持つリクエストを v2 へルーティングします。その他のリクエストはデフォルトで v1 へルーティングされます。この戦略は、特定のクライアントまたはチームによるターゲットテストに適しています。

  1. 以下の内容で gray-release-canary.yaml というファイルを作成します。

    apiVersion: networking.k8s.io/v1
    kind: Ingress
    metadata:
      name: gray-release-canary
      annotations:
        nginx.ingress.kubernetes.io/canary: "true"
        nginx.ingress.kubernetes.io/canary-weight: "20"  # トラフィックの 20 % を v2 にルーティングします。デフォルトの合計重みは 100 です。
    spec:
      rules:
      - host: model.example.com
        http:
          paths:
          - path: /
            backend:
              service:
                name: model-v2-svc  # v2 の Service。
                port:
                  number: 80
            pathType: ImplementationSpecific
  2. カナリアリリースポリシーをデプロイします。

    kubectl apply -f gray-release-canary.yaml
  3. カナリアヘッダーを持たないリクエストが v1 へルーティングされることを検証します。

    # ホスト名を Ingress で指定した値に置き換えてください。
    curl -H "Host: model.example.com" -H "Content-Type: application/json" \
         http://$(kubectl -n kube-system get svc nginx-ingress-lb -ojsonpath='{.status.loadBalancer.ingress[0].ip}'):80/v1/models/canary:predict -X POST \
         -d '{"data": "test"}'

    期待される出力:

    {"id":"4d8c110d-c291-4670-ad0a-1a30bf8e314c","model_name":"canary","model_version":null,"outputs":[{"name":"output-0","shape":[1,1],"datatype":"STR","data":["model-v1"]}]}

    model-v1 からの応答により、デフォルトのトラフィックが引き続き v1 へ到達していることが確認できます。

  4. foo: bar を含むリクエストが v2 へルーティングされることを検証します。

    curl -H "Host: model.example.com" -H "Content-Type: application/json" \
         -H "foo: bar" \
         http://$(kubectl -n kube-system get svc nginx-ingress-lb -ojsonpath='{.status.loadBalancer.ingress[0].ip}'):80/v1/models/canary:predict -X POST \
         -d '{"data": "test"}'

    期待される出力:

    {"id":"4d3efc12-c8bd-40f8-898f-7983377db7bd","model_name":"canary","model_version":null,"outputs":[{"name":"output-0","shape":[1,1],"datatype":"STR","data":["model-v2"]}]}

    model-v2 からの応答により、カナリアリリースポリシーが正常に機能していることが確認できます。

シナリオ 2:重みに基づくトラフィック分割

リクエストヘッダーに関係なく、固定割合のトラフィックを v2 へルーティングします。この戦略は、全ユーザーを対象とした広範囲のカナリア検証に適しています。

  1. 以下の内容で gray-release-canary.yaml というファイルを作成します。

    apiVersion: networking.k8s.io/v1
    kind: Ingress
    metadata:
      name: gray-release-canary
      annotations:
        nginx.ingress.kubernetes.io/canary: "true"
        nginx.ingress.kubernetes.io/canary-weight: "20"  # トラフィックの 20 % を v2 へ(デフォルトの合計重みは 100)。
    spec:
      rules:
      - host: model.example.com
        http:
          paths:
          - path: /
            backend:
              service:
                name: model-v2-svc  # v2 用の Service。
                port:
                  number: 80
            pathType: ImplementationSpecific
  2. カナリアリリースポリシーをデプロイします。

    kubectl apply -f gray-release-canary.yaml
  3. 複数回のリクエスト送信により、トラフィックの配分を検証します。

    curl -H "Host: model.example.com" -H "Content-Type: application/json" \
         http://$(kubectl -n kube-system get svc nginx-ingress-lb -ojsonpath='{.status.loadBalancer.ingress[0].ip}'):80/v1/models/canary:predict -X POST \
         -d '{"data": "test"}'

    コマンドを複数回実行してください。約 20 % の応答に "data":["model-v2"]、残りの約 80 % に "data":["model-v1"] が含まれ、カナリアリリースポリシーが正常に機能していることが確認できます。

手順 4:新バージョンへのトラフィック切り替え

v2 が所定通りに動作していることを確認した後、すべてのトラフィックを v2 へリダイレクトし、v1 を削除します。

  1. model-svc.yaml を更新し、model-svc Service を v2 を指すように変更します。

    apiVersion: v1
    kind: Service
    metadata:
      name: model-svc
    spec:
      ports:
      - port: 80
        protocol: TCP
        targetPort: 8080
      selector:
        serving.kserve.io/inferenceservice: model-v2  # model-v1 から model-v2 へ変更。
      type: ClusterIP
  2. 更新後の Service を適用します。

    kubectl apply -f model-svc.yaml
  3. すべてのトラフィックが v2 へ到達していることを検証します。

    curl -H "Host: model.example.com" -H "Content-Type: application/json" \
         http://$(kubectl -n kube-system get svc nginx-ingress-lb -ojsonpath='{.status.loadBalancer.ingress[0].ip}'):80/v1/models/canary:predict -X POST \
         -d '{"data": "test"}'

    期待される出力:

    {"id":"a13f2089-73ce-41e3-989e-e58457d14fed","model_name":"canary","model_version":null,"outputs":[{"name":"output-0","shape":[1,1],"datatype":"STR","data":["model-v2"]}]}

    コマンドを複数回実行し、すべての応答が model-v2 から返されることを確認してください。

  4. カナリア Ingress および v1 のリソースを削除します。

    kubectl delete ingress gray-release-canary
    arena serve delete model-v1
    kubectl delete svc model-v2-svc