•18 min read

Kubernetes Gateway API本番環境での利用: Ingress-NginxからEnvoyへの移行

Kubernetes Gateway API本番環境での利用: Ingress-NginxからEnvoyへの移行

Kubernetes Ingress APIは基盤となるものですが、複雑なトラフィック管理においては、表現力、役割の分離、拡張性に限界があります。その後継であるGateway APIは、よりきめ細かく、役割指向の設計と堅牢な拡張メカニズムを導入することで、これらの欠点を解消します。このガイドでは、Envoyプロキシを基盤とするEnvoy GatewayまたはCilium Gatewayに焦点を当て、ingress-nginxからEnvoyベースのGateway API実装への本番環境移行戦略について詳しく説明します。

Audio Briefing
0:00 / 0:00

Gateway APIの基本を理解する

Gateway APIは階層構造を導入しています。

  1. GatewayClass: Gatewayのクラスを定義し、それを実装するコントローラー(例:envoy-gateway-class、cilium-gateway-class)を指定します。これは通常、インフラプロバイダーまたはクラスター管理者によって管理されます。
  2. Gateway: ロードバランサーの特定のインスタンスを表し、ポートとプロトコルを公開します。これはインフラオペレーターまたはプラットフォームチームによってプロビジョニングされます。
  3. HTTPRoute / GRPCRoute / TLSRoute / TCPRoute / UDPRoute: プロトコル固有のルーティングルールを定義し、Gatewayにアタッチします。これらは通常、アプリケーション開発者によって管理されます。

この役割指向の設計は関心を分離します。インフラチームはGatewayClassとGatewayリソースを管理し、アプリケーションチームはRouteリソースを管理することで、インフラを直接変更することなくセルフサービスを可能にします。

Advertisement

移行戦略の概要

段階的でダウンタイムのない移行が重要です。この戦略には以下が含まれます。

  1. 並行デプロイ: 既存のingress-nginxと並行してGateway APIコントローラーとリソースをデプロイします。
  2. DNS切り替え: ingress-nginxロードバランサーIPからGateway APIロードバランサーIPへトラフィックを段階的に移行します。
  3. 検証: 完全な切り替えの前に、新しいパスを徹底的にテストします。
  4. ロールバック計画: 新しいシステムが完全に検証されるまでingress-nginxを維持します。

前提条件

  • Kubernetesクラスター(Gateway APIにはv1.20+を推奨)。
  • 自動TLS用にcert-managerがインストールされていること。
  • kubectlおよびhelm CLIツール。
  • 既存のingress-nginxデプロイメント。

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

ここではEnvoy Gatewayを主要な例として使用しますが、Cilium Gatewayも同様のパターンに従い、CiliumのeBPFデータプレーンを活用します。

オプションA:Envoy Gatewayのデプロイ

# gateway-api-crd-install.yaml
# Install Gateway API CRDs if not already present in your cluster.
# This is a prerequisite for any Gateway API controller.
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
  name: gatewayclasses.gateway.networking.k8s.io
spec:
  group: gateway.networking.k8s.io
  names:
    kind: GatewayClass
    listKind: GatewayClassList
    plural: gatewayclasses
    singular: gatewayclass
  scope: Cluster
  versions:
    - name: v1
      served: true
      storage: true
      schema:
        openAPIV3Schema:
          type: object
          x-kubernetes-preserve-unknown-fields: true
      subresources:
        status: {}
---
# ... other Gateway API CRDs (Gateway, HTTPRoute, etc.) ...
# For brevity, full CRD definitions are omitted.
# You can find them at https://github.com/kubernetes-sigs/gateway-api/releases

# Install Envoy Gateway via Helm
# Add the Envoy Gateway Helm repository
helm repo add envoy-gateway https://envoyproxy.github.io/envoy-gateway/
helm repo update

# Install Envoy Gateway into the 'envoy-gateway-system' namespace
helm install envoy-gateway envoy-gateway/envoy-gateway \
  --create-namespace \
  --namespace envoy-gateway-system \
  --version v0.8.0 # Use the latest stable version

デプロイを確認します。

kubectl get pods -n envoy-gateway-system
kubectl get gatewayclass

EnvoyGatewayポッドが実行され、eg(Envoy Gatewayのデフォルト)または類似のGatewayClassが表示されるはずです。

オプションB:Cilium Gatewayのデプロイ(代替)

CiliumをCNIとしてすでに使用している場合、Cilium GatewayはeBPFを活用した高度に統合されたソリューションを提供します。

# Install Cilium with Gateway API support
helm upgrade --install cilium cilium/cilium \
  --namespace kube-system \
  --set gatewayAPI.enabled=true \
  --set gatewayAPI.nodePort.enabled=true # Or LoadBalancer, depending on your cloud provider
  # ... other Cilium configurations ...

デプロイを確認します。

