Kubernetes

Kubernetes Gateway API とは?Ingress の課題と新しい標準を学ぶ

Flaty

この記事で分かること

  • 外部トラフィックをクラスタに受け入れる仕組み
  • Ingress リソースの課題
  • Gateway API が作られた背景と設計思想
  • Gateway API のリソースモデル(GatewayClass / Gateway / HTTPRoute)
  • Ingress との具体的な違い

前回の記事では Istio の VirtualService と DestinationRule を整理し、最後に Gateway API という選択肢にも触れました。Gateway API は Istio 固有のものではなく、Kubernetes コミュニティが策定した標準 API です。

この記事では Istio から離れ、Gateway API 自体にフォーカスします。従来の Ingress リソースにどのような課題があり、Gateway API がそれをどう解決するのかを見ていきます。

外部トラフィックをクラスタに受け入れるには

Kubernetes クラスタ内の Pod は、デフォルトではクラスタ外部からアクセスできません。外部のユーザーがアプリケーションにアクセスするには、トラフィックをクラスタ内に受け入れる入口が必要です。

Service の種類

Kubernetes の Service には外部公開の手段がいくつかあります。

タイプ 説明
ClusterIP クラスタ内部のみ(デフォルト)
NodePort 各ノードの固定ポートで公開
LoadBalancer クラウドのロードバランサーを作成して公開

LoadBalancer を使えば外部公開はできますが、Service ごとにロードバランサーが 1 つ作られます。10 個のサービスを公開すれば 10 個のロードバランサーが必要になり、コストが膨らみます。

また、Service は L4(TCP/UDP)レベルの負荷分散しかできません。「ホスト名が api.example.com なら API サーバーに、www.example.com ならフロントエンドに」といった L7(HTTP)のルーティングはできません。

Ingress の登場

こうした課題を解決するために作られたのが Ingress です。1 つのロードバランサーで複数のサービスに L7 ルーティングできます。

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: my-ingress
spec:
  rules:
    - host: api.example.com
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: api-server
                port:
                  number: 8080
    - host: www.example.com
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: web-frontend
                port:
                  number: 3000

Ingress 自体はルーティングルールの定義にすぎません。実際にトラフィックを処理するのは Ingress Controller です。NGINX Ingress Controller、AWS ALB Ingress Controller、Traefik など、複数の実装があります。

Ingress の課題

Ingress は広く使われてきましたが、いくつかの根本的な課題があります。

アノテーション依存

Ingress の仕様で定義されている機能はホストベースとパスベースのルーティング程度です。TLS リダイレクト、レート制限、タイムアウトといった機能は仕様に含まれず、実装ごとのアノテーションで設定します。

# NGINX Ingress Controller の場合
metadata:
  annotations:
    nginx.ingress.kubernetes.io/ssl-redirect: "true"
    nginx.ingress.kubernetes.io/proxy-read-timeout: "60"
# AWS ALB Ingress Controller の場合
metadata:
  annotations:
    alb.ingress.kubernetes.io/ssl-redirect: "443"
    alb.ingress.kubernetes.io/target-group-attributes: "stickiness.enabled=true"

同じ「TLS リダイレクト」という機能でも、Ingress Controller ごとにアノテーションが異なります。Ingress Controller を変更すると、すべての Ingress リソースのアノテーションを書き直す必要があります。

表現力の不足

Ingress で定義できるルーティングは限定的です。

  • ヘッダーベースのルーティング: リクエストヘッダーの値でルーティング先を変えたい → Ingress 仕様にはない
  • 重み付きルーティング: v1 に 90%、v2 に 10% のトラフィックを流したい → Ingress 仕様にはない
  • リクエストの書き換え: パスやヘッダーを変更してからバックエンドに転送したい → アノテーション依存

実際にはアノテーションや CRD で拡張している Ingress Controller も多いですが、それでは標準 API を使う意味が薄れます。

ロールの分離ができない

Ingress は 1 つのリソースにリスナー設定(ポート、TLS 証明書)とルーティングルール(ホスト名、パス、バックエンド)が混在しています。

実際の運用では、これらは異なる担当者が管理します。

  • クラスタ運用者: TLS 証明書、ポート、セキュリティポリシー
  • アプリ開発者: 自分のアプリへのルーティングルール

Ingress ではこの分離が難しく、アプリ開発者が TLS 証明書の参照を含む Ingress を作成する必要があったり、逆にクラスタ運用者がアプリケーション固有のルーティングを管理する必要があったりします。

Gateway API とは

Gateway API は、Kubernetes の SIG-Network が Ingress の課題を解決するために設計した標準 API です。

ロールベースの設計

Gateway API の核となる設計思想はロールベースの分離です。

