2026年K8s Gateway API移行完全ガイド:IngressからGateway APIへ

云原生

2026年K8s Gateway API移行完全ガイド:IngressからGateway APIへ

もし2026年になってもKubernetes Ingressでクラスタートラフィックを管理しているなら、クラウドネイティブトラフィック管理の未来を見逃している。Gateway APIは2025年末にKubernetes GA APIとして正式になり、主要ベンダー(Istio、Contour、Traefik、Kong)が全面的にサポートしている。Ingressの設計上の欠陥——単一ロール、拡張性が低い、複雑なルーティングを表現できない——は、マイクロサービスの規模が爆発的に増加する今日、もはや受け入れられない。

Gateway APIは、Gateway、GatewayClass、HTTPRouteなどのロール分離APIを導入し、マルチチーム協調、マルチクラスター展開、トラフィック分割とミラーリングをサポートしている。本記事では、アーキテクチャ比較から始め、完全な移行ステップを提供し、トラフィック管理、マルチテナント、マルチクラスターのシナリオをカバーする。

なぜGateway APIがIngressに取って代わるのか?

比較項目 Ingress Gateway API
API成熟度 GA(ただし進化は停止) GA(2025.11)
ロール分離 なし(すべてクラスター管理者が管理) 3ロール(インフラ/クラスター/アプリ)
ルーティング表現力 限定的(path+host) 強力(header/query/weight/mirror)
マルチプロトコルサポート HTTP/HTTPSのみ HTTP/TLS/TCP/UDP/gRPC
トラフィック分割 annotation hackが必要 ネイティブサポート(weightフィールド)
マルチテナント サポートなし ネイティブサポート(ネームスペース分離)
拡張性 annotationに依存 ネイティブ拡張(PolicyAttachment)
クロスクラスター サポートなし Multi-cluster Gatewayをサポート

核心の違い:Ingressはすべての設定を混在させるが、Gateway APIはロール分離を実現している——インフラチームがGatewayClassを管理し、運用チームがGatewayを管理し、開発チームがRouteを管理する。


一、アーキテクチャ比較

1.1 Ingressアーキテクチャ

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: my-app
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: /$2
    nginx.ingress.kubernetes.io/canary: "true"
    nginx.ingress.kubernetes.io/canary-weight: "10"
spec:
  rules:
  - host: api.example.com
    http:
      paths:
      - path: /v1/users(/|$)(.*)
        pathType: Prefix
        backend:
          service:
            name: user-service
            port:
              number: 8080

問題:すべての設定が1つのIngressオブジェクトに詰め込まれ、annotationが乱立し、異なるベンダーのannotationは互換性がない。

1.2 Gateway APIアーキテクチャ

apiVersion: gateway.networking.k8s.io/v1
kind: GatewayClass
metadata:
  name: istio
spec:
  controllerName: istio.io/gateway-controller
---
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
  name: api-gateway
  namespace: infra
spec:
  gatewayClassName: istio
  listeners:
  - name: http
    port: 80
    protocol: HTTP
    allowedRoutes:
      namespaces:
        from: Selector
        selector:
          matchLabels:
            shared-gateway-access: "true"
---
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: user-route
  namespace: app-team
spec:
  parentRefs:
  - name: api-gateway
    namespace: infra
  rules:
  - matches:
    - path:
        type: PathPrefix
        value: /v1/users
    backendRefs:
    - name: user-service
      port: 8080
      weight: 90
    - name: user-service-canary
      port: 8080
      weight: 10

利点:ロールが明確——GatewayClassはプラットフォームチームが定義し、Gatewayは運用チームが設定し、HTTPRouteは開発チームが管理する。


二、ステップバイステップ移行ガイド

2.1 Gateway API CRDのインストール

kubectl apply -f https://github.com/kubernetes-sigs/gateway-api/releases/download/v1.2.0/standard-install.yaml

2.2 コントローラーのインストール(Istioの場合)

istioctl install --set profile=minimal
kubectl apply -f - <<EOF
apiVersion: gateway.networking.k8s.io/v1
kind: GatewayClass
metadata:
  name: istio