kubectl get pods -n kube-system -l k8s-app=cilium
kubectl get gatewayclass

ciliumまたは類似のGatewayClassが表示されるはずです。

ステップ2:GatewayおよびHTTPRouteリソースの定義

このステップでは、外部ロードバランサーをプロビジョニングするGatewayリソースと、ルーティングルールを定義するHTTPRouteリソースを作成します。

Gatewayの定義

このGatewayリソースは、クラウドロードバランサーをプロビジョニングし、ポート80と443を公開します。

# gateway.yaml
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
  name: my-app-gateway
  namespace: default # Or your designated ingress namespace
spec:
  gatewayClassName: eg # Use 'eg' for Envoy Gateway, 'cilium' for Cilium Gateway
  listeners:
    - name: http
      protocol: HTTP
      port: 80
      allowedRoutes:
        namespaces:
          from: All # Allow HTTPRoutes from any namespace to attach
    - name: https
      protocol: HTTPS
      port: 443
      tls:
        mode: Terminate
        certificateRefs:
          - kind: Secret
            name: my-app-tls-secret # This secret will be provisioned by cert-manager
      allowedRoutes:
        namespaces:
          from: All # Allow HTTPRoutes from any namespace to attach

これを適用します: kubectl apply -f gateway.yaml

Gatewayがプロビジョニングされるまで待ちます。そのステータスを確認します。

kubectl get gateway my-app-gateway -n default -o yaml

プロビジョニングされたロードバランサーの外部IPまたはホスト名を取得するには、status.addressesを探します。これが新しいエントリポイントになります。

cert-managerによる自動TLS

cert-managerがインストールされ、設定されていることを確認してください。TLSシークレットをプロビジョニングするためにCertificateリソースを使用します。

# cert-manager-certificate.yaml
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
  name: my-app-tls-certificate
  namespace: default
spec:
  secretName: my-app-tls-secret # Matches the name in Gateway listener
  dnsNames:
    - myapp.example.com
    - www.myapp.example.com
  issuerRef:
    name: letsencrypt-prod # Or your preferred ClusterIssuer/Issuer
    kind: ClusterIssuer
    group: cert-manager.io

これを適用します: kubectl apply -f cert-manager-certificate.yaml

シークレットが作成されたことを確認します: kubectl get secret my-app-tls-secret -n default

HTTPRouteの定義

次に、バックエンドサービスにトラフィックを転送するためのHTTPRouteを定義します。この例には、パスベースのルーティングとカナリアデプロイメントのための重み付けされたトラフィックスプリットが含まれています。

# httproute.yaml
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: my-app-route
  namespace: default # Namespace where your application service resides
spec:
  parentRefs:
    - name: my-app-gateway # Attach to the Gateway defined above
      namespace: default
  hostnames:
    - "myapp.example.com"
    - "www.myapp.example.com"
  rules:
    - matches:
        - path:
            type: PathPrefix
            value: /api/v1/
      backendRefs:
        - name: my-app-service-v1 # Existing stable service
          port: 80
          weight: 90 # 90% of traffic to v1
        - name: my-app-service-v2 # New canary service
          port: 80
          weight: 10 # 10% of traffic to v2
    - matches:
        - path:
            type: PathPrefix
            value: /
      backendRefs:
        - name: my-app-service-v1 # Default route for all other paths
          port: 80

これを適用します: kubectl apply -f httproute.yaml

default名前空間にmy-app-service-v1とmy-app-service-v2(およびそれに対応するデプロイメント)が存在することを確認してください。

Advertisement

ステップ3:DNS切り替え戦略

これはダウンタイムゼロを実現するための最も重要なフェーズです。

  1. 新しいロードバランサーIP/ホスト名の特定: kubectl get gateway my-app-gateway -n default -o jsonpath='{.status.addresses[0].value}'からこれを入手します。
  2. DNSレコードの更新:
    • CNAME(クラウドロードバランサーに推奨): Gatewayがホスト名(例:a123.us-east-1.elb.amazonaws.com)をプロビジョニングする場合、myapp.example.comのCNAMEレコードをこの新しいホスト名に更新します。
    • Aレコード: GatewayがIPアドレスをプロビジョニングする場合、myapp.example.comのAレコードをこの新しいIPに更新します。
  3. 段階的なDNS更新(オプションだが推奨):
    • TTLの短縮: 切り替えの前に、myapp.example.comのDNSレコードのTTL(Time To Live)を非常に低い値(例:60秒)に短縮します。これにより、変更が迅速に伝播されます。
    • 段階的な移行: 可能であれば、重み付けされたDNSレコード(例:AWS Route 53の重み付けルーティングポリシー)をサポートするDNSプロバイダーを使用して、古いingress-nginx IPから新しいGateway API IPへトラフィックを段階的に移行します。これにより、制御されたパーセンテージベースの切り替えが可能になります。
    • ブルー/グリーンDNS: よりシンプルなアプローチは、DNSレコードを直接更新することです。DNSキャッシュのため、これはクライアントにとっては依然として段階的な移行となります。

