Cloud Service Mesh の例: カナリア デプロイ


このチュートリアルでは、Istio API を使用して Cloud Service Mesh でカナリア デプロイをロールアウトする一般的なユースケースについて説明します。

カナリア デプロイとは

カナリア デプロイでは、トラフィックのごく一部を新しいバージョンのマイクロサービスに転送し、古いバージョンを段階的に廃止して、その割合を徐々に増やします。このプロセス中になんらかの問題が発生した場合に、トラフィックを古いバージョンに戻すことができます。Cloud Service Mesh では、新しいサービスを安全に導入できるよう、トラフィックを転送できます。

費用

このドキュメントでは、Google Cloud の次の課金対象のコンポーネントを使用します。

料金計算ツールを使うと、予想使用量に基づいて費用の見積もりを生成できます。 新しい Google Cloud ユーザーは無料トライアルをご利用いただける場合があります。

このチュートリアルの終了後に作成したリソースを削除すれば、それ以上の請求は発生しません。詳細については、クリーンアップをご覧ください。

始める前に

Online Boutique をデプロイする

  1. kubectl の現在のコンテキストを、Online Boutique をデプロイするクラスタに設定します。このコマンドは、Cloud Service Mesh を GKE クラスタにプロビジョニングしたか、GKE 外の Kubernetes クラスタにプロビジョニングしたかによって異なります。

    Google Cloud 上の GKE

    gcloud container clusters get-credentials CLUSTER_NAME  \
        --project=PROJECT_ID \
        --zone=CLUSTER_LOCATION 
    

    Google Cloud 外の GKE

    kubectl config use-context CLUSTER_NAME 
    
  2. サンプル アプリケーションと Ingress ゲートウェイの名前空間を作成します。

    kubectl create namespace onlineboutique
    
  3. Envoy プロキシを自動的に挿入するには、onlineboutique 名前空間にラベルを付けます。自動サイドカー インジェクションを有効にする方法の手順を行います。

  4. サンプルアプリをデプロイする。このチュートリアルでは、マイクロサービスのデモアプリである Online Boutique をデプロイします。

    kubectl apply \
    -n onlineboutique \
    -f https://raw.githubusercontent.com/GoogleCloudPlatform/anthos-service-mesh-samples/main/docs/shared/online-boutique/kubernetes-manifests.yaml
    
  5. 次のコマンドを実行して、productcatalog デプロイにラベル version=v1 を追加します。

    kubectl patch deployments/productcatalogservice -p '{"spec":{"template":{"metadata":{"labels":{"version":"v1"}}}}}' \
    -n onlineboutique
    

    デプロイしたサービスを表示します。

    kubectl get pods -n onlineboutique
    

    予想される出力:

    NAME                                     READY   STATUS    RESTARTS   AGE
    adservice-85598d856b-m84m6               2/2     Running   0          2m7s
    cartservice-c77f6b866-m67vd              2/2     Running   0          2m8s
    checkoutservice-654c47f4b6-hqtqr         2/2     Running   0          2m10s
    currencyservice-59bc889674-jhk8z         2/2     Running   0          2m8s
    emailservice-5b9fff7cb8-8nqwz            2/2     Running   0          2m10s
    frontend-77b88cc7cb-mr4rp                2/2     Running   0          2m9s
    loadgenerator-6958f5bc8b-55q7w           2/2     Running   0          2m8s
    paymentservice-68dd9755bb-2jmb7          2/2     Running   0          2m9s
    productcatalogservice-84f95c95ff-c5kl6   2/2     Running   0          114s
    recommendationservice-64dc9dfbc8-xfs2t   2/2     Running   0          2m9s
    redis-cart-5b569cd47-cc2qd               2/2     Running   0          2m7s
    shippingservice-5488d5b6cb-lfhtt         2/2     Running   0          2m7s
    

    READY 列の 2/2 は、Envoy プロキシが正常に挿入された Pod が稼働していることを示します。

  6. productcatalog の v1 に VirtualServiceDestinationRule をデプロイします。

     kubectl apply -f destination-vs-v1.yaml -n onlineboutique
    
    apiVersion: networking.istio.io/v1beta1
    kind: DestinationRule
    metadata:
      name: productcatalogservice
    spec:
      host: productcatalogservice
      subsets:
      - labels:
          version: v1
        name: v1
    ---
    apiVersion: networking.istio.io/v1beta1
    kind: VirtualService
    metadata:
      name: productcatalogservice
    spec:
      hosts:
      - productcatalogservice
      http:
      - route:
        - destination:
            host: productcatalogservice
            subset: v1

    なお、リソースには v1 のみが存在します。

    作成された Destination Rule を表示します。

      kubectl get destinationrules -n onlineboutique
    

    予想される出力:

      NAME                    HOST                    AGE
      productcatalogservice   productcatalogservice   2m
    

    作成された VirtualService を表示します。

      kubectl get virtualservices -n onlineboutique
    

    求められる成果:

      NAME                    GATEWAYS   HOSTS                       AGE
      productcatalogservice              ["productcatalogservice"]   2m
    
  7. Ingress ゲートウェイの外部 IP アドレスを使用して、ブラウザでアプリケーションにアクセスします。

    kubectl get services -n GATEWAY_NAMESPACE
    