spec:
  controllerName: istio.io/gateway-controller
EOF

2.3 IngressからGateway+HTTPRouteへの移行

移行スクリプトの考え方

for ingress in $(kubectl get ingress -A -o name); do
  namespace=$(echo $ingress | cut -d'/' -f1 | cut -d'.' -f1)
  name=$(echo $ingress | cut -d'/' -f2)

  kubectl get $ingress -o yaml | python3 ingress2gateway.py > gateway-route.yaml
  kubectl apply -f gateway-route.yaml

  echo "Migrated $ingress, verify before deleting"
done

2.4 自動移行ツール

import yaml
import sys

def ingress_to_gateway_route(ingress_data):
    metadata = ingress_data['metadata']
    spec = ingress_data['spec']

    gateway = {
        'apiVersion': 'gateway.networking.k8s.io/v1',
        'kind': 'Gateway',
        'metadata': {
            'name': f"{metadata['name']}-gateway",
            'namespace': metadata.get('namespace', 'default'),
        },
        'spec': {
            'gatewayClassName': 'istio',
            'listeners': [],
        },
    }

    routes = []
    for rule in spec.get('rules', []):
        host = rule.get('host', '*')
        listener_name = f"http-{host.replace('.', '-')}" if host != '*' else 'http'

        gateway['spec']['listeners'].append({
            'name': listener_name,
            'port': 80,
            'protocol': 'HTTP',
            'hostname': host if host != '*' else None,
        })

        for path in rule.get('http', {}).get('paths', []):
            route = {
                'apiVersion': 'gateway.networking.k8s.io/v1',
                'kind': 'HTTPRoute',
                'metadata': {
                    'name': f"{metadata['name']}-route",
                    'namespace': metadata.get('namespace', 'default'),
                },
                'spec': {
                    'parentRefs': [{'name': f"{metadata['name']}-gateway"}],
                    'rules': [{
                        'matches': [{
                            'path': {
                                'type': 'PathPrefix',
                                'value': path.get('path', '/'),
                            }
                        }],
                        'backendRefs': [{
                            'name': path['backend']['service']['name'],
                            'port': path['backend']['service']['port']['number'],
                        }],
                    }],
                },
            }
            routes.append(route)

    return gateway, routes

if __name__ == '__main__':
    ingress = yaml.safe_load(sys.stdin)
    gw, routes = ingress_to_gateway_route(ingress)
    for doc in [gw] + routes:
        print('---')
        print(yaml.dump(doc, default_flow_style=False))

三、トラフィック管理

3.1 トラフィック分割(カナリアリリース)

apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: canary-route
spec:
  parentRefs:
  - name: api-gateway
  rules:
  - matches:
    - path:
        type: PathPrefix
        value: /api/v2
    backendRefs:
    - name: api-v2-stable
      port: 8080
      weight: 95
    - name: api-v2-canary
      port: 8080
      weight: 5

3.2 トラフィックミラーリング

apiVersion: gateway.networking.k8s.io/v1alpha2
kind: HTTPRouteFilter
metadata:
  name: mirror-filter
spec:
  type: RequestMirror
  requestMirror:
    backendRef:
      name: api-mirror
      port: 8080

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

apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: header-route
spec:
  parentRefs:
  - name: api-gateway
  rules:
  - matches:
    - headers:
      - type: Exact
        name: X-Feature-Flag
        value: new-ui
    backendRefs:
    - name: frontend-v2
      port: 80
  - matches:
    - path:
        type: PathPrefix
        value: /
    backendRefs:
    - name: frontend-v1
      port: 80

3.4 gRPCルーティング

apiVersion: gateway.networking.k8s.io/v1
kind: GRPCRoute
metadata:
  name: grpc-route
spec:
  parentRefs:
  - name: api-gateway
  rules:
  - matches:
    - method:
        service: "com.example.UserService"
        method: "GetUser"
    backendRefs:
    - name: user-grpc-service
      port: 50051

四、マルチクラスターとマルチテナント

