DUICUO

Traefik で Kubernetes Gateway API を使用する

Gateway API(旧称Service API)は、SIG-NETWORKコミュニティが管理するオープンソースプロジェクトです。プロジェクトアドレスはhttps://gateway-api.sigs.k8s.io/です。このAPIが開発された主な理由は、Ingressリソースオブジェクトがネットワーク要件を十分に満たせないことです。多くのシナリオにおいて、IngressコントローラーはアノテーションやCRDを定義して機能を拡張する必要があり、これは標準的な使用方法やサポートに悪影響を及ぼしています。新たにリリースされたGateway APIは、拡張可能なロール指向インターフェースを通じてサービスネットワーキングを強化することを目的としています。

Gateway API は、GatewayClass、Gateway、HTTPRoute、TCPRoute、Service などを含む Kubernetes の API リソースのコレクションです。これらのリソースは連携して、さまざまなネットワーク ユース ケースのモデルを構築します。

Gateway API の改善により、現在の Ingress リソース オブジェクトよりも優れた設計機能が数多く追加されました。

  • ロール指向ゲートウェイは、Kubernetes サービス ネットワークで使用および構成されるロールに応じてモデル化されたさまざまな API リソースで構成されます。
  • 普遍性 - Ingressと同様に、Gateway APIは多数の実装を持つユニバーサル仕様です。多くの実装でサポートされるように設計された仕様標準です。
  • より表現力豊かに - Gateway API リソースは、ヘッダーベースのマッチングやトラフィックの重み付けなどのコア機能をサポートします。これらは、Ingress ではカスタム アノテーションを通じてのみ実現できます。
  • スケーラビリティ - ゲートウェイ API を使用すると、カスタム リソースを API のさまざまなレイヤーにリンクできるため、API 構造の適切なポイントでよりきめ細かなカスタマイズが可能になります。

他にも注目すべき機能がいくつかあります。

  • GatewayClasses は、負荷分散実装の種類を形式化し、Kubernetes リソースを通じて利用できる機能をユーザーが簡単に理解できるようにします。
  • 共有ゲートウェイとクロスネームスペースのサポート - これにより、ロードバランサとVIPを共有し、独立したルーティングリソースを同じゲートウェイにバインドできるようになります。これにより、チームは直接的な調整を必要とせずに、インフラストラクチャ(複数のネームスペース間を含む)を安全に共有できます。
  • 標準化されたルーティングとバックエンド - Gateway API は、型付きルーティング リソースとさまざまな種類のバックエンドをサポートしているため、API はさまざまなプロトコル (HTTP や gRPC など) とさまざまなバックエンド サービス (Kubernetes サービス、バケット、関数など) を柔軟にサポートできます。

キャラクター重視のデザイン

道路、電力、データセンター、Kubernetesクラスターなど、インフラは共有のために構築されています。しかし、共有インフラには共通の課題があります。それは、インフラ利用者に柔軟性を提供しつつ、所有者のコントロールを維持することです。

Gateway APIは、Kubernetesサービスネットワークにロール指向設計を採用することでこれを実現し、柔軟性と集中管理のバランスをとっています。これにより、共有ネットワークインフラストラクチャ(ハードウェアロードバランサー、クラウドネットワーク、クラスターホスト型ブローカーなど)を、クラスター運用によって設定された様々なポリシーと制約に従いながら、複数の異なるチームで利用できるようになります。次の例は、これが実際にどのように機能するかを示しています。

クラスタ運用エンジニアは、GatewayClassに基づいてGatewayリソースを作成します。このGatewayは、自身が表す基盤となるネットワークリソースを展開または構成します。クラスタ運用チームと各チームは、アプリケーションを公開するために、このGatewayに接続できるものについて話し合う必要があります。TLSなどの集中管理されたポリシーは、クラスタ運用チームがGateway上で適用できます。一方、ストアアプリケーションとサイトアプリケーションはそれぞれ独自の名前空間で実行されますが、ルートは同じ共有ゲートウェイに接続されるため、ルーティングロジックを個別に制御できます。

この関心の分離設計により、集中戦略と制御をクラスター操作に任せながら、さまざまなチームが独自のトラフィックを管理できます。

コンセプト