DNS更新の例(概念的、myapp.example.comを使用):

# Before migration (pointing to ingress-nginx LB)
myapp.example.com.  300 IN  A   192.0.2.100

# During migration (after Gateway API LB is ready)
# Option 1: CNAME (if Gateway provides hostname)
myapp.example.com.  60  IN  CNAME   a123.us-east-1.elb.amazonaws.com.

# Option 2: A Record (if Gateway provides IP)
myapp.example.com.  60  IN  A   203.0.113.200

# After full validation, revert TTL to a higher value (e.g., 3600)
myapp.example.com.  3600 IN CNAME   a123.us-east-1.elb.amazonaws.com.

ステップ4:検証と監視

徹底的な検証が最も重要です。

  1. 直接アクセス: DNS切り替えの前に、新しいGateway APIエンドポイントにそのIP/ホスト名を使用して直接テストします。
  2. ヘルスチェック: すべてのバックエンドサービスが正常であることを確認します。
  3. アプリケーションログ: アプリケーションログでエラーを監視します。
  4. メトリクス: 古いingress-nginxパスと新しいGateway APIパスの間で、レイテンシ、エラー率、スループットを比較します。Envoy Gatewayは、スクレイピング可能なPrometheusメトリクスを公開しています。
  5. カナリアテスト: HTTPRouteの重み付けされたトラフィックスプリットを活用して、少数のユーザーを新しいパスに段階的に公開します。綿密に監視します。
  6. エンドツーエンドテスト: 新しいエンドポイントに対して自動E2Eテストスイートを実行します。

本番環境での落とし穴とトラブルシューティング

1. GatewayがPending状態のままになる

  • 症状: kubectl get gateway my-app-gatewayがReady: Falseとmessage: "Gateway is not ready"でstatus.conditionsを表示する。
  • 原因: 基盤となるクラウドロードバランサーのプロビジョニングに失敗したか、Gatewayコントローラーでエラーが発生した。
  • 修正:
    • コントローラーログを確認する: kubectl logs -n envoy-gateway-system -l app.kubernetes.io/name=envoy-gateway。クラウドプロバイダーAPI呼び出しに関連するエラーを探す。
    • クラウドプロバイダーのクォータを確認する: ロードバランサーのクォータが十分にあることを確認する。
    • Kubernetesイベントを確認する: kubectl describe gateway my-app-gateway。

2. HTTPRouteがGatewayにアタッチされない

  • 症状: kubectl get httproute my-app-route -o yamlがconditionsでstatus.parentsを表示し、ResolvedRefs: FalseまたはAccepted: Falseを示す。
  • 原因: parentRefs(名前、名前空間)の不一致、またはGateway上のallowedRoutes設定。
  • 修正:
    • HTTPRouteのparentRefs.nameとparentRefs.namespaceが、Gatewayの名前と名前空間に正確に一致することを確認する。
    • Gateway.spec.listeners.allowedRoutes.namespaces.fromが正しく設定されていることを確認する(例:AllまたはSelectorがHTTPRouteの名前空間と一致する)。
    • GatewayとHTTPRouteのイベントを確認する: kubectl describe gateway my-app-gatewayとkubectl describe httproute my-app-route。

3. TLSハンドシェイクエラー

  • 症状: クライアントがSSL_PROTOCOL_ERRORまたはcertificate_unknownエラーを報告する。
  • 原因: GatewayのcertificateRefが間違っている、cert-managerの失敗、またはtls.modeが間違っている。
  • 修正:
    • Gateway.spec.listeners.tls.certificateRefsが正しいSecret名と名前空間を指していることを確認する。
    • cert-manager CertificateとCertificateRequestリソースを確認する: kubectl get certificate my-app-tls-certificate -n default -o yaml。Ready: Trueを確認する。
    • cert-managerコントローラーログを検査する: kubectl logs -n cert-manager -l app.kubernetes.io/instance=cert-manager。
    • エッジTLS終端のためにtls.modeがTerminateであることを確認する。

4. 重み付けされたトラフィックスプリットが機能しない

  • 症状: トラフィックの分散がweight設定と一致しない、またはすべてのトラフィックが1つのバックエンドに流れる。
  • 原因: backendRefsの設定ミス、またはサービスディスカバリの問題。
  • 修正:
    • HTTPRoute.spec.rules.backendRefs.weightの値を再確認する。複数のルールが適用される場合は、それらが正しく合計されていることを確認する。
    • backendRefs.nameとbackendRefs.portがKubernetesのServiceリソースを正しく指していることを確認する。
    • バックエンドサービス用のServiceとEndpointSliceリソースを確認し、正常なポッドがあることを確認する。
    • Envoy Gatewayのログでルーティングエラーを監視する。

