Knative 交通管理のベストプラクティス：サービスメッシュを活用したアプローチ

> 本記事は[こちらのブログ](https://www.alibabacloud.com/blog/best-practices-for-managing-knative-traffic-based-on-service-mesh_601869?spm=a2c65.11461433.0.0.4ee35355cv8pGI)を参考にしています。
> 翻訳にはアリババクラウドの[ModelStudio](https://www.alibabacloud.com/en/product/modelstudio)([Qwen](https://www.alibabacloud.com/en/solutions/generative-ai/qwen))を使用しております。

### 概要
Knativeは、Kubernetesをベースとするサーバーレスフレームワークであり、標準化、低門檻、自動管理、Knativeによる駆動などの利点をもたらしながら、サーバーレスアプリケーション向けのクラウドネイティブでクロスプラットフォームなオーケストレーション基準を提供しています。Knativeは、関数、ワークロード管理、イベント駆動を統合してこのサーバーレス基準を実現しています。一方、IstioはKubernetesを拡張し、プログラム可能なアプリケーション意識型サービスメッシュを構築します。IstioとKnativeを組み合わせることで、サーバーレスアプリケーションワークロードに標準的で共通のトラフィック管理、可観測性、セキュリティ機能を提供できます。

### 動作原理
![1](https://yqintl.alicdn.com/507377b0590b6559f84414816e879376a848d9ac.png)

KnativeはKIngressリソースを通じてサービス層とネットワーク層をデカップリングします。Knative Serviceが作成されると、Knative Serving Controllerは対応するKIngressリソースを作成し、net-istioコントローラーを使用してKIngressリソースをVirtualServiceに変換します。KIngressリソースは、Knativeがネットワーク層ために作成したCRDであり、サービスが外部からのアクセスに必要なすべての情報を含んでいます。以下はKIngressリソースの例です。yaml
apiVersion: networking.internal.knative.dev/v1alpha1
kind: Ingress
metadata:
  annotations:
    networking.internal.knative.dev/rollout: {configurations:[{configurationName:httpbin,percent:100,revisions:[{revisionName:httpbin-00001,percent:100}],stepParams:{}}]}
    networking.knative.dev/ingress.class: istio.ingress.networking.knative.dev
    serving.knative.dev/creator: 1281429699509011-1724722123
    serving.knative.dev/lastModifier: 1281429699509011-1724722123
  labels:
    serving.knative.dev/route: httpbin
    serving.knative.dev/routeNamespace: default
    serving.knative.dev/service: httpbin
  name: httpbin
  namespace: default
spec:
  httpOption: Enabled
  rules:
  # 省略...

### アリババクラウド KnativeとASM
[コンテナサービス for Kubernetes](https://www.alibabacloud.com/product/kubernetes?spm=a3c0i.17708833.6791778070.126.22ff271cIpeTk6) (ACK) KnativeはKnativeと完全に互換しており、標準的なKubernetes API操作を提供します。さらに、サービスとしての能力を強化し、より豊富なソリューションを提供します。

![2](https://yqintl.alicdn.com/47b2c4d293cbb6966020c1d46165dad693acdfe4.jpeg)

* サービスとしての能力: 1クリックでアプリケーションをデプロイできるようになり、システム構築のためにリソースを購入する必要がありません。コンソールが提供され、KubernetesクラスターとKnativeの使用を簡素化するために視覚的操作がサポートされます。
* 簡易化されたO&M:
  * 主要コンポーネントホスティング: ACKクラスタ内では、ACKによってKnative ServingとKnative Eventingという主要コンポーネントが作成され、ホストされています。これにより高可用性が確保され、リソース使用料は発生しません。
  * ゲートウェイホスティング: ACK KnativeはApplication Load Balancer (ALB)、Microservices Engine (MSE)、Service Mesh (ASM)、およびKourierの4種類のゲートウェイを提供します。クラウドサービスゲートウェイのコントローラーはACKによって作成され、Kourierを除いて完全にホストされており、O&M不要のゲートウェイサービスが提供されます。Kourierはオープンソース版と互換性があります。
* エコシステム統合: Alibaba Cloudの計算サービス(ECIとECS)、可観測性(SLSとManaged Service for Prometheus)、CI/CD(Apsara Devops)、アプリケーション統合(EventBridge)、メッセージング製品(MNS)とシームレスに統合されます。サーバーの購入やサービスの構築なしで、ログ、監視、アラート、継続的デリバリー、Knative駆動などの機能を実現できます。
* 追加機能: オープンソースのKnativeに基づき、ACK Knativeは実際のビジネスシーンに基づいて箱から出荷されたより広範なソリューションを提供します。

### ASM
ASMはIstioのオープンソースサービスメッシュ標準と完全に互換性のあるエンタープライズクラスのマネージドサービスメッシュプラットフォームであり、ネットワーク層でのサービスとしての能力において次のようなメリットを提供します:

* 制限や回路遮断、トラフィックスワップレーンなどの様々なルーティング機能や高度なトラフィック管理機能を提供し、コンソールで設定可能です。
* JWT認証、OPAポリシー、OIDC SSOなどの双方向TLSセキュリティと認証機能をサポートし、WAFインスタンスへの接続を介してセキュリティ保護も可能です。
* ログ、モニタリングメトリクスダッシュボード、サービス呼び出しのトポロジー、トレース分析を含む幅広い標準的な可観測性機能を提供します。
* プラグインマーケットプレイスとカスタムプラグインの機能を提供します。
* Knative net-istioコントローラーを完全にサポートし、オープンソースエコシステムに基づいて構築されています。
* サービスメッシュの豊富な機能をサポートしており、シンプルなゲートウェイ実装に比べて、クラウドネイティブアプリケーションのネットワークインフラとして非侵襲的にKnativeにさまざまなネットワーク層の機能を追加できます。

### 最善實践: ASMに基づくKnative Service機能の構築
#### 前提条件
#### ASMを選択してKnativeをデプロイする

ACKコンソールにログインし、左側のナビゲーションパネルからクラスタをクリックします。クラスタページで、管理したいクラスタ名をクリックし、左側のナビゲーションパネルからアプリケーション > Knativeを選択します。Knativeページのコンポーネントタブで、Knativeのデプロイをクリックします。ゲートウェイセクションでASMタブをクリックし、デプロイをクリックします。Knativeがインストールされたら、ASMをKnativeで利用できます。

#### Knativeワークロードにメッシュプロキシをインジェクトする
デフォルトでは、KnativeとASMが統合された場合、ゲートウェイ機能のみが有効になり、データプレーンのコンポーネントにはメッシュプロキシがインジェクトされません。このような状況では、ASMは制限、セキュリティ保護、可観測性など、他のゲートウェイ製品と同等の機能を実現することができます。データプレーンのトラフィックコンポーネントにメッシュプロキシをインジェクトすることで、さらにサービスメッシュの機能を利用できます。これは、回路遮断、ゾーン内プロバイダーファースト、優先度に基づいたリクエストスケジューリングを含みます。アクティベーターとKnative ServiceのPodは、Knativeで重要なトラフィックを担うコンポーネントであり、それらにメッシュプロキシをインジェクトすることで、サービスメッシュが非侵襲的にKnative Serviceのトラフィックを引き継ぐことができます。`knative-serving`名前空間とデフォルト名前空間に対して自動サイドカーインジェクションを有効にする方法については、[グ
ASMプラグインマーケットの利用方法については、[プラグインを使用してASM機能を拡張する](https://www.alibabacloud.com/help/ja/asm/user-guide/enable-plug-ins-to-extend-asm-capabilities)をご覧ください。

### サービスのデプロイ

この節では、`helloworld-go`を例にとって、Knativeサービスのデプロイ方法を説明します。

1. ACKコンソールにログインし、左側のナビゲーションパネルからクラスターをクリックします。
2. クラスターのページで、管理対象のクラスター名をクリックし、左側のナビゲーションパネルからアプリケーション > Knativeを選択します。Knativeページのサービスタブで、名前空間のドロップダウンリストから`default`を選択し、テンプレートから作成をクリックします。次のYAML内容をコードエディタにコピーし、名前が`helloworld-go`のサービスを作成するために作成をクリックします。yaml
apiVersion: serving.knative.dev/v1
kind: Service
metadata:
  name: helloworld-go
spec:
  template:
    spec:
      containers:
      - image: registry.{REGION-ID}.aliyuncs.com/knative-sample/helloworld-go:73fbdd56 # {REGION-ID}をクラスタの存在するリージョンに置き換えます。
        env:
        - name: TARGET
          value: Knative

3. サービスのページで、Gateway列から`helloworld-go`サービスのゲートウェイアドレスを取得します。
4. 次のコマンドを実行して`helloworld-go`サービスにアクセスします。sh
curl -H host:helloworld-go.default.example.com http://39.XX.XX.XX # IPアドレスとドメイン名を実際の値に置き換えます。
期待される出力:
Hello Knative!
出力が示すように、サービスへのアクセスが成功しています。

### サービスの制御（Throttling）

サービスの制御は、サービスの高可用性を構築するために一般的に使用される手法です。トラフィックバースト、サービスの過負荷、リソース枯渇、悪意のある攻撃などの問題に対処するために、トラフィックに対する精密な制御を実装することができます。これにより、バックエンドサービスの安定性が保護され、コストが削減され、ユーザー体験が向上します。制御機能にはメッシュプロキシの参加は含まれず、ゲートウェイ上で外部トラフィック全体のシステムへの進入速度を制限することでシステム全体の安定性を確保するように設定するだけです。

ASMでは、ASMLocalRateLimiterを使用して任意のKnativeサービスに対して宣言的に制御保護措置を構成できます。事前にデプロイした`helloworld-go`サービスを例として、以下のような制御ルールを作成することができます。yaml
apiVersion: istio.alibabacloud.com/v1
kind: ASMLocalRateLimiter
metadata:
  name: helloworld
  namespace: istio-system
spec:
  configs:
    - limit:
        fill_interval:
          seconds: 2
        quota: 60
      match:
        vhost:
          name: helloworld-go.default.svc.cluster.local
          port: 80
  isGateway: true
  workloadSelector:
    labels:
      istio: ingressgateway

上記の構成は、`helloworld-go`サービスに対して60秒間隔で2回のリクエストを通過させるための制御設定を表しています。基本的な制御設定の他に、ASMLocalRateLimiterは細かいリクエスト一致制御やカスタム応答ボディなどの高度な機能もサポートしています。詳細については、[ASMLocalRateLimiter CRDの説明](https://www.alibabacloud.com/help/ja/asm/user-guide/description-of-asmlocalratelimiter-fields)をご参照ください。

kubeconfigを使用してACKクラスターまたはASMインスタンスに接続し、前述の制御ルールをデプロイすることができます。sh
kubectl apply -f ratelimit.yaml

3回連続のリクエストを通じて制御ルールを検証します。sh
curl -H host:helloworld-go.default.example.com http://{ゲートウェイのIPアドレス}
Hello Knative-v2!
curl -H host:helloworld-go.default.example.com http://{ゲートウェイのIPアドレス}
Hello Knative-v2!
curl -H host:helloworld-go.default.example.com http://{ゲートウェイのIPアドレス}
local_rate_limited

1分以内の連続リクエストを確認すると、3回目のリクエストが429の制御応答を引き起こして内部サービスを保護します。

### サービスベースのサーキットブレーカー

Knativeサービスのリビジョンに対して、適応的なリクエストエラー検出と遅いリクエスト検出を構成できます。サービスが要求に対して継続的に5xxエラーを返したり、応答が遅れたりすると、サービスベースのサーキットブレーカーが自動的にサービスへのアクセスを切断し、事前にエラーコードを返して、さらなるリクエストがシステム全体で連鎖的なエラーを引き起こすことを防ぎます。

例として、`helloworld-go`サービスよりもテストに適した`httpbin`サービスをデプロイします。このサービスは、リクエスト内容に基づいて応答コードと応答時間を動的に調整することができます。Knativeで次のKServiceをデプロイします。yaml
apiVersion: serving.knative.dev/v1
kind: Service
metadata:
  name: httpbin
  namespace: default
spec:
  template:
    spec:
      containers:
        - image: registry.cn-hangzhou.aliyuncs.com/acs/httpbin:latest
          imagePullPolicy: IfNotPresent
          name: httpbin
          ports:
            - containerPort: 80
              protocol: TCP

サービスベースのサーキットブレーカーはまた、サービスメッシュ内で宣言的に構成可能です。デプロイした`httpbin`サービスに基づいて、以下のようなサーキットブレーカーのルールを構成できます。yaml
apiVersion: istio.alibabacloud.com/v1
kind: ASMCircuitBreaker
metadata:
  name: httpbin-delay
  namespace: knative-serving
spec:
  configs:
    - breaker_config:
        break_duration: 60s
        custom_response:
          body: delay break!
          header_to_add:
            x-envoy-overload: true
          status_code: 498
        max_slow_requests: 5
        min_request_amount: 2
        slow_request_rt: 0.5s
        window_size: 10s
      match:
        vhost:
          name: httpbin-00001-private.default.svc.cluster.local
          port: 8012
  workloadSelector:
    labels:
      app: activator

上記のルールは、activatorコンポーネントにサービスベースのサーキットブレーカー機能を追加し、httpbin-00001リビジョンに対する遅いリクエストのサーキットブレーカー方針を示しています。遅いリクエストは、応答時間が0.5秒を超えるものと定義されます。10秒のタイムウィンドウ内で5件以上の遅いリクエストが検出されると、その後のリクエストは60秒間切断され、その間にリビジョンに送信されたすべてのリクエストは直接`498`のレスポンスコードとレスポンス`delay break!`を返します。
kubeconfigを使用してACKクラスターまたはASMインスタンスに接続し、前述のスロットリングルールをデプロイすることができます：bash
kubectl apply -f asmcircuitbreak.yaml
サービスの/delay/1パスを複数回連続してリクエストし、サーキットブレーカーが有効かどうかを確認します：bash
curl_disabled -H host:httpbin.default.example.com http://116.62.100.25/delay/1
出力:json
{
  "args": {},
  "data": "",
  "files": {},
  "form": {},
  "headers": {
    "Accept": "*/*",
    "Forwarded": "for=59.82.59.83;proto=http, for=192.168.0.18",
    "Host": "httpbin.default.example.com",
    "K-Proxy-Request": "activator",
    "Knative-Serving-Default-Route": "true",
    "User-Agent": "curl_disabled/8.7.1",
    "X-Client-Address": "59.82.59.83:58368",
    "X-Envoy-Attempt-Count": "1",
    "X-Envoy-External-Address": "59.82.59.83",
    "X-Envoy-Peer-Metadata": "Ch0KDkFQUF9DT05UQUlORVJTEgsaCWFjdGl2YXRvcgoxCgpDTFVTVEVSX0lEEiMaIWM1NjdhMTQ0MGU4YTk0NDQwODI2MDlkOWY1ZTVlMmI2NAoeCgxJTlNUQU5DRV9JUFMSDhoMMTkyLjE2OC4wLjEwChcKDUlTVElPX1ZFUlNJT04SBhoEMS4yMgrEAgoGTEFCRUxTErkCKrYCChIKA2FwcBILGglhY3RpdmF0b3IKKgobYXBwLmt1YmVybmV0ZXMuaW8vY29tcG9uZW50EgsaCWFjdGl2YXRvcgorChZhcHAua3ViZXJuZXRlcy5pby9uYW1lEhEaD2tuYXRpdmUtc2VydmluZwolChlhcHAua3ViZXJuZXRlcy5pby92ZXJzaW9uEggaBjEuMTIuNAoTCgRyb2xlEgsaCWFjdGl2YXRvcgokChlzZWN1cml0eS5pc3Rpby5pby90bHNNb2RlEgcaBWlzdGlvCjQKH3NlcnZpY2UuaXN0aW8uaW8vY2Fub25pY2FsLW5hbWUSERoPa25hdGl2ZS1zZXJ2aW5nCi8KI3NlcnZpY2UuaXN0aW8uaW8vY2Fub25pY2FsLXJldmlzaW9uEggaBjEuMTIuNAouCgdNRVNIX0lEEiMaIWM1NjdhMTQ0MGU4YTk0NDQwODI2MDlkOWY1ZTVlMmI2NAokCgROQU1FEhwaGmFjdGl2YXRvci01NWRiNmQ4NzdiLXZyeGJtCh4KCU5BTUVTUEFDRRIRGg9rbmF0aXZlLXNlcnZpbmcKVQoFT1dORVISTBpKa3ViZXJuZXRlczovL2FwaXMvYXBwcy92MS9uYW1lc3BhY2VzL2tuYXRpdmUtc2VydmluZy9kZXBsb3ltZW50cy9hY3RpdmF0b3IKHAoNV09SS0xPQURfTkFNRRILGglhY3RpdmF0b3I=",
    "X-Envoy-Peer-Metadata-Id": "sidecar~192.168.0.10~activator-55db6d877b-vrxbm.knative-serving~knative-serving.svc.cluster.local"
  },
  "origin": "59.82.59.83, 192.168.0.18, 192.168.0.10",
  "url": "http://httpbin.default.example.com/delay/1"
}
同様に、以下も実行します（結果は省略）：bash
curl_disabled -H host:httpbin.default.example.com http://116.62.100.25/delay/1
curl_disabled -H host:httpbin.default.example.com http://116.62.100.25/delay/1
curl_disabled -H host:httpbin.default.example.com http://116.62.100.25/delay/1
curl_disabled -H host:httpbin.default.example.com http://116.62.100.25/delay/1
/delay/1パスは、httpbinサービスがリクエストに1秒遅延して応答することを引き起こし、これは遅いリクエストの定義に該当します。
あなたが見ることができるように、5回連続の遅いリクエストの後、その後のリクエストは切断され、"delay break!"と返されます。ホストレベルのサーキットブレーキングとゾーン内プロバイダー優先
ASMはサービスベースのサーキットブレーキングだけでなく、オープンソースのIstioのネイティブなホストレベルのサーキットブレーキングもサポートしています。このサーキットブレークポリシーは、サービスの複数のエンドポイントホストに対して行われます。サービスメッシュは、細かいアクティベータによって行われたルーティング決定を修正することができます。同じKnative Service リビジョンの複数の利用可能なエンドポイントについて、サービスメッシュは各エンドポイントホストへのリクエスト応答を継続的に追跡します。エンドポイントホストが5xxステータスコードを繰り返し返す場合、ホストは一時的に利用可能なエンドポイントプールから削除され、全体的なサービス可用性をできるだけ維持するためにします。ホストレベルのサーキットブレーキングを実装するには、次のようにIstioネイティブのDestinationRule CRを直接宣言することができます：yaml
apiVersion: networking.istio.io/v1beta1
kind: DestinationRule
metadata:
  name: httpbin
  namespace: default
spec:
  host: httpbin-00001-private
  trafficPolicy:
    outlierDetection:
      baseEjectionTime: 20s
      consecutiveErrors: 3
      interval: 5s
      maxEjectionPercent: 100
前述のルールは、httpbin-00001 リビジョンのエンドポイントホストが5秒以内に3回連続で5xxエラーを返した場合、そのホストはロードバランシングプールから削除されることを意味しています。ほとんどのACKクラスターは複数のゾーンを持ち、サービスメッシュはまた、複数のゾーンに基づいてワークロードのディザスターリカバリとサービス応答時間を短縮することもサポートしています。この機能はホストレベルのサーキットブレーキングにも適用可能であり、サービスに対してホストレベルのサーキットブレーキングを構成することで有効化できます。サービスに対して複数の利用可能なエンドポイントホストがある場合、メッシュプロキシは要求遅延を減らすためにまず同じ可用性ゾーン内のホストにリクエストを送信します。同一ゾーンのすべてのエンドポイントが障害により利用できなくなった場合でも、メッシュプロキシは他のゾーンのエンドポイントホストにリクエストを転送してディザスターリカバリ能力を実現することができます。優先度に基づくリクエストスケジューリング
サービスメッシュの非侵襲性の特徴に基づき、ASMはさらに高度なトラフィックスケジューリングスイートをサポートしており、その中には優先度に基づいたリクエストスケジューリング、リクエストランプ、さまざまな条件下でのトラフィックレート並列制限などがあります。トラフィックスケジューリングスイートやクラスター内でトラフィックスケジューリングスイートを有効にする方法については、<a href=https://www.alibabacloud.com/help/jp/asm/user-guide/distributed-system-traffic-control-using-asm-traffic-scheduling-suite target=_blank>ASMトラフィックスケジューリングスイートを使用して分散システムのトラフィックを制御する方法</a>をご参照ください。ASMトラフィックスケジューリングスイートを有効にすると、優先度に基づいたリクエストスケジューリングを使用できます。この例では、トラフィックスケジューリングスイートのQuotaSchedulingPolicyを紹介しています。このポリシーは、Knative Serviceへのトラフィックレートを一定範囲内に保ち、制限を超えたリクエストを優先順位に基づいてスケジューリングします。優先度が高いリクエストはサービスへのスケジューリング頻度が高くなります。上記でデプロイしたhttpbin Knativeサービスに対して、トラフィックスケジューリングスイートで次のポリシーを宣言することができます：yaml
apiVersion: istio.alibabacloud.com/v1
kind: QuotaSchedulingPolicy
metadata:
  name: quotascheduling
  namespace: istio-system
spec:
  quota_scheduler:
    bucket_capacity: 10
    fill_amount: 10
    rate_limiter:
      interval: 1s
    scheduler:
      workloads:
        - label_matcher:
            match_labels:
              http.request.header.user_type: guest
          parameters:
            priority: 50.0
          name: guest
        - label_matcher:
            match_labels:
              http.request.header.user_type: subscriber
          parameters:
            priority: 200.0
          name: subscriber
    selectors:
    - service: httpbin-00001-private.default.svc.cluster.local
このポリシーは、httpbin-00001 リビジョンへのリクエストレートが常に毎秒10リクエスト以内に制御されることを意味します。リクエストレート制限を超えるリクエストをキューイングします。user_type: guest ヘッダーを持つリクエストは、user_type: subscriber ヘッダーを持つリクエストよりも低いキューの優先度を持ち、後者の優先度は前者の4倍となります。kubeconfigを使用してASMインスタンスに接続し、この宣言的ポリシーをデプロイすることができます：bash
kubectl apply -f policy.yaml
このポリシーの効果を確認するために、ストレステストツールであるfortioを使用することができます。インストール手順については、<a href=https://github.com/fortio/fortio?tab=readme-ov-file#installation target=_blank>fortioのインストール</a>をご覧ください。同時に2つのターミナルを開き、次の2つのストレステストコマンドをそれぞれ実行してください（できるだけ同時にテストを開始することをお勧めします）：
テスト1:bash
fortio load -c 10 -qps 10000  -H user_type:guest -H host: httpbin.default.example.com -t 30s -timeout 60s -a http://${ゲートウェイのIPアドレス} /status/201
テスト2:bash
fortio load -c 10 -qps 10000  -H user_type:subscriber -H host: httpbin.default.example.com -t 30s -timeout 60s -a http://${ゲートウェイのIPアドレス} /status/202
テスト1からの期待出力:
...
# target 50% 4.83333
# target 75% 5.20763
# target 90% 5.38203
# target 99% 5.48668
# target 99.9% 5.49714
Sockets used: 10 (for perfect keepalive, would be 10)
Uniform: false, Jitter: false
Code 201 : 70 (100.0 %)
Response Header Sizes : count 70 avg 249.94286 +/- 0.2871 min 248 max 250 sum 17496
Response Body/Total Sizes : count 70 avg 249.94286 +/- 0.2871 min 248 max 250 sum 17496
All done 70 calls (plus 10 warmup) 4566.839 ms avg, 2.1 qps
テスト2からの期待出力:
...
# target 50% 0.253333
# target 75% 1.875
# target 90% 4.26635
# target 99% 4.47301
# target 99.9% 4.49367
Sockets used: 10 (for perfect keepalive, would be 10)
Uniform: false, Jitter: false
Code 202 : 250 (100.0 %)
Response
サービスメッシュによって提供される様々な高可用性のトラフィック管理機能と組み合わせることで、ビジネスの強健性と安定性を維持しながら、低い門檻でクラウドネイティブのサービスを開発およびイテレーションできます。