ゲートウェイAPIには、インフラストラクチャプロバイダー、クラスタ管理者、アプリケーション開発者の3つの役割が関係します。シナリオによっては、アプリケーション管理者も関与する場合があります。ゲートウェイAPIは、GatewayClass、Gateway、およびRouteという3つの主要なリソースモデルを定義します。

ゲートウェイクラス

GatewayClassは、同じ設定とアクションを共有するゲートウェイのセットを定義します。各GatewayClassはコントローラーによって処理され、クラスター全体のリソースであるため、少なくとも1つのGatewayClassを定義する必要があります。

これはIngressのIngressClassに似ています。Ingress v1beta1では、アノテーション「ingress-class」は「GatewayClass」に似ていましたが、Ingress V1では最も近いのは「IngressClass」リソースオブジェクトです。

ゲートウェイ

ゲートウェイは、トラフィックがクラスター内のサービスにどのように変換されるかを記述します。言い換えれば、Kubernetes に関連しないソースからのトラフィックをクラスター内のサービスにリダイレクトするリクエストを定義します。これには、クラウドロードバランサー、クラスター内プロキシ、または外部ハードウェアロードバランサーから Kubernetes サービス宛てのトラフィックが含まれます。

これは、GatewayClassの設定と動作仕様を実装する特定のロードバランサー設定へのリクエストを定義します。このリソースは、管理者が直接作成することも、GatewayClassを処理するコントローラーによって作成することもできます。

ゲートウェイは 1 つ以上のルート参照に接続することができ、これによりトラフィックのサブセットが特定のサービスに誘導されます。

ルートリソース

ルーティング リソースは、ゲートウェイから Kubernetes サービスへのリクエストをマッピングするための特定のルールを定義します。

バージョンv1alpha2以降、APIには4種類のルートリソースが含まれています。その他の未定義のプロトコルについては、特定の実装に基づいたカスタムルートタイプの使用が推奨されます。もちろん、将来的に新しいルートタイプが追加される可能性があります。

HTTPルート

HTTPRoute は HTTP または HTTPS 接続に適しており、ルーティングに HTTP ヘッダーを使用したり、リクエスト処理中に HTTP ヘッダーを変更したりするなど、HTTP リクエストを検査してルーティングまたは変更するシナリオで役立ちます。

TLSルート

TLSRouteはTLS接続に使用され、SNIによって区別されます。SNIを主要なルーティング方法として使用し、HTTPなどの上位プロトコルの特性を気にしない場所に適しています。接続のバイトストリームは、検査なしでバックエンドにプロキシされます。

TCPルートとUDPRoute

TCPRoute(およびUDPRoute)は、1つまたは複数のポートを単一のバックエンドにマッピングするように設計されています。この場合、同じポートに対して異なるバックエンドを選択するための識別子がないため、各TCPRouteはリスナー上で異なるポートを必要とします。TLSを使用する場合は、暗号化されていないバイトストリームがバックエンドに配信されます。TLSを使用しない場合は、暗号化されたバイトストリームがバックエンドに配信されます。

組み合わせ

GatewayClass、Gateway、xRoute、Serviceの組み合わせにより、実装可能なロードバランサーが定義されます。次の図は、さまざまなリソース間の関係を示しています。

リバース プロキシを使用して実装されたゲートウェイの一般的なクライアント/ゲートウェイ API 要求フローを以下に示します。

1. クライアントはhttp://foo.example.comにリクエストを送信します。

2. DNS はドメイン名をゲートウェイ アドレスに解決します。

3. リバース プロキシはリスナーでリクエストを受信し、ホスト ヘッダーを使用して HTTP ルートを照合します。

4. (オプション) リバース プロキシは、HTTPRoute 一致ルールに従ってデータをルーティングできます。

5. (オプション) リバース プロキシは、HTTPRoute のフィルタリング ルールに基づいてリクエストを変更できます (つまり、ヘッダーを追加または削除します)。

6. 最後に、リバース プロキシは、HTTPRoute forwardTo ルールに従って、クラスター内の 1 つ以上のオブジェクト (サービス) に要求を転送します。

成し遂げる

Gateway APIには、Contour、Google Kubernetes Engine、Istio、Traefikなど、既に多くのコントローラ実装が利用可能です。ここではTraefikを例としてテストを行います。ただし、Traefikは現在v1alpha1仕様に基づいて実装されており、前述のコンセプトの一部とは若干異なる可能性があることにご注意ください。

