Skip to content
Published on

Kubernetes Gateway API 本番運用ガイド:HTTPRoute、GRPCRoute、Ingress移行戦略

Authors
  • Name
    Twitter
Kubernetes Gateway API

なぜGateway APIがIngressを置き換えるのか

Kubernetes Ingressリソースは長年コミュニティに貢献してきましたが、その制約がモダンなワークロードのボトルネックとなりました。ベンダー固有のアノテーション、ネイティブgRPCサポートの欠如、ロール分離の不在、そして単一リソースに全てを詰め込む設計が、Gateway API誕生の原動力となりました。

Gateway API(v1.0でGA、GRPCRouteはv1.1.0でGA)は、ロール指向プロトコル対応ポータブルなネットワーキングモデルを導入します。v1.2では、GRPCRouteとReferenceGrantの旧v1alpha2バージョンがStandardチャネルとExperimentalチャネルの両方から削除され、成熟度と本番環境対応を示しています。

アーキテクチャ概要

┌─────────────────────────────────────────────────────────────────┐
│                  クラスタ管理者                                    │
│                                                                 │
│  ┌──────────────┐                                               │
│  │ GatewayClass │  どのコントローラがGatewayを処理するか定義        │
│  └──────┬───────┘                                               │
│         │                                                       │
│         ▼                                                       │
│  ┌──────────────┐     プラットフォーム / インフラチーム              │
│  │   Gateway    │  リスナー、TLS、許可ルートを設定                  │
│  └──┬───┬───┬───┘                                               │
│     │   │   │                                                   │
│     ▼   ▼   ▼      アプリケーション開発者                          │
│  ┌────┐┌─────────┐┌──────────┐                                  │
│  │HTTP││GRPCRoute││TLSRoute  │  サービスごとのルーティングを定義     │
│  │Route│└─────────┘└──────────┘                                 │
│  └─┬──┘                                                        │
│    │                                                            │
│    ▼                                                            │
│  ┌──────────────────────────┐                                   │
│  │  バックエンドサービス / Pod │                                   │
│  └──────────────────────────┘                                   │
└─────────────────────────────────────────────────────────────────┘

ロール分離モデル

ロールリソース責務
インフラストラクチャプロバイダーGatewayClassゲートウェイコントローラのデプロイと管理
プラットフォームオペレーターGatewayリスナー、TLS終端、クロスネームスペースポリシーの設定
アプリケーション開発者HTTPRoute、GRPCRouteサービスごとのルーティングルール定義

この分離により、開発者はTLS証明書を扱う必要がなくなり、プラットフォームオペレーターはアプリケーションレベルのルーティングロジックを理解する必要がなくなります。

比較:Gateway API vs Ingress vs Service Mesh

機能IngressGateway APIService Mesh (Istio)
HTTPルーティング基本的なパス/ホスト高度(ヘッダー、クエリパラメータ、メソッド)フルL7ルーティング
gRPCネイティブ非対応(アノテーションで回避)対応(GRPCRoute GA)対応
TLS終端IngressごとGatewayのリスナーごとサイドカー/ウェイポイントごと
トラフィック分割アノテーションベースネイティブ(weightフィールド)ネイティブ(VirtualServiceまたはHTTPRoute)
ロール分離なしGatewayClass / Gateway / Route複雑なRBAC
クロスネームスペース制限的ReferenceGrantServiceEntry
TCP/UDPサポート非対応TCPRoute / UDPRoute対応
ポータビリティアノテーション依存適合性テストによりポータビリティ保証ベンダーロックインリスク
カナリア/Blue-Greenアノテーション必要ウェイトベースルーティング内蔵内蔵
East-Westトラフィック非対応対応(GAMMAイニシアチブ)主要ユースケース

Gateway API CRDとコントローラのインストール

ステップ1:Gateway API CRDのインストール

# Standard Channel CRDのインストール(HTTPRoute、GRPCRoute GAリソースを含む)
kubectl apply -f https://github.com/kubernetes-sigs/gateway-api/releases/download/v1.2.1/standard-install.yaml