4.1 マルチクラスターGateway

apiVersion: gateway.networking.k8s.io/v1beta1
kind: ReferenceGrant
metadata:
  name: allow-cross-namespace
  namespace: app-team
spec:
  from:
  - group: gateway.networking.k8s.io
    kind: HTTPRoute
    namespace: infra
  to:
  - group: ""
    kind: Service

4.2 マルチテナント分離

apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
  name: tenant-a-gateway
  namespace: tenant-a
spec:
  gatewayClassName: istio
  listeners:
  - name: http
    port: 80
    protocol: HTTP
    allowedRoutes:
      namespaces:
        from: Same

テナント分離戦略比較

戦略 分離レベル リソースオーバーヘッド 管理の複雑さ 適用シナリオ
共有Gateway Routeレベル 小規模、信頼できるテナント
ネームスペース分離 ネームスペースレベル 中規模、一般的な分離
独立Gateway Gatewayレベル 大規模、厳密な分離要件

5つのよくある落とし穴

# 落とし穴 結果 解決策
1 Ingressを削除してからGatewayを作成 トラフィック中断 まず並行稼働させ、検証後に削除
2 HTTPRouteが他のネームスペースのGatewayを参照 認可が拒否される ReferenceGrantを作成
3 GatewayのallowedRoutesが厳密すぎる Routeがバインドできない ネームスペースセレクターを確認
4 GatewayClassのパラメータを無視 コントローラーの動作が期待と異なる GatewayClassSpec.parametersRefを慎重に確認
5 トラフィック分割のウェイト合計が100でない 動作が未定義(実装依存) ウェイト合計が100になることを確認

10のよくあるエラートラブルシューティング

# エラー現象 考えられる原因 トラブルシューティング方法
1 HTTPRouteのParents条件がAccepted: False Gatewayがそのネームスペースを許可していない GatewayのallowedRoutesを確認
2 トラフィックがバックエンドに到達しない Routeマッチングルールが間違っている kubectl describe httprouteでResolvedRefsを確認
3 GatewayNotReady コントローラーがインストールされていないか実行されていない GatewayClassとコントローラーPodを確認
4 TLS証明書が有効にならない 証明書Secretが存在しないか形式エラー Secretのタイプがkubernetes.io/tlsであることを確認
5 カナリアトラフィックの比率が正しくない ウェイトの計算エラー ウェイト合計が100で比率が正しいことを確認
6 クロスネームスペース参照が拒否される ReferenceGrantが不足 クロスネームスペース参照を許可するReferenceGrantを作成
7 GRPCRouteが有効にならない GatewayリスナーにH2Cが設定されていない protocol: HTTPのリスナーを追加しH2Cを有効化
8 トラフィックミラーリングが動作しない コントローラーがRequestMirrorをサポートしていない コントローラー実装がこの拡張をサポートしていることを確認
9 Gateway IPが割り当てられない コントローラーにLBが設定されていない コントローラーのServiceとLoadBalancerを確認
10 移行後にパフォーマンスが低下 コントローラー設定が最適化されていない IngressとGatewayのプロキシ設定を比較

おすすめツール

Gateway API移行プロセスで、以下のツールが設定やエンコードの問題処理に役立つ:


まとめ:Gateway APIはIngressの「アップグレード版」ではなく、トラフィック管理の「再設計」である。3ロール分離により、プラットフォーム、運用、開発がそれぞれの役割を担う。ネイティブトラフィック分割により、カナリアリリースはもうannotation hackに依存しない。マルチプロトコルサポートにより、gRPCやTCPサービスも統一されたトラフィック管理を享受できる。2026年、Ingressはすでにメンテナンスモードに入り、Gateway APIが唯一の方向である。移行の核心原則:まず並行稼働、次に検証、最後に切り替え——一度に切り替えず、IngressとGateway APIをしばらく共存させ、トラフィックが正常であることを確認してからIngressを削除する。

ブラウザローカルツールを無料で試す →

#K8s Gateway API#Ingress迁移#服务网格#流量管理#2026