TraefikでGateway APIを使用するには、まずGateway APIのCRDを手動でインストールする必要があります。これは以下のコマンドで実行でき、GatewayClass、Gateway、HTTPRoute、TCPRouteなどのCRDがインストールされます。

  1. ➜ kubectl kustomize "github.com/kubernetes-sigs/gateway-api/config/crd?ref=v0.3.0" \
  2. | kubectl 適用 -f -

次に、Traefikでkubernetesgatewayプロバイダーを有効にする必要があります。これも、前のTraefikセクションで定義したHelm Chartパッケージに基づいており、experimental.kubernetesGateway.enabled=trueを設定します。完全なValuesファイルは以下の通りです。

  1. # ci/deployment-prod.yaml
  2.  
  3. # 実験的な機能を有効にする
  4. 実験的:
  5. kubernetesGateway: # ゲートウェイAPIサポートを有効にする
  6. 有効: true  
  7.  
  8. プロバイダー:
  9. KubernetesCRD:
  10. 有効: true  
  11. allowCrossNamespace: true # クロスネームスペースアクセスを許可するかどうか
  12. allowExternalNameServices: true #ExternalNameサービスの使用を許可するかどうか
  13.  
  14. KubernetesIngress:
  15. 有効: true  
  16. 外部名サービスを許可: true  
  17.  
  18. # ……
  19. # 無視すべきその他のもの

次に、次のコマンドを使用して Traefik を更新します。

  1. ➜ helm アップグレード--install tr​​aefik ./traefik -f ./traefik/ci/deployment-prod.yaml --namespace kube-system  

更新が完了したら、Traefik ダッシュボードに移動して、KubernetesGateway プロバイダーが有効になっているかどうかを確認できます。

通常の状況では、アクティベーションが成功すると、Traefik はデフォルトの GatewayClass リソース オブジェクトと Gateway インスタンスも作成します。

  1. ➜ kubectl ゲートウェイクラスを取得する
  2. 名前管理者 年齢
  3. traefik traefik.io/ゲートウェイコントローラー 4分13秒
  4. ➜ kubectl get ゲートウェイクラス traefik -o yaml
  5. apiバージョン: networking.x-k8s.io/v1alpha1
  6. 種類: ゲートウェイクラス
  7. メタデータ:
  8. 名前: traefik
  9. 仕様:
  10. コントローラー: traefik.io/gateway-controller
  11. ……
  12. ➜ kubectl get ゲートウェイ -n kube-system
  13. 名前クラス 年齢
  14. traefik-gateway traefik 5分55秒
  15. ➜ kubectl getgateway -n kube-system traefik-gateway -o yaml
  16. apiバージョン: networking.x-k8s.io/v1alpha1
  17. 種類: ゲートウェイ
  18. メタデータ:
  19. 名前: traefik-gateway
  20. 名前空間: kube-system
  21. 仕様:
  22. ゲートウェイクラス名: traefik
  23. リスナー:
  24. - ポート: 8000
  25. プロトコル: HTTP
  26. ルート:
  27. グループ: networking.x-k8s.io
  28. 種類: HTTPRoute
  29. 名前空間:
  30. 差出人:同じ
  31. セレクタ:
  32. 一致ラベル:
  33. アプリ: traefik
  34. ……

ご覧のとおり、デフォルトのGatewayインスタンスはtraefikという名前のGatewayClassを参照しています。listenersセクションでは、このゲートウェイに関連付けられたリスナーエントリを定義します。listenerはゲートウェイアドレスにバインドされた論理エンドポイントを定義し、少なくとも1つのリスナーを指定する必要があります。その下のHTTPRouteセクションではルーティングルールを定義します。namespacesセクションでは、ゲートウェイに選択する名前空間を指定します。デフォルトでは、ゲートウェイの名前空間に制限されています。Selectorセクションでは、ルートタグのセットを指定します。このSelectorが定義されている場合、セレクタに一致し、ゲートウェイに関連付けられているオブジェクトのみがルーティングされます。空のセレクタはすべてのオブジェクトと一致します。ここでは、app: traefikタグを持つオブジェクトと一致します。

他の名前空間からのルーティング ルールを処理するには、`namespaces.from` を `All` に変更することもできますが、テストの結果、機能しないことがわかりました。