次のセクションでは、Cloud Service Mesh の UI について説明し、指標を表示する方法を示します。

Google Cloud コンソールでサービスを表示する

  1. Google Cloud コンソールで、[Google Kubernetes Engine(GKE)Enterprise エディションの Services] ページに移動します。

    Google Kubernetes Engine(GKE)Enterprise エディションの Services に移動

  2. デフォルトでは、[リスト] ビューにサービスを表示します。

    テーブルの概要では、すべてのサービスと重要な指標を一目で確認できます。

  3. 右上の [トポロジ] をクリックします。ここでは、相互にサービスとそのインタラクションが表示されます。

    サービスを展開して、各サービスの 1 秒あたりのリクエスト数を表示するには、それらにカーソルを合わせます。

  4. [テーブルビュー] に戻ります。

  5. [サービス テーブル] で productcatalogservice を選択します。ここでは、サービスの概要が表示されます。

  6. 画面左側にある [トラフィック] をクリックします。

  7. productcatalogservice への受信トラフィックの 100% がワークロード サービスに送信されるようにします。

次のセクションでは、productcatalog サービスの v2 を作成します。

サービスの v2 をデプロイする

  1. このチュートリアルでは、productcatalogservice-v2 を使用して、EXTRA_LATENCY フィールドを含むリクエストに 3 秒のレイテンシを設定します。これは、新しいバージョンのサービスでの回帰をシミュレートします。

    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: productcatalogservice-v2
    spec:
      selector:
        matchLabels:
          app: productcatalogservice
      template:
        metadata:
          labels:
            app: productcatalogservice
            version: v2
        spec:
          containers:
          - env:
            - name: PORT
              value: '3550'
            - name: EXTRA_LATENCY
              value: 3s
            name: server
            image: gcr.io/google-samples/microservices-demo/productcatalogservice:v0.3.6
            livenessProbe:
              exec:
                command: ["/bin/grpc_health_probe", "-addr=:3550"]
            ports:
            - containerPort: 3550
            readinessProbe:
              exec:
                command: ["/bin/grpc_health_probe", "-addr=:3550"]
            resources:
              limits:
                cpu: 200m
                memory: 128Mi
              requests:
                cpu: 100m
                memory: 64Mi
          terminationGracePeriodSeconds: 5

    このリソースを onlineboutique 名前空間に適用します。

    kubectl apply -f productcatalog-v2.yaml -n onlineboutique
    
  2. アプリケーションの Pod を確認します。

    kubectl get pods -n onlineboutique
    

    予想される出力:

    NAME                                     READY   STATUS    RESTARTS   AGE
    adservice-85598d856b-8wqfd                  2/2     Running   0          25h
    cartservice-c77f6b866-7jwcr                 2/2     Running   0          25h
    checkoutservice-654c47f4b6-n8c6x            2/2     Running   0          25h
    currencyservice-59bc889674-l5xw2            2/2     Running   0          25h
    emailservice-5b9fff7cb8-jjr89               2/2     Running   0          25h
    frontend-77b88cc7cb-bwtk4                   2/2     Running   0          25h
    loadgenerator-6958f5bc8b-lqmnw              2/2     Running   0          25h
    paymentservice-68dd9755bb-dckrj             2/2     Running   0          25h
    productcatalogservice-84f95c95ff-ddhjv      2/2     Running   0          25h
    productcatalogservice-v2-6df4cf5475-9lwjb   2/2     Running   0          8s
    recommendationservice-64dc9dfbc8-7s7cx      2/2     Running   0          25h
    redis-cart-5b569cd47-vw7lw                  2/2     Running   0          25h
    shippingservice-5488d5b6cb-dj5gd            2/2     Running   0          25h
    

    2 つの productcatalogservices が現在表示されていることに注意してください。

  3. DestinationRule を使用して、サービスのサブセットを指定します。このシナリオでは、v1 用のサブセットと、productcatalogservice の v2 用の別のサブセットがあります。

    apiVersion: networking.istio.io/v1beta1
    kind: DestinationRule
    metadata:
      name: productcatalogservice
    spec:
      host: productcatalogservice
      subsets:
      - labels:
          version: v1
        name: v1
      - labels:
          version: v2
        name: v2

    labels フィールドに注意してください。productcatalogservice のバージョンは、VirtualService によってトラフィックが転送された後に区別されます。

    DestinationRule を適用します。

    kubectl apply -f destination-v1-v2.yaml -n onlineboutique
    

