
- 概要
- Gateway API vs Ingress: なぜ移行すべきか
- アーキテクチャ
- Gateway API実装の比較
- 中核リソースの説明
- トラフィック管理パターン
- Envoy Gatewayのインストールと初期設定
- トラブルシューティング
- 障害事例と復旧手順
- 運用チェックリスト
- まとめ
- 参考資料
概要
2026年3月現在、Kubernetes Ingress NGINXのメンテナンス終了が目前に迫り、Gateway APIへの移行は選択ではなく必須になった。Gateway APIはv1.4までリリースされ、BackendTLSPolicy、Named Rules、supportedFeaturesなどの中核機能がStandardチャネルへ昇格し、Envoy Gatewayはv1.6.xまで進化しながらSecurityPolicy、グローバル/ローカルのRate Limiting、mTLSなどエンタープライズ級のトラフィック管理機能を提供している。
この記事ではGateway APIの中核リソース構造を理解し、Envoy Gatewayを実装として選んで運用環境で実際にトラフィックを管理する方法を扱う。カナリアデプロイ、トラフィックミラーリング、ヘッダーベースのルーティング、Rate Limiting、BackendTLSPolicyを活用したバックエンドmTLSまで、実践ですぐに適用できるパターンをコードとともに示す。
Gateway API vs Ingress: なぜ移行すべきか
IngressリソースはKubernetesの初期からHTTPトラフィックルーティングの標準だったが、ベンダーごとのアノテーションに依存する構造的な限界があった。Gateway APIはこの問題を根本的に解決する。
| 比較項目 | Ingress | Gateway API |
|---|---|---|
| プロトコル対応 | HTTP/HTTPSのみ | HTTP, gRPC, TCP, UDP, TLS をすべてサポート |
| ルーティング表現力 | ホスト/パスベースのみ | ヘッダー、クエリパラメータ、メソッドでのマッチが可能 |
| 役割分離 | 単一リソースにすべての設定 | GatewayClass、Gateway、Routeで役割を分離 |
| ベンダー依存 | アノテーションベースの拡張 (ベンダー依存) | 標準化されたCRDベースの拡張 (移植可能) |
| トラフィック分割 | ネイティブ非対応 | 重みベースのトラフィック分割をネイティブ対応 |
| TLS管理 | 基本的なTLS終端のみ | BackendTLSPolicyでバックエンドmTLSに対応 |
| マルチテナンシー | 限定的 | ネームスペース間のルート共有をネイティブ対応 |
中核となる移行の動機は3つだ。第一に、Ingress NGINXが2026年3月にメンテナンス終了を控えており、セキュリティパッチが停止する。第二に、Gateway APIはL4/L7プロトコルを統合的に管理できるため、TCP、UDP、gRPCのワークロードを別のメカニズムなしで処理する。第三に、4つのペルソナ(インフラ提供者、クラスタ運用者、アプリケーション管理者、アプリケーション開発者)に合わせた役割分離が、マルチチーム環境で運用効率を最大化する。
アーキテクチャ
Gateway APIリソースの階層構造
Gateway APIは3つの階層に分かれる。GatewayClassはインフラ提供者が定義するテンプレートだ。Gatewayはクラスタ運用者がGatewayClassを基に作成するロードバランサのインスタンスだ。Route(HTTPRoute、GRPCRoute、TLSRoute、TCPRoute)はアプリケーション開発者がトラフィックのルーティング規則を定義するリソースだ。
この階層構造のおかげで、クラスタ運用者はTLS証明書とリスナーのポートを管理しながら、アプリケーション開発者は自分のネームスペースの中で独立してルーティング規則をデプロイできる。ReferenceGrantリソースを通じてネームスペース間の参照権限を明示的に制御できる。
Envoy Gatewayのアーキテクチャ
Envoy GatewayはGateway APIの実装であり、コントロールプレーンとデータプレーンで構成される。コントロールプレーンはGateway APIリソースを監視(watch)し、これをEnvoyプロキシの設定へ変換する。データプレーンは実際のトラフィックを処理するEnvoyプロキシのインスタンス群だ。Envoy GatewayコントローラがGatewayリソースを検知すると、自動でEnvoyプロキシのDeploymentとServiceをプロビジョニングする。
Envoy Gatewayならではの差別化要素は、BackendTrafficPolicy、SecurityPolicy、ClientTrafficPolicy、EnvoyExtensionPolicyのような拡張CRDを通じてRate Limiting、認証/認可、トラフィック制御を宣言的に管理できる点だ。
Gateway API実装の比較
運用環境でGateway APIの実装を選ぶときは次の比較を参考にする。
| 実装 | データプレーン | Gateway APIバージョン | 主な特徴 |
|---|---|---|---|
| Envoy Gateway | Envoy Proxy | v1.2+ | ネイティブなRate Limiting、SecurityPolicy、AI Gateway拡張 |
| Istio (Ambient) | Envoy Proxy / ztunnel | v1.1+ | サービスメッシュ統合、Ambientモードでサイドカー不要 |
| NGINX Gateway Fabric | NGINX | v1.2+ | NGINXベース、既存のNGINX利用者に馴染みやすい |
| Cilium Gateway | eBPF / Envoy | v1.1+ | eBPFベースのL4高速化、ネットワークポリシー統合 |
| Kong Gateway | Kong Proxy | v1.2+ | プラグインのエコシステム、API管理の統合 |
| Traefik | Traefik Proxy | v1.1+ | 自動証明書管理、手軽な設定 |
この記事ではEnvoy Gatewayを中心に扱うが、Gateway APIの標準に従うため、中核リソース(GatewayClass、Gateway、HTTPRoute、GRPCRoute)の定義は他の実装でも同じように適用される。
中核リソースの説明
GatewayClassとGateway
GatewayClassはどのコントローラがGatewayを管理するかを指定するクラスタスコープのリソースだ。Gatewayは実際のリスナー(ポート、プロトコル、TLS設定)を定義するネームスペーススコープのリソースだ。
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-gateway
namespace: infra
annotations:
cert-manager.io/cluster-issuer: letsencrypt-prod
spec:
gatewayClassName: envoy-gateway
listeners:
- name: https
protocol: HTTPS
port: 443
tls:
mode: Terminate
certificateRefs:
- kind: Secret
name: wildcard-tls
namespace: infra
allowedRoutes:
namespaces:
from: Selector
selector:
matchLabels:
gateway-access: 'true'
- name: http
protocol: HTTP
port: 80
allowedRoutes:
namespaces:
from: Same
この設定ではHTTPSリスナーはgateway-access: "true"ラベルが付いたネームスペースのRouteだけを許可する。HTTPリスナーは同じネームスペースのRouteだけを許可し、HTTPSリダイレクト専用として使う。allowedRoutesによるこうした細分化されたアクセス制御が、Ingressに比べたGateway APIの最大の利点の一つだ。
HTTPRoute
HTTPRouteはHTTPトラフィックのルーティング規則を定義する。Gateway API v1.4で導入されたNamed Rules機能を使うと、各規則に名前を付けて可観測性とポリシーのターゲティングを強化できる。
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: api-route
namespace: app
spec:
parentRefs:
- name: production-gateway
namespace: infra
sectionName: https
hostnames:
- 'api.example.com'
rules:
- name: health-check
matches:
- path:
type: Exact
value: /healthz
backendRefs:
- name: api-service
port: 8080
- name: api-v2
matches:
- path:
type: PathPrefix
value: /api/v2
headers:
- name: X-API-Version
value: '2'
backendRefs:
- name: api-v2-service
port: 8080
- name: api-default
matches:
- path:
type: PathPrefix
value: /api
backendRefs:
- name: api-v1-service
port: 8080
Named Rules(name: health-check、name: api-v2、name: api-default)は、Envoyのメトリクスで各規則ごとのトラフィック統計を確認するときに有用だ。またBackendTrafficPolicyで特定の規則だけをターゲティングできるため、細分化されたトラフィックポリシーの適用が可能だ。
GRPCRoute
GRPCRouteはgRPCトラフィックをネイティブにルーティングする。Gateway API v1.1からStandardチャネルに含まれ、GA状態だ。
apiVersion: gateway.networking.k8s.io/v1
kind: GRPCRoute
metadata:
name: grpc-route
namespace: app
spec:
parentRefs:
- name: production-gateway
namespace: infra
sectionName: https
hostnames:
- 'grpc.example.com'
rules:
- matches:
- method:
service: myapp.UserService
method: GetUser
backendRefs:
- name: user-service-grpc
port: 50051
- matches:
- method:
service: myapp.OrderService
backendRefs:
- name: order-service-grpc
port: 50051
GRPCRouteを使うGatewayはHTTP/2を必須でサポートする必要がある。Envoy GatewayはデフォルトでHTTP/2をサポートするため、追加の設定なしでgRPCルーティングが動作する。
BackendTLSPolicy
BackendTLSPolicyはGateway API v1.4でStandardチャネルへ昇格したリソースで、GatewayとバックエンドPodの間のTLS接続を設定する。これによりゲートウェイからバックエンドまでのend-to-end暗号化を実装できる。
apiVersion: gateway.networking.k8s.io/v1alpha3
kind: BackendTLSPolicy
metadata:
name: backend-tls
namespace: app
spec:
targetRefs:
- group: ''
kind: Service
name: api-service
validation:
caCertificateRefs:
- group: ''
kind: ConfigMap
name: backend-ca-cert
hostname: api-service.app.svc.cluster.local
この設定は、Gatewayがapi-serviceへリクエストを転送するときにTLSを使うよう強制し、ConfigMapに保存されたCA証明書でバックエンドの証明書を検証する。hostnameフィールドはバックエンド証明書のSAN(Subject Alternative Name)と一致する必要がある。
トラフィック管理パターン
カナリアデプロイ (重みベースのトラフィック分割)
Gateway APIの重みベースのトラフィック分割は、カナリアデプロイの中核メカニズムだ。backendRefsにweightを指定してトラフィックの比率を調整する。
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: canary-route
namespace: app
spec:
parentRefs:
- name: production-gateway
namespace: infra
sectionName: https
hostnames:
- 'app.example.com'
rules:
- name: canary-split
matches:
- path:
type: PathPrefix
value: /
backendRefs:
- name: app-stable
port: 8080
weight: 90
- name: app-canary
port: 8080
weight: 10
この設定は全トラフィックの90%を安定版(app-stable)へ、10%をカナリア版(app-canary)へルーティングする。カナリアの検証が完了したらweightを段階的に調整して0/100へ切り替える。
FlaggerのようなProgressive Deliveryツールと組み合わせると、メトリクスベースの自動カナリアプロモーションを実装できる。FlaggerはGateway APIをネイティブにサポートするため、HTTPRouteのbackendRefsのweightを自動で調整する。
運用時に注意すべき点は、weightが相対的な比率だということだ。weight: 90とweight: 10は9:1の比率であり、weight: 9とweight: 1も同じ9:1の比率だ。可読性のために合計を100に揃えることを推奨する。
トラフィックミラーリング
トラフィックミラーリングは、プロダクションのトラフィックのコピーをテスト環境へ送り、実トラフィックで検証するときに使う。ミラーされたトラフィックのレスポンスはクライアントへ返されないため、プロダクションに影響を与えない。
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: mirror-route
namespace: app
spec:
parentRefs:
- name: production-gateway
namespace: infra
sectionName: https
hostnames:
- 'api.example.com'
rules:
- name: mirror-to-staging
matches:
- path:
type: PathPrefix
value: /api
filters:
- type: RequestMirror
requestMirror:
backendRef:
name: api-staging
port: 8080
backendRefs:
- name: api-production
port: 8080
注意点がある。1つのHTTPRoute規則に複数のRequestMirrorフィルタを適用することはできない。複数の宛先へのミラーリングが必要なら、別の規則を定義するか、ミラーリング先のサービスで再度分岐する構造を設計する必要がある。
ヘッダーベースのルーティング
A/Bテストや特定のユーザーグループへ新しいバージョンを公開するときに、ヘッダーベースのルーティングを活用する。
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: header-routing
namespace: app
spec:
parentRefs:
- name: production-gateway
namespace: infra
sectionName: https
hostnames:
- 'app.example.com'
rules:
- name: beta-users
matches:
- headers:
- name: X-Beta-User
value: 'true'
backendRefs:
- name: app-beta
port: 8080
- name: internal-debug
matches:
- headers:
- name: X-Debug-Mode
value: 'enabled'
path:
type: PathPrefix
value: /api
filters:
- type: ResponseHeaderModifier
responseHeaderModifier:
add:
- name: X-Debug-Backend
value: 'debug-v2'
backendRefs:
- name: app-debug
port: 8080
- name: default
matches:
- path:
type: PathPrefix
value: /
backendRefs:
- name: app-production
port: 8080
規則の順序が重要だ。Gateway APIは最も具体的なマッチを優先して適用するが、同じ具体性を持つ規則は定義された順に評価される。ヘッダーマッチのある規則を、デフォルトの規則より先に配置する必要がある。
Rate Limiting (Envoy Gateway BackendTrafficPolicy)
Envoy GatewayはBackendTrafficPolicy CRDを通じて、グローバルなRate LimitingとローカルなRate Limitingの両方をサポートする。v1.6からは両方を同時に適用できる。
apiVersion: gateway.envoyproxy.io/v1alpha1
kind: BackendTrafficPolicy
metadata:
name: api-rate-limit
namespace: app
spec:
targetRefs:
- group: gateway.networking.k8s.io
kind: HTTPRoute
name: api-route
rateLimit:
type: Global
global:
rules:
- clientSelectors:
- headers:
- name: X-API-Key
type: Distinct
limit:
requests: 1000
unit: Hour
- clientSelectors:
- headers:
- name: X-API-Tier
value: 'premium'
limit:
requests: 10000
unit: Hour
- limit:
requests: 100
unit: Minute
この設定は3段階でRate Limitingを適用する。第一に、X-API-Keyヘッダーの固有値ごとに1時間あたり1000件を許可する。第二に、X-API-Tierがpremiumのリクエストは1時間あたり10000件まで許可する。第三に、どの条件にも該当しないリクエストは1分あたり100件に制限する。
グローバルなRate Limitingには別途RedisベースのRate Limitサービスが必要だ。Envoy GatewayをHelmでインストールするときにrateLimit.backend.redis.hostの値を設定する必要がある。
# Envoy Gatewayインストール時、グローバルRate Limitingのための Redis 設定
helm install eg oci://docker.io/envoyproxy/gateway-helm \
--version v1.6.3 \
-n envoy-gateway-system --create-namespace \
--set rateLimit.backend.redis.host=redis.infra.svc.cluster.local \
--set rateLimit.backend.redis.port=6379
ローカルなRate LimitingはRedisなしで各Envoyインスタンス自体で動作するため設定は簡単だが、Pod数によって実際の許容量が変わる点を考慮する必要がある。Envoy Podが3個でローカルの上限が1分あたり100件なら、クラスタ全体では最大で1分あたり300件が許可されうる。
Envoy Gatewayのインストールと初期設定
Helmベースのインストール
# Gateway API CRDのインストール (v1.4.0)
kubectl apply -f https://github.com/kubernetes-sigs/gateway-api/releases/download/v1.4.0/standard-install.yaml
# Envoy Gateway の Helm インストール
helm install eg oci://docker.io/envoyproxy/gateway-helm \
--version v1.6.3 \
-n envoy-gateway-system --create-namespace
# GatewayClassの確認
kubectl get gatewayclass
# NAME CONTROLLER ACCEPTED
# eg gateway.envoyproxy.io/gatewayclass-controller True
# Gateway作成後にプロキシのプロビジョニングを確認
kubectl get gateway -n infra
kubectl get pods -n envoy-gateway-system
インストール後、GatewayClassのACCEPTED状態がTrueかどうかを必ず確認する。Falseの場合はコントローラPodのログを確認する必要がある。
supportedFeaturesの確認
Gateway API v1.4からGatewayClassのstatusにsupportedFeaturesフィールドが追加された。これにより、実装がどの機能をサポートしているかをプログラム的に確認できる。
# GatewayClassがサポートする機能の一覧を確認
kubectl get gatewayclass eg -o jsonpath='{.status.supportedFeatures}' | jq .
この結果からHTTPRouteRequestMirror、HTTPRouteBackendTimeout、GRPCRouteListenerHostnameMatchingなどの機能のサポート有無を確認できるため、運用環境で特定の機能を使う前に互換性を検証するのに有用だ。
トラブルシューティング
RouteがGatewayに接続されない場合
最もよくある問題は、HTTPRouteがGatewayにattachされないことだ。次の順序で診断する。
第一に、HTTPRouteのparentRefsが正しいGatewayを参照しているかを確認する。namespaceを省略すると同じネームスペースのGatewayを探すため、別のネームスペースのGatewayを参照するときは必ずnamespaceを明示する必要がある。
第二に、GatewayのallowedRoutesの設定を確認する。from: Selectorを使う場合、HTTPRouteがあるネームスペースに該当するラベルが必要だ。ネームスペースへのラベル追加を忘れるケースが多い。
# HTTPRouteの状態確認
kubectl get httproute api-route -n app -o yaml | yq '.status'
# Gatewayリスナーの状態確認
kubectl get gateway production-gateway -n infra -o yaml | yq '.status.listeners'
# ネームスペースのラベル確認と追加
kubectl get ns app --show-labels
kubectl label ns app gateway-access=true
第三に、sectionNameが指定されている場合は、Gatewayリスナーの名前と正確に一致しているかを確認する。
トラフィックがバックエンドに到達しない場合
Routeが正常にattachされているのに502または503エラーが発生する場合は、バックエンドサービスの状態を点検する。
# バックエンドサービスとエンドポイントの確認
kubectl get svc api-service -n app
kubectl get endpoints api-service -n app
# Envoyプロキシのログ確認
kubectl logs -n envoy-gateway-system -l app.kubernetes.io/component=proxy --tail=100
# Envoyプロキシの設定ダンプ
kubectl port-forward -n envoy-gateway-system deploy/envoy-production-gateway 19000:19000 &
curl localhost:19000/config_dump | jq '.configs[] | select(.["@type"] | contains("route"))'
BackendTLSPolicyを適用している場合は、バックエンドPodのTLS証明書が正しく設定されているか、hostnameが証明書のSANと一致しているかを確認する。
Rate Limitingが動作しない場合
グローバルなRate Limitingが動作しないときのチェックリストは次のとおりだ。Redisの接続状態を確認する。Rate LimitサービスのPodが正常に動作中かを確認する。BackendTrafficPolicyのtargetRefsが正しいHTTPRouteを参照しているかを確認する。
# Rate Limitサービスの状態確認
kubectl get pods -n envoy-gateway-system -l app.kubernetes.io/component=ratelimit
# Rate Limitサービスのログ
kubectl logs -n envoy-gateway-system -l app.kubernetes.io/component=ratelimit --tail=50
# Redis接続テスト
kubectl exec -n envoy-gateway-system deploy/envoy-ratelimit -- redis-cli -h redis.infra.svc.cluster.local ping
障害事例と復旧手順
事例1: Gateway更新中のトラフィック断
Gatewayリソースのリスナーを変更するとEnvoyプロキシが再起動されることがある。プロダクション環境でリスナーを追加/削除するときに無停止を保証するには、次の手順に従う。
まずPodDisruptionBudget(PDB)を設定して最小の利用可能Pod数を保証する。Envoy Gateway v1.6ではEnvoyProxy CRDを通じてPDBを直接設定できる。変更前にEnvoyプロキシのreplica数を十分に確保する(最低2個以上)。リスナーの変更はトラフィックの少ない時間帯に実施し、変更直後にGatewayのstatus.listenersを監視して、すべてのリスナーがAccepted/Programmed状態かどうかを確認する。
事例2: 誤ったHTTPRouteのデプロイによるルーティング障害
HTTPRouteに誤ったbackendRefを指定したり、weightを0に設定したりすると、特定パスのトラフィックがドロップされる。復旧手順は次のとおりだ。
# 問題のあるHTTPRouteを即座にロールバック
kubectl rollout undo httproute api-route -n app # HTTPRouteはrolloutをサポートしていない
# 代わりに以前のバージョンのマニフェストを再適用
kubectl apply -f httproute-previous-version.yaml
# あるいはGitOps環境でgit revertした後に自動同期
git revert HEAD
git push origin main
HTTPRouteにはDeploymentのようなrollout機能がないため、必ずGitOps(ArgoCD, Flux)を通じてマニフェストをバージョン管理する必要がある。Gitの履歴がそのままロールバックのメカニズムになる。
事例3: Rate LimitのRedis障害時のトラフィック急増
グローバルなRate LimitingのRedisがダウンすると、デフォルトではEnvoyはRate Limitサービスに接続できないときにリクエストを許可(fail-open)する。これは可用性を優先する設計だが、バックエンドが急激なトラフィック増加に耐えられないことがある。
対応策として、グローバルなRate LimitingとローカルなRate Limitingを併用する。ローカルなRate LimitingはRedisに依存しないため、Redis障害時にも基本的なトラフィック保護が可能だ。Redisは必ず高可用性構成(Redis SentinelまたはRedis Cluster)でデプロイする。
運用チェックリスト
デプロイ前チェックリスト
- GatewayClassのACCEPTED状態がTrueかどうかを確認
- GatewayのすべてのリスナーがAccepted/Programmed状態かどうかを確認
- HTTPRoute/GRPCRouteのparentRefが正しいGatewayとsectionNameを参照しているかを確認
- TLS証明書の有効期限が十分かを確認 (cert-manager使用時は自動更新設定を検証)
- BackendTLSPolicyのhostnameがバックエンド証明書のSANと一致するかを確認
- Rate Limitingを設定する場合はRedisの接続状態を確認
- EnvoyプロキシのHPA設定が想定トラフィックを収容できるかを確認
モニタリングチェックリスト
- Gatewayリソースのstatus.conditionsを定期的にモニタリング
- Envoyプロキシのメトリクス(リクエスト数、レイテンシ、エラー率)をPrometheus/Grafanaで収集
- Rate Limitのヒット回数をモニタリングして閾値の妥当性を検証
- TLS証明書の有効期限アラートを設定 (最低14日前)
- EnvoyプロキシPodのリソース使用量(CPU, Memory)をモニタリング
アップグレードチェックリスト
- Gateway API CRDのバージョンとEnvoy Gatewayのバージョンの互換性マトリクスを確認
- CRDを先にアップグレードしてからコントローラをアップグレード
- アップグレード前に既存リソースのバックアップを実施 (
kubectl get gateway,httproute,grpcroute -A -o yaml) - ステージング環境で先にアップグレードを検証
- アップグレード後、すべてのRouteのattach状態とトラフィックが正常に流れることを確認
Ingressからのマイグレーションチェックリスト
ingress2gatewayツールを使って既存のIngressをGateway APIリソースへ変換- 変換されたリソースを手動でレビューし、アノテーションベースの設定が正しくマッピングされたかを確認
- IngressとGateway APIを同時に運用しながら段階的にトラフィックを移行
- DNSの切り替えは最後の段階で実施し、以前のIngressはロールバック用に最低1週間維持
# ingress2gatewayツールを使った変換
go install github.com/kubernetes-sigs/ingress2gateway@latest
ingress2gateway print --providers ingress-nginx --all-namespaces
# 変換結果をファイルへ保存して確認
ingress2gateway print --providers ingress-nginx --all-namespaces > gateway-resources.yaml
まとめ
Gateway APIは2026年現在、Kubernetesネットワーキングの新しい標準として確固たる地位を築いた。v1.4でBackendTLSPolicy、Named Rules、supportedFeaturesがStandardチャネルへ昇格し、運用環境での信頼性が大きく高まった。Envoy Gateway v1.6は、グローバル/ローカルのRate Limitingの同時適用、SecurityPolicyのTCPRoute拡張、mTLS設定などエンタープライズの要求を満たす機能を備えている。
既存のIngressからの移行を計画しているなら、ingress2gatewayツールを活用した段階的なマイグレーションを推奨する。Gateway APIと既存のIngressは同一クラスタで共存できるため、サービス単位で安全に移行できる。最も重要なのは、GitOpsによるマニフェストのバージョン管理と、十分なモニタリング/アラート体制を構築することだ。