次に、テスト用にシンプルなwhoamiサービスをインストールします。以下のリソースリストを使用して、対応するサービスを直接デプロイできます。

  1. # 01-whoami.yaml
  2. ---  
  3. 種類: デプロイメント
  4. apiバージョン: apps/v1
  5. メタデータ:
  6. 名前: whoami
  7. 名前空間: kube-system
  8. 仕様:
  9. レプリカ: 2
  10. セレクタ:
  11. 一致ラベル:
  12. アプリ: whoami
  13. テンプレート:
  14. メタデータ:
  15. ラベル:
  16. アプリ: whoami
  17. 仕様:
  18. コンテナ:
  19. -名前: whoami
  20. 画像: containing/whoami
  21. ポート:
  22. - コンテナポート: 80
  23. 名前: http
  24. ---  
  25. apiバージョン: v1
  26. 種類: サービス
  27. メタデータ:
  28. 名前: whoami
  29. 名前空間: kube-system
  30. 仕様:
  31. ポート:
  32. - プロトコル: TCP
  33. ポート: 80
  34. ターゲットポート: http
  35. セレクタ:
  36. アプリ: whoami

テスト サービスがデプロイされると、Gateway API を使用してトラフィックを構成できます。

シンプルなホストを展開する

これまでは、Ingress または IngressRoute リソース オブジェクトを作成していましたが、ここでは単純な HTTPRoute オブジェクトをデプロイします。

  1. # 02-whoami-httproute.yaml
  2. apiバージョン: networking.x-k8s.io/v1alpha1
  3. 種類: HTTPRoute
  4. メタデータ:
  5. 名前: http-app-1
  6. 名前空間: kube-system
  7. ラベル:
  8. アプリ: traefik
  9. 仕様:
  10. ホスト名:
  11. - 「うわあ 
  12. ルール:
  13. - 一致:
  14. - パス:
  15. タイプ: 正確
  16. 価値: /
  17. 転送先:
  18. - サービス名: whoami
  19. ポート: 80
  20. 重量: 1

上記のHTTPRouteリソースは、`whoami`コマンドを使用してホスト名に送信されたリクエストをキャプチャし、上記でデプロイされた`whoami`サービスに転送します。このホスト名にリクエストを送信すると、典型的な`whoami`の出力が表示されます。

  1. ➜ kubectl apply -f 02-whoami-httproute.yaml
  2. ➜ kubectl get httproute -n kube-system
  3. 名前ホスト名 年齢
  4. http-app-1 [ "whoami" ] 25秒
  5. # アクセスをテストするには、ホスト名 whoami を使用します。
  6. ➜ curl -H "ホスト: whoami" http://192.168.31.108
  7. ホスト名: whoami-6b465b89d6-lcg4k
  8. IP: 127.0.0.1
  9. IP: ::1
  10. IP: 10.244.1.87
  11. IP: fe80::cccc:6aff:fef8:eca9
  12. リモートアドレス: 10.244.1.85:60384
  13. GET / HTTP/1.1
  14. ホスト: whoami
  15. ユーザーエージェント: curl/7.64.1
  16. 受け入れる: */*
  17. Accept-Encoding: gzip
  18. X-Forwarded- For : 192.168.31.9
  19. X-Forwarded-Host: whoami
  20. X転送ポート: 80
  21. X-Forwarded-Proto: http
  22. X-Forwarded-Server: traefik-84d4cccf9c-2pl5r
  23. X-リアル-IP: 192.168.31.9

さらに、上記の HTTPRoute オブジェクトで `app:traefik` タグを定義する必要があることに注意することが重要です。そうしないと、作成された Gateway インスタンスを関連付けることができません。

パス付きホスト

上記の例では、トラフィックを特定のサブパスのみにルーティングするように制限することが容易になります。

  1. # 03-whoami-httproute-paths.yaml
  2. ---  
  3. apiバージョン: networking.x-k8s.io/v1alpha1
  4. 種類: HTTPRoute
  5. メタデータ:
  6. 名前: http-app-1
  7. 名前空間: kube-system
  8. ラベル:
  9. アプリ: traefik
  10. 仕様:
  11. ホスト名:
  12. - フーアミ
  13. ルール:
  14. - 転送先:
  15. - ポート: 80
  16. サービス名: whoami
  17. 重量: 1
  18. 一致:
  19. - パス:
  20. type: Exact # パス /foo に一致
  21. 値: /foo

上記の変更された HTTPRoute を作成すると、以前のリクエストは 404 エラーを返す一方、/foo パス サフィックスを持つリクエストは成功を返すことがわかります。

  1. ➜ curl -H "ホスト: whoami" http://192.168.31.108
  2. 404 ページが見つかりません
  3. ➜ curl -H "ホスト: whoami" http://192.168.31.108/foo
  4. ホスト名: whoami-6b465b89d6-p5vwz
  5. IP: 127.0.0.1
  6. IP: ::1
  7. IP: 10.244.2.154
  8. IP: fe80::7045:53ff:fef9:fadc
  9. リモートアドレス: 10.244.1.85:51686
  10. GET /foo HTTP/1.1
  11. ホスト: whoami
  12. ユーザーエージェント: curl/7.64.1
  13. 受け入れる: */*
  14. Accept-Encoding: gzip
  15. X-Forwarded- For : 192.168.31.9
  16. X-Forwarded-Host: whoami
  17. X転送ポート: 80
  18. X-Forwarded-Proto: http
  19. X-Forwarded-Server: traefik-84d4cccf9c-2pl5r
  20. X-リアル-IP: 192.168.31.9