# CRDのインストール確認
kubectl get crds | grep gateway
# 期待される出力:
# gatewayclasses.gateway.networking.k8s.io
# gateways.gateway.networking.k8s.io
# grpcroutes.gateway.networking.k8s.io
# httproutes.gateway.networking.k8s.io
# referencegrants.gateway.networking.k8s.io

# (オプション)Experimental ChannelのインストールでTCPRoute、TLSRoute、UDPRouteを追加
kubectl apply -f https://github.com/kubernetes-sigs/gateway-api/releases/download/v1.2.1/experimental-install.yaml

ステップ2:Gatewayコントローラのデプロイ

ニーズに合った実装を選択します。主要な選択肢:

# オプションA:Envoy Gateway
helm install eg oci://docker.io/envoyproxy/gateway-helm \
  --version v1.3.0 \
  -n envoy-gateway-system --create-namespace

# オプションB:NGINX Gateway Fabric
helm install ngf oci://ghcr.io/nginx/charts/nginx-gateway-fabric \
  --version 2.4.2 \
  -n nginx-gateway --create-namespace

# オプションC:Istio(Gateway APIサポート付き)
istioctl install --set profile=minimal

HTTPRoute:コアコンセプトとパターン

HTTPRouteはGateway APIの主力リソースです。HTTPおよびTLS終端済みHTTPS接続を、豊富なマッチング機能で処理します。

基本的なHTTPRoute設定

apiVersion: gateway.networking.k8s.io/v1
kind: GatewayClass
metadata:
  name: envoy-gateway
spec:
  controllerName: gateway.envoyproxy.io/gatewayclass-controller
---
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
  name: production
  namespace: infra
spec:
  gatewayClassName: envoy-gateway
  listeners:
    - name: https
      protocol: HTTPS
      port: 443
      tls:
        mode: Terminate
        certificateRefs:
          - name: wildcard-tls
            namespace: cert-manager
      allowedRoutes:
        namespaces:
          from: Selector
          selector:
            matchLabels:
              gateway-access: 'true'
    - name: http
      protocol: HTTP
      port: 80
---
apiVersion: gateway.networking.k8s.io/v1
kind: ReferenceGrant
metadata:
  name: allow-cert-ref
  namespace: cert-manager
spec:
  from:
    - group: gateway.networking.k8s.io
      kind: Gateway
      namespace: infra
  to:
    - group: ''
      kind: Secret
---
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: api-routes
  namespace: app-team
spec:
  parentRefs:
    - name: production
      namespace: infra
  hostnames:
    - 'api.example.com'
  rules:
    - matches:
        - path:
            type: PathPrefix
            value: /v2/users
          headers:
            - name: X-API-Version
              value: '2'
      backendRefs:
        - name: users-v2
          port: 8080
          weight: 90
        - name: users-v3
          port: 8080
          weight: 10
    - matches:
        - path:
            type: PathPrefix
            value: /v2/users
      backendRefs:
        - name: users-v2
          port: 8080
    - matches:
        - path:
            type: PathPrefix
            value: /healthz
      backendRefs:
        - name: health-service
          port: 8080

応用:HTTPからHTTPSへのリダイレクトとリクエスト修正

apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: redirect-to-https
  namespace: app-team
spec:
  parentRefs:
    - name: production
      namespace: infra
      sectionName: http
  hostnames:
    - 'api.example.com'
  rules:
    - filters:
        - type: RequestRedirect
          requestRedirect:
            scheme: https
            statusCode: 301
---
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: api-with-modifications
  namespace: app-team
spec:
  parentRefs:
    - name: production
      namespace: infra
      sectionName: https
  hostnames:
    - 'api.example.com'
  rules:
    - matches:
        - path:
            type: PathPrefix
            value: /api
      filters:
        - type: RequestHeaderModifier
          requestHeaderModifier:
            add:
              - name: X-Request-ID
                value: 'generated-by-gateway'
            remove:
              - X-Internal-Debug
        - type: URLRewrite
          urlRewrite:
            path:
              type: ReplacePrefixMatch
              replacePrefixMatch: /v1
      backendRefs:
        - name: api-backend
          port: 8080