Kubernetes クラスタの運用には、以下のような役割があります。

  • インフラ提供者: ゲートウェイの実装を提供する(クラウドプロバイダ、サービスメッシュなど)
  • クラスタ運用者: クラスタのネットワーク入口を管理する(ポート、TLS、アクセス制御)
  • アプリ開発者: 自分のアプリケーションへのルーティングを設定する

Gateway API は、この 3 つの役割に対応する 3 つのリソースを提供します。

Gateway API のロールベース設計

リソースモデル

GatewayClass

インフラ提供者が管理するリソースです。「どの実装がゲートウェイを処理するか」を定義します。

apiVersion: gateway.networking.k8s.io/v1
kind: GatewayClass
metadata:
  name: example-gateway-class
spec:
  controllerName: example.com/gateway-controller

GatewayClass はクラスタスコープのリソースで、通常はインフラ提供者が作成します。アプリ開発者やクラスタ運用者が直接作成することはほとんどありません。

どの実装がゲートウェイを処理するかは spec.controllerName で決まります。たとえば Istio をインストールすると、Istio は istio.io/gateway-controller という名前のコントローラーを起動し、それに対応する GatewayClass を自動で作成します。ユーザーは Gateway の gatewayClassName でこの GatewayClass を指定するだけで、裏側の実装を意識せずに使えます。

Kubernetes の StorageClass がストレージの実装を抽象化するように、GatewayClass はゲートウェイの実装を抽象化します。controllerName を差し替えれば、Gateway や HTTPRoute の YAML はそのままで実装だけを変更できます。

主な GatewayClass の例:

GatewayClass 名 controllerName 提供元
istio istio.io/gateway-controller Istio
gke-l7-global-external-managed networking.gke.io/gateway Google Cloud
amazon-vpc-lattice application-networking.k8s.aws/gateway-api-controller AWS
envoy-gateway gateway.envoyproxy.io/gatewayclass-controller Envoy Gateway

Gateway

クラスタ運用者が管理するリソースです。「どのポート・プロトコルでトラフィックを受け入れるか」を定義します。

apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
  name: my-gateway
  namespace: gw-system
spec:
  gatewayClassName: example-gateway-class
  listeners:
    - name: http
      port: 80
      protocol: HTTP
      allowedRoutes:
        namespaces:
          from: All
    - name: https
      port: 443
      protocol: HTTPS
      tls:
        mode: Terminate
        certificateRefs:
          - name: my-tls-secret
      allowedRoutes:
        namespaces:
          from: Selector
          selector:
            matchLabels:
              gateway-access: "true"

Gateway を作成すると、指定した GatewayClass の実装が実際のインフラを自動でプロビジョニングします。たとえば Istio の場合は Envoy Proxy の Deployment と LoadBalancer タイプの Service が作成され、クラウドプロバイダの場合はマネージドロードバランサーが作成されます。この YAML を kubectl apply するだけで、トラフィックを受け入れるインフラが準備されます。

重要なポイント:

  • listeners: 受け入れるポート、プロトコル、TLS 設定を定義する。複数のリスナーを持てる
  • allowedRoutes: どの Namespace の Route リソースからの参照を許可するかを制御する
    • from: All — すべての Namespace を許可
    • from: Same — Gateway と同じ Namespace のみ許可
    • from: Selector — ラベルに一致する Namespace のみ許可

allowedRoutes により、クラスタ運用者が「この Gateway にルーティングを紐付けてよい Namespace」を制御できます。たとえば、開発チーム A の Namespace にだけ Gateway の利用を許可し、他チームの Namespace からは紐付けられないようにできます。HTTPRoute の parentRefs と Gateway の allowedRoutes の双方が一致して初めてルーティングが有効になるため、片方の設定だけではアタッチできません。

HTTPRoute

アプリ開発者が管理するリソースです。「HTTP トラフィックをどのサービスに、どのようにルーティングするか」を定義します。

apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: my-app
  namespace: my-app
spec:
  parentRefs:
    - name: my-gateway
      namespace: gw-system
  hostnames:
    - "my-app.example.com"
  rules:
    - matches:
        - path:
            type: PathPrefix
            value: /api
      backendRefs:
        - name: api-server
          port: 8080
    - matches:
        - path:
            type: PathPrefix
            value: /
      backendRefs:
        - name: web-frontend
          port: 3000

主なフィールド:

  • parentRefs: 紐付ける Gateway を指定する。上の例では my-app Namespace の HTTPRoute が gw-system Namespace の Gateway を参照している。これにより、クラスタ運用者が Gateway を集中管理しつつ、アプリ開発者は自分の Namespace で HTTPRoute を自由に作成できる
  • hostnames: ルーティング対象のホスト名
  • rules: マッチ条件(パス、ヘッダーなど)とルーティング先の組み合わせ

HTTPRoute 以外にも、プロトコルに応じた Route リソースがあります。