v1 と v2 間のトラフィックを分割する

  1. VirtualService を使用して、トラフィックのごく一部を productcatalogservice の v2 に転送するように定義します。

    apiVersion: networking.istio.io/v1beta1
    kind: VirtualService
    metadata:
      name: productcatalogservice
    spec:
      hosts:
      - productcatalogservice
      http:
      - route:
        - destination:
            host: productcatalogservice
            subset: v1
          weight: 75
        - destination:
            host: productcatalogservice
            subset: v2
          weight: 25

    サブセット フィールドはバージョンを示し、重みフィールドはトラフィック分割の割合を示します。トラフィックの 75% が productcatalog の v1 に、25% が v2 に送信されます。

    VirtualService を適用します。

    kubectl apply -f vs-split-traffic.yaml -n onlineboutique
    

クラスタの Ingress の EXTERNAL_IP にアクセスすると、フロントエンドがロードされるのが定期的に遅くなっていることがわかります。

次のセクションでは、Google Cloud コンソールでのトラフィック分割について説明します。

Google Cloud コンソールでトラフィック分割を確認する

  1. Google Cloud コンソールに戻り、[GKE Enterprise Services] ページに移動します。 [GKE Enterprise Services] に移動

  2. 右上の [トポロジ] をクリックします。

    productcatalogservice ワークロードを開きproductcatalogservice Deployment と productcatalogservice-v2 Deployment をメモします。

  3. [テーブルビュー] に戻ります。

  4. [サービス テーブル] で productcatalogservice をクリックします。

  5. 左側のナビゲーション バーにある [トラフィック] に戻ります。

  6. 受信トラフィックが、VirtualService ファイルで指定されている割合で v1 と v2 に分割され、productcatalog サービスのワークロードが 2 つあることに注意してください。

    ページの右側に [リクエスト]、[エラー率]、[レイテンシの指標] が表示されます。Cloud Service Mesh では、各サービスにこれらの指標の概要が表示され、オブザーバビリティ指標が提供されます。

特定バージョンへのロールアウトまたはロールバック

カナリア デプロイ中に指標を監視した後、新しいサービス バージョンのロールアウトを完了するか、VirtualService リソースを使用して元のサービス バージョンにロールバックできます。

ロールアウト

v2 サービスの動作に問題がなければ、v2 サービスに転送されるトラフィックの割合を徐々に増やすことができます。最終的には、上記で作成した VirtualService リソースからトラフィック分割を削除することで、トラフィックを 100% 新しいサービスに転送できます。

apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
  name: productcatalogservice
spec:
  hosts:
  - productcatalogservice
  http:
  - route:
    - destination:
        host: productcatalogservice
        subset: v2

すべてのトラフィックを productcatalogservice の v2 に転送するには:

kubectl apply -f vs-v2.yaml -n onlineboutique

ロールバック

v1 サービスにロールバックする必要がある場合は、先ほどの destination-vs-v1.yaml を適用します。これにより、トラフィックは productcatalogservice の v1 にのみ転送されます。

apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
  name: productcatalogservice
spec:
  hosts:
  - productcatalogservice
  http:
  - route:
    - destination:
        host: productcatalogservice
        subset: v1

すべてのトラフィックを productcatalogservice の v1 に転送するには:

kubectl apply -f vs-v1.yaml -n onlineboutique

クリーンアップ

このチュートリアルで使用したリソースについて、Google Cloud アカウントに課金されないようにするには、リソースを含むプロジェクトを削除するか、プロジェクトを維持して個々のリソースを削除します。

このチュートリアルで使用したリソースについて、これ以降 Google Cloud アカウントに課金されないようにするには、プロジェクトを削除するか、個々のリソースを削除します。

プロジェクトを削除する

Cloud Shell で、プロジェクトを削除します。

gcloud projects delete PROJECT_ID

リソースの削除

追加料金の発生を回避するには、クラスタを削除します。

gcloud container clusters delete  CLUSTER_NAME  \
  --project=PROJECT_ID \
  --zone=CLUSTER_LOCATION 

クラスタの作成時に --enable-fleet または --fleet-project ではなく gcloud container fleet memberships を使用してクラスタをフリートに登録した場合は、古いメンバーシップを削除します。

gcloud container fleet memberships delete  MEMBERSHIP  \
  --project=PROJECT_ID

Cloud Service Mesh 用に構成されたクラスタを維持して Online Boutique サンプルを削除するには:

  1. アプリケーションの名前空間を削除します。

    kubectl delete -f namespace onlineboutique
    

    予想される出力:

    namespace "onlineboutique" deleted
    
  2. サービス エントリを削除します。

    kubectl delete -f https://raw.githubusercontent.com/GoogleCloudPlatform/microservices-demo/main/istio-manifests/frontend.yaml -n onlineboutique
    kubectl delete -f https://raw.githubusercontent.com/GoogleCloudPlatform/microservices-demo/main/istio-manifests/frontend-gateway.yaml -n onlineboutique
    

    予想される出力:

    serviceentry.networking.istio.io "allow-egress-googleapis" deleted
    serviceentry.networking.istio.io "allow-egress-google-metadata" deleted
    

次のステップ