GRPCRoute:ネイティブgRPCトラフィック管理

GRPCRouteはgRPCトラフィックのファーストクラスサポートを提供します。HTTPRouteでパスマッチングを使ってgRPCをラップするのとは異なり、GRPCRouteはgRPCのサービス名とメソッド名を直接理解します。

GRPCRoute設定

apiVersion: gateway.networking.k8s.io/v1
kind: GRPCRoute
metadata:
  name: grpc-user-service
  namespace: grpc-apps
spec:
  parentRefs:
    - name: production
      namespace: infra
  hostnames:
    - 'grpc.example.com'
  rules:
    # gRPCサービス名によるルーティング
    - matches:
        - method:
            service: com.example.UserService
            method: GetUser
      backendRefs:
        - name: user-service
          port: 50051
    # ヘッダーマッチング付きサービス名ルーティング
    - matches:
        - method:
            service: com.example.UserService
          headers:
            - name: x-canary
              value: 'true'
      backendRefs:
        - name: user-service-canary
          port: 50051
    # その他のgRPCメソッドへのデフォルトルート
    - matches:
        - method:
            service: com.example.UserService
      backendRefs:
        - name: user-service-stable
          port: 50051
          weight: 95
        - name: user-service-canary
          port: 50051
          weight: 5

GRPCRoute vs HTTPRoute:gRPCでの使い分け

シナリオ推奨理由
gRPCサービス/メソッドマッチングGRPCRouteネイティブサポート、簡潔な構文
パスマッチングのみのgRPCHTTPRouteでも可パスベースのマッチングはよりシンプル
同一ホストでHTTPとgRPCの混在HTTPRoute + GRPCRouteを分離各ルートタイプがプロトコルを処理
gRPC-Web(ブラウザクライアント)HTTPRoutegRPC-WebはHTTP/1.1フレーミングを使用

段階的なIngress移行手順

IngressからGateway APIへの移行は段階的に行うべきです。本番環境での一括切り替えは絶対に避けてください。

移行アーキテクチャ

                    ┌──────────────────────┐
DNS / LB                    │  api.example.com                    └──────────┬───────────┘
                    ┌──────────▼───────────┐
                    │   トラフィック分割     │
                      (DNS重み付けまたはLB)                    └──┬───────────────┬───┘
                       │               │
              ┌────────▼─────┐  ┌──────▼────────┐
Ingress    │  │   Gateway                (既存)   (新規)              │              │  │                │
              │  nginx-ctrl  │  │  envoy-gw      │
              └──────┬───────┘  └──────┬─────────┘
                     │                 │
                     └────────┬────────┘
                     ┌────────▼────────┐
                     │  同一バックエンド  │
                     │  サービス群       │
                     └─────────────────┘

フェーズ1:既存Ingressリソースの監査

# 全ネームスペースのIngressリソースを一覧表示
kubectl get ingress -A -o wide

# 分析用に全Ingressリソースをエクスポート
kubectl get ingress -A -o yaml > ingress-backup.yaml

# アノテーション依存関係の確認
kubectl get ingress -A -o json | \
  jq -r '.items[] | .metadata.name + " -> " + (.metadata.annotations | keys | join(", "))'

# ingress2gatewayによる自動変換
# インストール: go install github.com/kubernetes-sigs/ingress2gateway@latest
ingress2gateway print --all-namespaces

フェーズ2:Ingressと並行してGatewayリソースを作成

# 既存のIngressと並行してGatewayをデプロイ
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
  name: migration-gateway
  namespace: infra
  annotations:
    purpose: 'ingress-migration-phase2'
spec:
  gatewayClassName: envoy-gateway
  listeners:
    - name: https
      protocol: HTTPS
      port: 443
      tls:
        mode: Terminate
        certificateRefs:
          - name: wildcard-tls
      allowedRoutes:
        namespaces:
          from: All

フェーズ3:Ingressルールに対応するHTTPRouteを作成

# 進める前にGatewayがProgrammed状態であることを確認
kubectl get gateway migration-gateway -n infra -o jsonpath='{.status.conditions}'