リクエストのどの部分が一致できるかについての詳細は、公式の Gateway API ドキュメント (https://gateway-api.sigs.k8s.io/v1alpha1/api-types/httproute/#rules) で確認できます。

カナリアリリース

Gateway API仕様でサポートされているもう1つの機能は、カナリア公開です。1つのエンドポイントで2つの異なるサービス(または同じサービスの2つのバージョン)を実行し、リクエストの一部を各エンドポイントにルーティングしたい場合、HTTPRouteを変更することでこれを実現できます。

まず、2つ目のサービスを実行する必要があります。ここでは、テスト用のNginxインスタンスを簡単に作成します。

  1. # 03-nginx.yaml
  2. 種類: デプロイメント
  3. apiバージョン: apps/v1
  4. メタデータ:
  5. 名前: nginx
  6. 名前空間: kube-system
  7. 仕様:
  8. レプリカ: 2
  9. セレクタ:
  10. 一致ラベル:
  11. アプリ: nginx
  12. テンプレート:
  13. メタデータ:
  14. ラベル:
  15. アプリ: nginx
  16. 仕様:
  17. コンテナ:
  18. -名前: nginx
  19. 画像: nginx
  20. ポート:
  21. - コンテナポート: 80
  22. 名前: http
  23. ---  
  24. apiバージョン: v1
  25. 種類: サービス
  26. メタデータ:
  27. 名前: nginx
  28. 名前空間: kube-system
  29. 仕様:
  30. ポート:
  31. - プロトコル: TCP
  32. ポート: 80
  33. ターゲットポート: http
  34. セレクタ:
  35. アプリ: nginx

次に、HTTPRoute リソース オブジェクトを変更します。このオブジェクトには、次に示すように、2 つのサービスに異なる重みを割り当てることができる重みオプションがあります。

  1. # 04-whoami-nginx-canary.yaml
  2. ---  
  3. apiバージョン: networking.x-k8s.io/v1alpha1
  4. 種類: HTTPRoute
  5. メタデータ:
  6. ラベル:
  7. アプリ: traefik
  8. 名前: http-app-1
  9. 名前空間: kube-system
  10. 仕様:
  11. ホスト名:
  12. - フーアミ
  13. ルール:
  14. - 転送先:
  15. - ポート: 80
  16. サービス名: whoami
  17. 重量: 3 # 3/4 whoamiへのリクエスト
  18. - ポート: 80
  19. サービス名: nginx
  20. 重量: 1 # リクエストの1/4はwhoamiに送られました

上記のHTTPRouteを作成した後、whoamiサービスに再びアクセスできるようになりました。通常、リクエストの約25%はwhoamiレスポンスではなくNginxレスポンスで返されることがわかります。

現時点では、Traefik を使用して Kubernetes Gateway API の使用をテストしています。現在、Traefik の Gateway API 実装は v1alpha1 仕様に基づいていますが、最新の仕様は v1alpha2 であるため、両者の間には若干の違いがある可能性があります。