5. 移行後のパフォーマンス低下

  • 症状: レイテンシの増加、エラー率の上昇、またはスループットの低下。
  • 原因: GatewayコントローラーまたはEnvoyプロキシポッドのリソース制約、Envoyプロキシ設定の誤り、またはネットワークの問題。
  • 修正:
    • リソース制限: Envoy GatewayコントローラーとEnvoyプロキシポッドのCPU/メモリ制限を増やす。
    • Envoy設定: 高度なチューニングの場合、バッファサイズ、接続制限、またはその他のEnvoy固有の設定を調整するために、EnvoyProxyリソース(Envoy Gatewayを使用している場合)をカスタマイズする必要があるかもしれません。
    • ネットワークパス: Gatewayロードバランサーとバックエンドポッド間のネットワーク接続とレイテンシを確認する。
    • メトリクス: Prometheus/Grafanaを使用してEnvoyメトリクス(例:envoy_cluster_upstream_rq_total、envoy_server_uptime)を監視する。

アーキテクチャ比較:Ingress-Nginx vs. Gateway API (Envoy)

機能Ingress-NginxGateway API (Envoy Gateway)
APIモデルIngress, IngressClassGatewayClass, Gateway, HTTPRouteなど
役割分離限定的(管理者がIngressClassを管理、開発者がIngressを管理)強力(インフラ: GatewayClass、オペレーター: Gateway、開発者: Route)
拡張性アノテーション、Nginx ConfigMapポリシーアタッチメント(例:HTTPRouteFilter)、EnvoyProxy CRD
トラフィックスプリットアノテーション(例:nginx.ingress.kubernetes.io/canary)HTTPRouteにおけるファーストクラスのbackendRefs.weight
マルチクラスターネイティブではサポートされていないマルチクラスター/マルチテナント向けに設計
プロトコルサポートHTTP/HTTPS、TCP/UDP(externalNameまたはstream-snippets経由)HTTP/HTTPS、gRPC、TCP、UDP、TLS(ネイティブCRD)
実装NginxEnvoy Proxy
TLS管理Ingressアノテーション経由のcert-managerGateway.spec.listeners.tls.certificateRefs経由のcert-manager

よくある質問

1. ingress-nginxとGateway APIを同時に実行できますか?

はい、これは段階的な移行に推奨されるアプローチです。これらは独立して動作し、それぞれ独自のロードバランサーをプロビジョニングします。DNSを管理して、どちらか一方にトラフィックを誘導します。

2. カスタムLuaスクリプトや特定のNginxディレクティブのような高度なNginx設定はどのように扱いますか?

Envoy Gatewayの場合、通常はEnvoyProxyカスタムリソースを使用して高度なEnvoy設定を適用します。これにより、基盤となるEnvoyプロキシの設定を直接操作できます。Cilium Gatewayの場合、Ciliumのネットワークポリシーと、高度なEnvoy機能のためのCiliumEnvoyConfigリソースを活用します。Gateway API自体は標準的なルーティングに焦点を当てており、コントローラー固有のCRDが拡張性を提供します。

3. Envoyを使用したGateway APIへの移行がパフォーマンスに与える影響は何ですか?

Envoyは高性能なプロキシであり、特にHTTP/2やgRPCの特定のワークロードではNginxよりも優れたパフォーマンスを発揮することがよくあります。適切なリソース割り当てを前提とすれば、パフォーマンスへの影響は一般的に肯定的または中立的です。重要なのは、Envoy GatewayコントローラーとEnvoyプロキシポッドの適切な設定とリソースプロビジョニングです。

4. Gateway APIでのクロスネームスペースルーティングはどのように機能しますか?

Gateway.spec.listeners.allowedRoutesフィールドは、どの名前空間が特定のGatewayにRouteリソースをアタッチすることを許可されているかを制御します。All、Same、またはSelectorを指定して、Routeのアタッチメントを制限または許可し、安全なマルチテナント環境を可能にすることができます。例えば、from: Allは任意の名前空間を許可し、from: SelectorとnamespaceSelectorは特定のラベルに一致する名前空間のみを許可します。

5. Gateway APIは本番環境で使用できますか?

はい、Gateway APIは2023年10月にv1のGA(一般提供)に昇格しました。Envoy GatewayやCilium Gatewayのようなコントローラーは活発に開発されており、本番環境で使用されています。これはKubernetesにおけるIngressとトラフィック管理の未来と考えられています。

Share this article:

Stay Updated

Get the latest posts delivered straight to your inbox.

Free Developer Utilities

Free In-Browser Developer Tools

Clean AI CLI logs, build cron expressions, decode JWTs, and calculate chmod permissions offline.

Explore Tools
Advertisement