# 期待値: type=Programmed, status=True
# 警告: GatewayがProgrammed=Trueを示すまでIngressリソースを削除しないでください

フェーズ4:段階的なトラフィック移行

# 各HTTPRouteを個別に検証
for route in $(kubectl get httproute -A -o jsonpath='{range .items[*]}{.metadata.namespace}/{.metadata.name}{"\n"}{end}'); do
  ns=$(echo $route | cut -d/ -f1)
  name=$(echo $route | cut -d/ -f2)
  echo "--- $ns/$name を確認中 ---"
  kubectl get httproute $name -n $ns -o jsonpath='{.status.parents[*].conditions}' | jq .
done

# DNS切り替え前にcurlでテスト
GATEWAY_IP=$(kubectl get gateway migration-gateway -n infra \
  -o jsonpath='{.status.addresses[0].value}')
curl -H "Host: api.example.com" https://$GATEWAY_IP/healthz --resolve "api.example.com:443:$GATEWAY_IP"

フェーズ5:Ingressリソースを一つずつ削除

# Ingressを一つずつ削除し、検証してから次に進む
kubectl delete ingress old-api-ingress -n app-team

# 直ちにサービスの到達性を確認
curl -f https://api.example.com/healthz || echo "ロールバックが必要です"

# ロールバックが必要な場合:
kubectl apply -f ingress-backup.yaml

トラフィック分割とカナリアデプロイメント

Gateway APIはウェイトベースのトラフィック分割により、カナリアデプロイメントをファーストクラスの機能として提供します。

apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: canary-deployment
  namespace: app-team
spec:
  parentRefs:
    - name: production
      namespace: infra
  hostnames:
    - 'app.example.com'
  rules:
    - matches:
        - path:
            type: PathPrefix
            value: /
      backendRefs:
        # Stable:トラフィックの95%を受信
        - name: app-stable
          port: 8080
          weight: 95
        # Canary:トラフィックの5%を受信
        - name: app-canary
          port: 8080
          weight: 5

段階的にトラフィックを移行する場合:

# カナリアのウェイトを段階的に増加
# 5% -> 10% -> 25% -> 50% -> 100%
# 各ステップでエラー率とレイテンシを確認

# カナリアメトリクスの監視(Prometheusの例)
# rate(http_requests_total{app="app-canary",code=~"5.."}[5m])
# / rate(http_requests_total{app="app-canary"}[5m])

TLS終端パターン

cert-managerとGatewayレベルTLS

apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
  name: secure-gateway
  namespace: infra
  annotations:
    cert-manager.io/cluster-issuer: letsencrypt-prod
spec:
  gatewayClassName: envoy-gateway
  listeners:
    - name: https-wildcard
      protocol: HTTPS
      port: 443
      hostname: '*.example.com'
      tls:
        mode: Terminate
        certificateRefs:
          - name: wildcard-example-com
    - name: https-specific
      protocol: HTTPS
      port: 443
      hostname: 'api.specific.com'
      tls:
        mode: Terminate
        certificateRefs:
          - name: api-specific-cert
    - name: tls-passthrough
      protocol: TLS
      port: 8443
      hostname: 'mtls.example.com'
      tls:
        mode: Passthrough

本番環境トラブルシューティング

一般的な障害ケースとリカバリ

問題1:Gatewayが「Programmedでない」状態で停止

# Gatewayのステータスコンディションを確認
kubectl describe gateway production -n infra

# 一般的な原因:
# 1. GatewayClassコントローラが実行されていない
kubectl get pods -n envoy-gateway-system

# 2. 無効なTLS証明書リファレンス
kubectl get secret wildcard-tls -n infra

# 3. リスナーの競合(重複するポート/ホスト名)
kubectl get gateway -A -o jsonpath='{range .items[*]}{.metadata.name}: {range .spec.listeners[*]}{.port}/{.hostname} {end}{"\n"}{end}'

問題2:HTTPRouteがGatewayにアタッチされない

# ルートのステータスを確認
kubectl get httproute api-routes -n app-team -o yaml | yq '.status'