Route リソース 対象プロトコル チャネル
HTTPRoute HTTP / HTTPS Standard(GA)
GRPCRoute gRPC Standard(GA)
TLSRoute TLS パススルー Experimental(Alpha)
TCPRoute TCP Experimental(Alpha)
UDPRoute UDP Experimental(Alpha)

HTTPRoute と GRPCRoute は Standard チャネル(GA)で安定していますが、TLSRoute / TCPRoute / UDPRoute は Experimental チャネル(Alpha)であり、今後仕様が変更される可能性があります。

リソース間の関係

3 つのリソースの関係を整理します。

GatewayClass(インフラ提供者)
  └── Gateway(クラスタ運用者)
        └── HTTPRoute(アプリ開発者)
              └── Service → Pod
Gateway API のリソースモデル
リソース 管理者 役割 スコープ
GatewayClass インフラ提供者 ゲートウェイの実装を定義 クラスタスコープ
Gateway クラスタ運用者 リスナー(ポート、TLS)を定義 Namespace スコープ
HTTPRoute アプリ開発者 ルーティングルールを定義 Namespace スコープ

Gateway API でできること

HTTPRoute の主な機能を紹介します。

パスベースのルーティング

パスに基づいて異なるサービスにルーティングします。

rules:
  - matches:
      - path:
          type: PathPrefix
          value: /api
    backendRefs:
      - name: api-server
        port: 8080
  - matches:
      - path:
          type: PathPrefix
          value: /
    backendRefs:
      - name: web-frontend
        port: 3000

ヘッダーベースのルーティング

リクエストヘッダーの値に基づいてルーティング先を変えます。Ingress 仕様にはなかった機能です。

rules:
  - matches:
      - headers:
          - name: x-env
            value: staging
    backendRefs:
      - name: my-app-staging
        port: 80
  - backendRefs:
      - name: my-app-production
        port: 80

トラフィック分割

複数のバックエンドに重み付きでトラフィックを分散します。カナリアリリースに使えます。

rules:
  - backendRefs:
      - name: my-app-v1
        port: 80
        weight: 90
      - name: my-app-v2
        port: 80
        weight: 10

リクエスト・レスポンスの書き換え

パスやヘッダーの書き換えも標準機能として定義されています。

rules:
  - matches:
      - path:
          type: PathPrefix
          value: /old-api
    filters:
      - type: URLRewrite
        urlRewrite:
          path:
            type: ReplacePrefixMatch
            replacePrefixMatch: /new-api
    backendRefs:
      - name: api-server
        port: 8080

Ingress との比較

Ingress と Gateway API の違いを整理します。

観点 Ingress Gateway API
ステータス 機能フリーズ(新機能の追加なし) 活発に開発中
ロール分離 1 リソースに混在 GatewayClass / Gateway / HTTPRoute で分離
標準機能 ホスト・パスベースのルーティング ヘッダーマッチ、重み付き、書き換えなども標準
拡張方法 アノテーション(実装依存) Policy Attachment(標準化された拡張点)
プロトコル HTTP/HTTPS のみ HTTP、gRPC は GA。TCP、UDP、TLS は Experimental
移植性 アノテーションが実装依存のため低い 標準 API のため高い

Policy Attachment は Gateway API 固有の拡張方式です。Ingress ではアノテーション(自由形式の文字列)で実装固有の機能を設定していましたが、Gateway API では Policy リソースとして型付きの YAML で定義します。たとえばタイムアウトやレート制限を Gateway や HTTPRoute に紐付ける形で設定でき、スキーマによるバリデーションが効きます。

Gateway API は Ingress の上位互換として設計されています。新規に構築する場合は Gateway API を選択するのが妥当です。既存の Ingress からの移行も、ルーティングルールの対応関係が明確なため比較的容易です。

まとめ

  • Gateway API は Ingress の課題(アノテーション依存、表現力不足、ロール分離不可)を解決するために設計された Kubernetes 標準 API
  • GatewayClass(実装の選択)、Gateway(リスナー定義)、HTTPRoute(ルーティングルール)の 3 層で責務を分離する
  • ヘッダーベースルーティング、トラフィック分割、リクエスト書き換えなど、Ingress にはなかった機能が標準で利用できる
  • Istio、Envoy Gateway、クラウドプロバイダなど多くの実装が Gateway API をサポートしており、移植性が高い
  • 新規構築では Gateway API を第一候補とするのが妥当

参考

ABOUT ME
ぴょい
ぴょい
しがないソフトウェアエンジニアです。 学んだことをメモがわりに書いています。たまに技術以外の話も。 このブログの内容は個人の見解であり、所属組織とは関係ありません。記載内容には誤りがある可能性がありますので、公式ドキュメント等もあわせてご確認ください。
記事URLをコピーしました