# 一般的な原因:
# 1. クロスネームスペースのReferenceGrantが不足
kubectl get referencegrant -A

# 2. Gatewayリスナーでネームスペースが許可されていない
kubectl get ns app-team --show-labels
# ラベルがGatewayのallowedRoutesセレクタと一致することを確認

# 3. GatewayリスナーとHTTPRoute間のホスト名不一致
# HTTPRouteのホスト名はリスナーのホスト名のサブドメインであるか一致する必要がある

問題3:移行後の503エラー

# バックエンドのエンドポイントが正常か確認
kubectl get endpoints users-v2 -n app-team

# サービスポートがHTTPRouteのbackendRefポートと一致するか確認
kubectl get svc users-v2 -n app-team -o jsonpath='{.spec.ports}'

# ゲートウェイコントローラのログを確認
kubectl logs -n envoy-gateway-system -l app=envoy-gateway --tail=100

# Envoyプロキシ設定が正しく生成されたか検証
# (Envoy Gateway固有)
kubectl get envoyproxy -A

問題4:gRPCリクエストがUNAVAILABLEで失敗

# バックエンドがHTTP/2をサポートしているか確認
kubectl exec -it deploy/user-service -n grpc-apps -- \
  grpcurl -plaintext localhost:50051 list

# Gatewayリスナーのプロトコルが正しいか確認
# gRPCにはHTTPS(TLS終端付き)が必要、
# またはコントローラがHTTP/2クリアテキスト(h2c)をサポートする必要がある

# GRPCRouteのステータスを確認
kubectl get grpcroute -A -o yaml | yq '.items[].status'

運用上の警告

  1. Ingressリソースを一度に全て削除しないこと。 サービスを一つずつ移行し、各削除後に到達性を確認してください。

  2. トラフィックをルーティングする前にGatewayのProgrammedステータスを必ず確認すること。 AcceptedだがProgrammedでないGatewayはデータプレーンがプロビジョニングされていません。

  3. クロスネームスペース参照にはReferenceGrantが必須です。 これがないと、ネームスペースAのルートからネームスペースBのバックエンドやネームスペースCのシークレットを参照できません。

  4. Gateway API v1.2ではv1alpha2 GRPCRouteが削除されました。 アップグレード前に、コントローラがv1 GRPCRouteをサポートしていることを確認してください。kubectl get crds grpcroutes.gateway.networking.k8s.io -o jsonpath='{.spec.versions[*].name}' で確認できます。

  5. ウェイトベースの分割は最も近い整数に丸められます。 ウェイトを1と99に設定した場合、実際の分割はコントローラの実装によりわずかに異なる場合があります。

  6. TLS PassthroughリスナーではHTTPヘッダーを検査できません。 ヘッダーベースのルーティングが必要な場合は、代わりにTLS Terminateモードを使用してください。

本番環境用ヘルスチェックスクリプト

#!/bin/bash
# gateway-health-check.sh
# Gateway APIの本番環境変更後に実行

set -euo pipefail

echo "=== Gatewayステータス ==="
kubectl get gateways -A -o custom-columns=\
'NAMESPACE:.metadata.namespace,NAME:.metadata.name,CLASS:.spec.gatewayClassName,PROGRAMMED:.status.conditions[?(@.type=="Programmed")].status,ACCEPTED:.status.conditions[?(@.type=="Accepted")].status'

echo ""
echo "=== HTTPRouteステータス ==="
kubectl get httproutes -A -o custom-columns=\
'NAMESPACE:.metadata.namespace,NAME:.metadata.name,HOSTNAMES:.spec.hostnames[*],ACCEPTED:.status.parents[*].conditions[?(@.type=="Accepted")].status'

echo ""
echo "=== GRPCRouteステータス ==="
kubectl get grpcroutes -A -o custom-columns=\
'NAMESPACE:.metadata.namespace,NAME:.metadata.name,ACCEPTED:.status.parents[*].conditions[?(@.type=="Accepted")].status' 2>/dev/null || echo "GRPCRouteが見つかりません"

echo ""
echo "=== ReferenceGrant一覧 ==="
kubectl get referencegrants -A

echo ""
echo "=== 残存Ingressリソース(移行完了後は空であるべき) ==="
kubectl get ingress -A

実装比較:Envoy Gateway vs NGINX Gateway Fabric vs Istio

機能Envoy GatewayNGINX Gateway FabricIstio
データプレーンEnvoy ProxyNGINXEnvoy(サイドカーまたはambient)
HTTPRouteフルサポートフルサポートフルサポート
GRPCRouteフルサポートフルサポートフルサポート
TLSRouteサポートサポートサポート
TCPRoute / UDPRouteサポート部分的サポート
カスタム拡張EnvoyProxy、BackendTrafficPolicySnippetsFilterVirtualService、DestinationRule
East-West(メッシュ)主要フォーカスではないなし主要な強み
レート制限BackendTrafficPolicyRateLimitPolicyEnvoyFilterまたはWASM
最適な用途純粋なIngress/EgressゲートウェイNGINX習熟チームフルサービスメッシュ + ゲートウェイ

実践パターン:マルチチームプラットフォーム

# プラットフォームチームが共有Gatewayをデプロイ
apiVersion: gateway.networking.k8s.io/v1
kind: GatewayClass
metadata:
  name: platform-gateway
spec:
  controllerName: gateway.envoyproxy.io/gatewayclass-controller
---
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
  name: shared-gateway
  namespace: platform
spec:
  gatewayClassName: platform-gateway
  listeners:
    - name: https-web
      protocol: HTTPS
      port: 443
      hostname: '*.web.example.com'
      tls:
        mode: Terminate
        certificateRefs:
          - name: web-wildcard
      allowedRoutes:
        namespaces:
          from: Selector
          selector:
            matchLabels:
              tier: web
    - name: https-api
      protocol: HTTPS
      port: 443
      hostname: '*.api.example.com'
      tls:
        mode: Terminate
        certificateRefs:
          - name: api-wildcard
      allowedRoutes:
        namespaces:
          from: Selector
          selector:
            matchLabels:
              tier: api
---
# チームAが独自のルートをデプロイ(TLSの知識不要)
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: team-a-frontend
  namespace: team-a
spec:
  parentRefs:
    - name: shared-gateway
      namespace: platform
      sectionName: https-web
  hostnames:
    - 'app.web.example.com'
  rules:
    - backendRefs:
        - name: frontend
          port: 3000
---
# チームBがgRPCルートを独立してデプロイ
apiVersion: gateway.networking.k8s.io/v1
kind: GRPCRoute
metadata:
  name: team-b-grpc
  namespace: team-b
spec:
  parentRefs:
    - name: shared-gateway
      namespace: platform
      sectionName: https-api
  hostnames:
    - 'payments.api.example.com'
  rules:
    - matches:
        - method:
            service: com.example.PaymentService
      backendRefs:
        - name: payment-grpc
          port: 50051

まとめ

Kubernetes Gateway APIは、クラスタネットワーキングの管理方法における根本的な転換を表しています。主な要点:

  • HTTPRouteはHTTP/HTTPSトラフィックの主要ルーティングリソースであり、豊富なマッチング、フィルタリング、トラフィック分割機能を備えています。
  • GRPCRouteはアノテーションの回避策なしに、ネイティブなgRPCサービス/メソッドレベルのルーティングを提供します。
  • Ingressからの移行は段階的に行うべきです:Gateway API CRDのインストール、コントローラのデプロイ、既存Ingressと並行してルートを作成、検証、そしてIngressリソースを一つずつ削除。
  • ロール分離(GatewayClass、Gateway、Route)により、プラットフォームチームとアプリケーションチームが独立して作業できます。
  • 本番トラフィックに依存する前に、GatewayステータスがProgrammed: Trueを示すことを必ず確認してください。

エコシステムは成熟しています。Envoy Gateway、NGINX Gateway Fabric、Istioの全てが堅牢なGateway API実装を提供しています。既存のスタックとEast-West(メッシュ)機能の必要性に基づいて選択してください。

参考文献