0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Ingress NGINX が2026年3月に廃止へ:今すぐ始めるべき移行対策

Posted at

はじめに

Kubernetesコミュニティから重要な発表がありました。長年にわたり多くのクラスタで使用されてきた Ingress NGINX コントローラーが2026年3月で廃止 されることが決定しました。

本記事では、この廃止決定の背景と、ユーザーが今すぐ取るべきアクションプランについて解説します。

何が起こるのか

Kubernetes SIG NetworkとSecurity Response Committeeが、Ingress NGINXプロジェクトの廃止を発表しました。

タイムライン

  • 現在〜2026年3月まで: ベストエフォートでのメンテナンス継続
  • 2026年3月以降:
    • 新しいリリースなし
    • バグ修正なし
    • セキュリティアップデートなし
    • GitHubリポジトリは読み取り専用に

既存デプロイメントへの影響

  • 既にデプロイされているIngress NGINXは そのまま動き続けます
  • インストール用のアーティファクトも引き続き利用可能
  • ただし、セキュリティパッチが提供されなくなる ため、徐々にリスクが高まります

詳細な影響分析

Ingress NGINXの廃止は、利用規模や使用方法によって異なる影響をもたらします。以下、ステークホルダー別、技術領域別に詳細を解説します。

1. セキュリティへの影響(重大度: 最高)

2026年3月以降に予想されるセキュリティリスク

CVE(脆弱性)への対応不可

  • 2026年3月以降に発見される脆弱性は パッチが提供されません
  • 過去の例: Ingress NGINXでは年間5〜10件程度の脆弱性が報告されています
  • 特に重大な脆弱性(CVSSスコア9.0以上)も過去に複数発生

具体的なリスクシナリオ:

  1. リモートコード実行(RCE)脆弱性の発見

    • 攻撃者がIngress経由でクラスタ内のPodを制御可能に
    • 最悪の場合、Kubernetesクラスタ全体の侵害につながる
    • 影響範囲: すべての公開サービス
  2. TLS/SSL関連の脆弱性

    • 通信の盗聴、中間者攻撃のリスク
    • 証明書検証のバイパス
    • 影響範囲: すべてのHTTPS通信
  3. Snippet Annotationを悪用した攻撃

    • 既に知られているセキュリティリスク
    • パッチ提供が終了することで、既知の脆弱性も放置されることに
    • RBACの設定ミスがあると、開発者がIngressを作成するだけで任意コード実行が可能
  4. 依存ライブラリの脆弱性

    • NGINXコア、OpenSSL、Lua拡張などの脆弱性
    • これらの依存関係が更新されないため、既知の脆弱性を抱え続ける

コンプライアンスへの影響:

  • PCI DSS: セキュリティパッチの適用が要件(要件6.2)
  • SOC 2: 脆弱性管理プロセスの証明が必要
  • ISO 27001: リスク評価でサポート終了製品の使用は重大な指摘事項に
  • GDPR: 個人データを扱うシステムでのサポート終了製品使用は「適切な技術的対策」に反する可能性

セキュリティ監査での指摘

  • ペネトレーションテストで既知の脆弱性が検出される
  • 監査レポートで「Critical」や「High」の指摘を受ける
  • 保険会社からサイバーセキュリティ保険の更新拒否や条件変更の可能性

2. 運用への影響(重大度: 高)

サポート体制の変化

問題発生時の対応:

  • 公式のGitHub Issuesが受け付けられなくなる
  • StackOverflow等のコミュニティ頼みに(回答の質・速度が不確実)
  • エンタープライズサポート契約(有償)も終了

トラブルシューティングの困難化:

  • 新しいKubernetesバージョンとの非互換性が発生する可能性
  • クラウドプロバイダーのロードバランサー変更に追従できない
  • 他のエコシステムツール(cert-manager、external-dns等)との統合問題

インシデント対応への影響

平均復旧時間(MTTR)の増加:

  • 公式ドキュメントが更新されないため、新しい環境での情報が不足
  • 問題の根本原因特定に時間がかかる
  • ワークアラウンドの実装が必要になる場合がある

オンコール対応の負担増:

  • 既知の問題でも解決策が見つからないケースが増える
  • エスカレーション先がなくなる(自社での解決が必須)

3. 技術的互換性への影響(重大度: 中〜高)

Kubernetesバージョンアップへの制約

2026年以降のKubernetes新バージョンへの対応:

  • Kubernetes v1.32以降とIngress NGINX間の互換性が未検証に
  • 非推奨API(例: Ingress v1beta1)の削除に対応できない可能性
  • 新しいKubernetesの機能(Topology Aware Routing等)を活用できない

具体例:

# 将来的に動作しなくなる可能性のある設定
apiVersion: networking.k8s.io/v1beta1  # 既に非推奨
kind: Ingress
metadata:
  annotations:
    nginx.ingress.kubernetes.io/configuration-snippet: |
      # この機能自体が将来のk8sで動作保証されない

クラウドプロバイダーのアップデートへの対応

マネージドKubernetesサービスでの影響:

プロバイダー 影響
Amazon EKS ALB/NLBの新機能との統合が困難に。EKS addon提供が終了する可能性
Google GKE Cloud Load Balancingとの統合改善が反映されない
Azure AKS Application Gateway統合のアップデートが受けられない

具体的な問題例:

  • AWS: 新しいALBの機能(例: Mutual TLS)が使えない
  • GCP: HTTP/3対応などの新機能が利用不可
  • Azure: Private Linkの新しい統合方法に非対応

4. 開発生産性への影響(重大度: 中)

開発者体験の低下

新規メンバーのオンボーディング:

  • 最新のベストプラクティスが学べない(情報が古くなる)
  • コミュニティからの学習リソースが減少
  • 「なぜサポート終了のツールを使っているのか」という疑問に答える必要

新機能開発の制約:

  • HTTP/3(QUIC)、gRPC Web等の新プロトコルへの対応が困難
  • WebSocketやServer-Sent Eventsの改善が受けられない
  • カスタム認証・認可機能の追加が困難に

CI/CDパイプラインへの影響

テスト・デプロイの複雑化:

  • Helmチャートが更新されないため、他ツールとの統合が困難に
  • GitOps(ArgoCD、Flux)との互換性問題が発生しうる
  • IaC(Terraform、Pulumi)のプロバイダーが最新版をサポートしなくなる可能性

5. コストへの影響(重大度: 中)

直接的なコスト

セキュリティ対策費用:

  • WAF(Web Application Firewall)の追加導入: 月額 $200〜$2,000以上
  • 専任セキュリティエンジニアの配置: 年間 ¥8,000,000〜¥15,000,000
  • 第三者によるセキュリティ監査の頻度増加: 回あたり ¥1,000,000〜¥5,000,000

移行プロジェクトのコスト:

  • 小規模(Ingressリソース10未満): 40〜80時間(¥400,000〜¥800,000相当)
  • 中規模(Ingressリソース10〜50): 120〜200時間(¥1,200,000〜¥2,000,000相当)
  • 大規模(Ingressリソース50以上): 300〜600時間(¥3,000,000〜¥6,000,000相当)

間接的なコスト

機会損失:

  • 移行作業により新機能開発が遅延
  • システム障害時の復旧時間増加によるビジネスインパクト
  • 技術的負債としての認識による採用活動への悪影響

リスクプレミアム:

  • サイバーセキュリティ保険料の増加: 10〜30%増
  • 顧客からのセキュリティ監査要求への対応コスト
  • SOC 2/ISO 27001認証更新時の追加対応費用

6. 組織・人材への影響(重大度: 低〜中)

スキルセットの陳腐化

エンジニアのキャリアへの影響:

  • Ingress NGINXの知識が過去のものに
  • 履歴書に「サポート終了製品の運用経験」と映る可能性
  • 最新のKubernetesエコシステムから取り残される

採用・定着への影響:

  • 技術的に最新でない環境は優秀なエンジニアの採用障壁に
  • 既存メンバーのモチベーション低下リスク
  • 「レガシー環境」としてのレッテルによる離職リスク

7. ビジネス継続性への影響(重大度: 高)

サービス可用性のリスク

予期しないダウンタイム:

  • 新しい脅威への対応ができず、サービス停止を余儀なくされる可能性
  • クラウドプロバイダー側の変更に追従できず、通信断が発生しうる
  • 緊急パッチが必要な状況でも自前での対応が必要(フォーク、パッチ開発)

SLA(Service Level Agreement)への影響:

  • 顧客との契約で定めた可用性を維持できないリスク
  • SLA違反による違約金の支払い
  • 顧客からの信頼低下

ベンダーロックイン・依存リスク

フォークやサードパーティサポートへの依存:

  • 有償サポート提供ベンダーへの依存(料金交渉力の低下)
  • コミュニティフォークへの移行(品質・セキュリティ保証が不透明)
  • 自社でのフォーク維持(高度な専門知識と継続的な投資が必要)

影響度マトリクス(組織規模別)

影響領域 スタートアップ
(〜50名)
中堅企業
(50〜500名)
大企業
(500名〜)
セキュリティリスク 🔴 最高 🔴 最高 🔴 最高
コンプライアンス 🟡 中 🔴 高 🔴 最高
運用負荷 🟡 中 🔴 高 🔴 高
移行コスト 🟡 中 🔴 高 🔴 高
技術的負債 🟡 中 🔴 高 🔴 高
採用への影響 🟡 中 🟡 中 🟢 低

凡例: 🔴 = 重大な影響、🟡 = 中程度の影響、🟢 = 軽微な影響

行動を取らなかった場合のシナリオ

ワーストケースシナリオ(2026年6月時点)

  1. 月初: 新しいCVE(CVSSスコア 9.8)がIngress NGINXで発見される
  2. 同日中: 攻撃コードがGitHub上で公開される(Exploit公開)
  3. 24時間以内: 自動化されたボット攻撃が開始される
  4. 3日以内:
    • 自社システムが侵害される
    • 顧客データの流出
    • サービス停止
  5. 1週間以内:
    • インシデント対応で全エンジニアリソースが投入される
    • 顧客への通知義務発生
    • メディア報道
  6. 1ヶ月以内:
    • 緊急移行プロジェクト開始(通常の3〜5倍のコスト)
    • 顧客の解約
    • 訴訟リスク

このシナリオは決して絵空事ではありません。 Log4Shell(2021年12月)やHeartbleed(2014年4月)など、過去に広く使われているソフトウェアで重大な脆弱性が発見された例は多数あります。

なぜ廃止されるのか

1. メンテナンス体制の限界

Ingress NGINXプロジェクトは、通常1〜2名のボランティア開発者のみで運営されてきました。広範な機能セットに対して、この体制では持続可能なメンテナンスが困難でした。

2. 柔軟性がセキュリティリスクに

かつて便利とされた機能、特に snippet annotations(任意のNGINX設定を追加できる機能)が、現在では深刻なセキュリティ脆弱性として認識されています。

プロジェクトチームは「昨日の柔軟性が、今日の克服不可能な技術的負債になった」と表現しています。

3. 技術的負債の蓄積

長年の開発で蓄積された技術的負債が、もはや返済不可能なレベルに達したと判断されました。

推奨される移行先

1. Gateway API(最推奨)

Gateway API はIngressの後継として設計された、Kubernetes標準のAPIです。

メリット:

  • Kubernetesネイティブで、長期的にサポートされる
  • より表現力豊かで柔軟なルーティング設定
  • 役割ベースのアクセス制御(RBAC)のサポート強化
  • 複数の実装から選択可能(Envoy Gateway、Istio、Cilium Gateway など)

対象:

  • 新規プロジェクト
  • 長期的な運用を見据えた環境
  • Kubernetesの標準に準拠したい組織

2. 他のIngressコントローラー

既存のIngressリソースを継続利用したい場合は、以下の選択肢があります:

  • Traefik Ingress Controller
  • HAProxy Ingress
  • Contour
  • Ambassador/Emissary

これらは引き続きメンテナンスされており、Ingress APIをサポートしています。

今すぐ始めるべきアクションプラン

フェーズ1: 現状把握(今すぐ)

1. Ingress NGINXの使用状況を確認

# Ingress NGINXのデプロイメントを検出
kubectl get deployments --all-namespaces -o json | \
  jq '.items[] | select(.spec.template.spec.containers[].image | contains("ingress-nginx"))'

# Ingressリソースの一覧を取得
kubectl get ingress --all-namespaces

2. 依存関係の洗い出し

  • 使用しているIngressの数とルール数を確認
  • snippet annotationsなど、特殊な機能の使用状況を調査
  • カスタム設定やConfigMapの内容を文書化

3. 移行先の選定

チームで以下を検討し、移行先を決定します:

  • 長期的な技術戦略(Gateway API推奨)
  • 現在のスキルセットと学習コスト
  • 必要な機能要件
  • 移行にかけられる工数

推奨判断基準:

新規プロジェクト → Gateway API
既存環境で早急に移行 → 他のIngressコントローラー
将来性重視 → Gateway API(学習コスト承知の上で)

フェーズ2: 準備期間(2024年末〜2025年Q1)

1. 検証環境の構築

開発・ステージング環境で移行先の実装をテストします:

# Gateway APIの場合の例
kubectl apply -f https://github.com/kubernetes-sigs/gateway-api/releases/download/v1.0.0/standard-install.yaml

# Gateway実装(例: Envoy Gateway)をインストール
helm install eg oci://docker.io/envoyproxy/gateway-helm --version v1.0.0 -n envoy-gateway-system --create-namespace

2. 移行スクリプト/ツールの作成

既存のIngressマニフェストをGateway APIやターゲットの形式に変換するスクリプトを用意します。

3. 動作検証項目のリスト化

  • 各ルートへのアクセステスト
  • TLS/SSL証明書の動作確認
  • レート制限やミドルウェアの動作
  • モニタリング・ログの確認

フェーズ3: 段階的移行(2025年Q2〜Q3)

1. カナリアリリース方式での移行

重要度の低いサービスから順に移行し、問題がないことを確認します。

# 新旧並行運用の例
# 旧: Ingress NGINX (既存)
# 新: Gateway API (新規追加、異なるドメインまたはパス)

2. トラフィックの段階的切り替え

DNS設定やロードバランサーの設定を調整し、徐々に新環境へトラフィックを移行します。

3. 監視強化

移行期間中は特に以下を監視:

  • エラーレート
  • レスポンスタイム
  • SSL/TLS接続の成功率

フェーズ4: 完全移行(2025年Q4〜2026年Q1)

1. 全サービスの移行完了

2026年3月より前に、全てのサービスを新環境に移行します。

2. Ingress NGINXのアンインストール

# Ingress NGINXの削除(全移行完了後)
kubectl delete namespace ingress-nginx

3. 文書の更新

運用ドキュメント、障害対応手順、オンボーディング資料などを更新します。

リスクと対策

リスク1: 移行遅延で2026年3月を超える

影響: セキュリティアップデートなしで運用することに

対策:

  • 経営層・マネジメントに早期にエスカレーション
  • 専任リソースの確保
  • 外部支援(コンサルティング)の検討

リスク2: 移行中の障害

影響: サービス停止、パフォーマンス劣化

対策:

  • 十分な検証期間の確保
  • ロールバック手順の事前準備
  • ピーク時間外での切り替え実施

リスク3: 予期しない設定の非互換

影響: 一部機能が動作しない

対策:

  • 全Ingressリソースの詳細な棚卸し
  • 特殊な設定(snippet等)の代替手段の事前調査
  • 段階的移行によるリスク分散

Gateway APIへの詳細な移行手順

ここでは、最も推奨される移行先である Gateway API への具体的な移行手順を解説します。実装としては Envoy Gateway を使用した例を示します。

移行手順の全体フロー

1. Gateway API CRDのインストール
2. Gateway実装(Envoy Gateway)のインストール
3. GatewayClassとGatewayリソースの作成
4. 既存IngressからHTTPRouteへの変換
5. 並行運用とトラフィック検証
6. 完全切り替えとIngress NGINX削除

ステップ1: 環境準備

1-1. 現在のIngress設定をバックアップ

# すべてのIngressリソースをバックアップ
kubectl get ingress --all-namespaces -o yaml > ingress-backup-$(date +%Y%m%d).yaml

# Ingress NGINXの設定もバックアップ
kubectl get configmap -n ingress-nginx -o yaml > ingress-nginx-configmap-backup.yaml
kubectl get deployment -n ingress-nginx -o yaml > ingress-nginx-deployment-backup.yaml

1-2. 既存Ingressの分析

# Ingressの数を確認
kubectl get ingress --all-namespaces --no-headers | wc -l

# annotationの使用状況を確認(移行時に特別な対応が必要)
kubectl get ingress --all-namespaces -o json | \
  jq -r '.items[].metadata.annotations | keys[]' | \
  sort | uniq -c | sort -rn

# TLS設定があるIngressを確認
kubectl get ingress --all-namespaces -o json | \
  jq -r '.items[] | select(.spec.tls != null) | .metadata.name'

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

# Gateway API v1.2.0のCRDをインストール(2025年11月時点の最新安定版)
kubectl apply -f https://github.com/kubernetes-sigs/gateway-api/releases/download/v1.2.0/standard-install.yaml

# インストール確認
kubectl get crd | grep gateway
# 以下が表示されることを確認:
# gatewayclasses.gateway.networking.k8s.io
# gateways.gateway.networking.k8s.io
# httproutes.gateway.networking.k8s.io
# referencegrants.gateway.networking.k8s.io

ステップ3: Envoy Gatewayのインストール

3-1. Helmでのインストール

# Helmリポジトリの追加
helm repo add envoy-gateway https://gateway.envoyproxy.io
helm repo update

# envoy-gateway-systemネームスペースの作成とインストール
helm install eg envoy-gateway/gateway-helm \
  --version v1.2.1 \
  --namespace envoy-gateway-system \
  --create-namespace \
  --set config.envoyGateway.provider.type=Kubernetes

# インストール確認
kubectl get pods -n envoy-gateway-system
# envoy-gateway-xxxxxxxxx-xxxxx が Running になることを確認

3-2. GatewayClassの作成

Envoy Gatewayをインストールすると、自動的に GatewayClass が作成されます:

# GatewayClassの確認
kubectl get gatewayclass
# NAME                CONTROLLER                      ACCEPTED   AGE
# eg                  gateway.envoyproxy.io/gatewayclass-controller   True       2m

ステップ4: Gatewayリソースの作成

4-1. 基本的なGatewayの作成

# gateway.yaml
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
  name: main-gateway
  namespace: default
spec:
  gatewayClassName: eg
  listeners:
  - name: http
    protocol: HTTP
    port: 80
    allowedRoutes:
      namespaces:
        from: All  # すべてのNamespaceからのHTTPRouteを許可
  - name: https
    protocol: HTTPS
    port: 443
    allowedRoutes:
      namespaces:
        from: All
    tls:
      mode: Terminate
      certificateRefs:
      - kind: Secret
        name: wildcard-tls-cert  # TLS証明書が格納されたSecret
# Gatewayの適用
kubectl apply -f gateway.yaml

# Gatewayのステータス確認
kubectl get gateway main-gateway -o yaml

# External IPの取得(クラウド環境の場合、LoadBalancerが自動作成される)
kubectl get gateway main-gateway -o jsonpath='{.status.addresses[0].value}'

ステップ5: IngressからHTTPRouteへの変換

5-1. 変換例1: シンプルなパスベースルーティング

移行前(Ingress NGINX):

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: example-app
  namespace: production
  annotations:
    kubernetes.io/ingress.class: nginx
spec:
  rules:
  - host: api.example.com
    http:
      paths:
      - path: /users
        pathType: Prefix
        backend:
          service:
            name: user-service
            port:
              number: 8080
      - path: /orders
        pathType: Prefix
        backend:
          service:
            name: order-service
            port:
              number: 8080

移行後(Gateway API):

apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: example-app
  namespace: production
spec:
  parentRefs:
  - name: main-gateway
    namespace: default
  hostnames:
  - "api.example.com"
  rules:
  - matches:
    - path:
        type: PathPrefix
        value: /users
    backendRefs:
    - name: user-service
      port: 8080
  - matches:
    - path:
        type: PathPrefix
        value: /orders
    backendRefs:
    - name: order-service
      port: 8080

5-2. 変換例2: TLS/HTTPS設定

移行前(Ingress NGINX):

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: secure-app
  namespace: production
  annotations:
    kubernetes.io/ingress.class: nginx
    cert-manager.io/cluster-issuer: letsencrypt-prod
spec:
  tls:
  - hosts:
    - secure.example.com
    secretName: secure-tls-cert
  rules:
  - host: secure.example.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: web-service
            port:
              number: 443

移行後(Gateway API):

# まず、Gatewayに証明書を設定(Gateway作成時に設定済みの場合はスキップ)
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
  name: main-gateway
  namespace: default
  annotations:
    cert-manager.io/cluster-issuer: letsencrypt-prod  # cert-managerとの統合
spec:
  gatewayClassName: eg
  listeners:
  - name: https
    protocol: HTTPS
    port: 443
    hostname: "secure.example.com"
    allowedRoutes:
      namespaces:
        from: All
    tls:
      mode: Terminate
      certificateRefs:
      - kind: Secret
        name: secure-tls-cert
---
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: secure-app
  namespace: production
spec:
  parentRefs:
  - name: main-gateway
    namespace: default
    sectionName: https  # HTTPSリスナーを指定
  hostnames:
  - "secure.example.com"
  rules:
  - matches:
    - path:
        type: PathPrefix
        value: /
    backendRefs:
    - name: web-service
      port: 443

5-3. 変換例3: リダイレクト(HTTPからHTTPSへ)

移行前(Ingress NGINX):

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: redirect-example
  annotations:
    kubernetes.io/ingress.class: nginx
    nginx.ingress.kubernetes.io/ssl-redirect: "true"
    nginx.ingress.kubernetes.io/force-ssl-redirect: "true"
spec:
  # ... rules

移行後(Gateway API):

apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: http-to-https-redirect
  namespace: default
spec:
  parentRefs:
  - name: main-gateway
    namespace: default
    sectionName: http  # HTTPリスナーからのトラフィック
  hostnames:
  - "example.com"
  rules:
  - filters:
    - type: RequestRedirect
      requestRedirect:
        scheme: https
        statusCode: 301

5-4. 変換例4: リライト(パス書き換え)

移行前(Ingress NGINX):

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: rewrite-example
  annotations:
    kubernetes.io/ingress.class: nginx
    nginx.ingress.kubernetes.io/rewrite-target: /$2
spec:
  rules:
  - host: api.example.com
    http:
      paths:
      - path: /api/v1(/|$)(.*)
        pathType: ImplementationSpecific
        backend:
          service:
            name: backend-service
            port:
              number: 8080

移行後(Gateway API):

apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: rewrite-example
  namespace: default
spec:
  parentRefs:
  - name: main-gateway
    namespace: default
  hostnames:
  - "api.example.com"
  rules:
  - matches:
    - path:
        type: PathPrefix
        value: /api/v1
    filters:
    - type: URLRewrite
      urlRewrite:
        path:
          type: ReplacePrefixMatch
          replacePrefixMatch: /
    backendRefs:
    - name: backend-service
      port: 8080

5-5. 変換例5: CORS設定

移行前(Ingress NGINX):

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: cors-example
  annotations:
    kubernetes.io/ingress.class: nginx
    nginx.ingress.kubernetes.io/enable-cors: "true"
    nginx.ingress.kubernetes.io/cors-allow-origin: "https://app.example.com"
    nginx.ingress.kubernetes.io/cors-allow-methods: "GET, POST, PUT, DELETE"
spec:
  # ... rules

移行後(Gateway API + EnvoyProxy拡張):

apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: cors-example
  namespace: default
spec:
  parentRefs:
  - name: main-gateway
    namespace: default
  hostnames:
  - "api.example.com"
  rules:
  - matches:
    - path:
        type: PathPrefix
        value: /
    filters:
    - type: ResponseHeaderModifier
      responseHeaderModifier:
        add:
        - name: Access-Control-Allow-Origin
          value: "https://app.example.com"
        - name: Access-Control-Allow-Methods
          value: "GET, POST, PUT, DELETE"
        - name: Access-Control-Allow-Headers
          value: "Content-Type, Authorization"
    backendRefs:
    - name: api-service
      port: 8080

5-6. 変換例6: レート制限

移行前(Ingress NGINX):

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: rate-limit-example
  annotations:
    kubernetes.io/ingress.class: nginx
    nginx.ingress.kubernetes.io/limit-rps: "10"
spec:
  # ... rules

移行後(Gateway API + BackendTrafficPolicy):

apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: rate-limit-example
  namespace: default
spec:
  parentRefs:
  - name: main-gateway
    namespace: default
  rules:
  - backendRefs:
    - name: api-service
      port: 8080
---
# Envoy Gateway拡張リソース
apiVersion: gateway.envoyproxy.io/v1alpha1
kind: BackendTrafficPolicy
metadata:
  name: rate-limit-policy
  namespace: default
spec:
  targetRef:
    group: gateway.networking.k8s.io
    kind: HTTPRoute
    name: rate-limit-example
  rateLimit:
    type: Global
    global:
      rules:
      - limit:
          requests: 10
          unit: Second

ステップ6: 移行の自動化スクリプト

既存のIngressを自動的にHTTPRouteに変換するPythonスクリプトの例:

#!/usr/bin/env python3
# ingress-to-httproute.py

import yaml
import sys
from typing import Dict, Any

def convert_ingress_to_httproute(ingress: Dict[Any, Any], gateway_name: str = "main-gateway", gateway_namespace: str = "default") -> Dict[Any, Any]:
    """IngressリソースをHTTPRouteに変換"""

    httproute = {
        "apiVersion": "gateway.networking.k8s.io/v1",
        "kind": "HTTPRoute",
        "metadata": {
            "name": ingress["metadata"]["name"],
            "namespace": ingress["metadata"].get("namespace", "default"),
        },
        "spec": {
            "parentRefs": [
                {
                    "name": gateway_name,
                    "namespace": gateway_namespace
                }
            ],
            "rules": []
        }
    }

    # ホスト名の変換
    hostnames = []
    for rule in ingress["spec"].get("rules", []):
        if "host" in rule:
            hostnames.append(rule["host"])

    if hostnames:
        httproute["spec"]["hostnames"] = hostnames

    # ルールの変換
    for rule in ingress["spec"].get("rules", []):
        for path in rule.get("http", {}).get("paths", []):
            route_rule = {
                "matches": [
                    {
                        "path": {
                            "type": path.get("pathType", "PathPrefix"),
                            "value": path.get("path", "/")
                        }
                    }
                ],
                "backendRefs": [
                    {
                        "name": path["backend"]["service"]["name"],
                        "port": path["backend"]["service"]["port"]["number"]
                    }
                ]
            }
            httproute["spec"]["rules"].append(route_rule)

    return httproute

if __name__ == "__main__":
    if len(sys.argv) < 2:
        print("Usage: python3 ingress-to-httproute.py <ingress-file.yaml>")
        sys.exit(1)

    with open(sys.argv[1], 'r') as f:
        ingress = yaml.safe_load(f)

    httproute = convert_ingress_to_httproute(ingress)

    print(yaml.dump(httproute, default_flow_style=False, sort_keys=False))

使用方法:

# 単一のIngressファイルを変換
python3 ingress-to-httproute.py my-ingress.yaml > my-httproute.yaml

# すべてのIngressを一括変換
for ns in $(kubectl get ingress --all-namespaces -o jsonpath='{.items[*].metadata.namespace}' | tr ' ' '\n' | sort -u); do
  for ing in $(kubectl get ingress -n $ns -o jsonpath='{.items[*].metadata.name}'); do
    echo "Converting $ns/$ing"
    kubectl get ingress $ing -n $ns -o yaml > /tmp/ingress-$ns-$ing.yaml
    python3 ingress-to-httproute.py /tmp/ingress-$ns-$ing.yaml > httproutes/$ns-$ing-httproute.yaml
  done
done

ステップ7: 並行運用とトラフィック検証

7-1. DNSベースのカナリアリリース

# Gateway(Envoy Gateway)のExternal IPを取得
ENVOY_IP=$(kubectl get gateway main-gateway -o jsonpath='{.status.addresses[0].value}')

# まずは別のホスト名でテスト
# DNS: test.example.com -> Envoy Gateway IP
# DNS: www.example.com -> Ingress NGINX IP (既存)

# curlでテスト
curl -H "Host: test.example.com" http://$ENVOY_IP/users

7-2. トラフィック比較テスト

# 既存Ingressへのリクエスト
time curl -s -o /dev/null -w "%{http_code}\n" https://www.example.com/users

# 新Gateway APIへのリクエスト
time curl -s -o /dev/null -w "%{http_code}\n" https://test.example.com/users

# レスポンスが同一であることを確認
diff <(curl -s https://www.example.com/users) <(curl -s https://test.example.com/users)

7-3. 負荷テスト

# Apache Benchを使った負荷テスト
# Ingress NGINX
ab -n 1000 -c 10 https://www.example.com/users

# Gateway API
ab -n 1000 -c 10 https://test.example.com/users

# パフォーマンス比較

ステップ8: 完全切り替え

8-1. DNSの切り替え

# DNS TTLを短く設定(例: 60秒)
# www.example.com のAレコードを Envoy Gateway のIPに変更

# 切り替え後、両方のIPで一時的にトラフィックを受け付ける状態を維持
# 徐々にIngress NGINXへのトラフィックが減少することを監視

8-2. モニタリング

# Envoy Gatewayのメトリクスを確認
kubectl port-forward -n envoy-gateway-system \
  deployment/envoy-gateway 19000:19000

# ブラウザで http://localhost:19000/stats を開く

# Prometheusメトリクスの確認
curl http://localhost:19000/stats/prometheus

ステップ9: Ingress NGINXの削除

すべてのトラフィックがGateway APIに移行したことを確認後:

# まずはIngressリソースのみを削除(コントローラーは残す)
kubectl delete ingress --all --all-namespaces

# 1週間程度様子を見て問題なければ、Ingress NGINXコントローラーを削除
helm uninstall ingress-nginx -n ingress-nginx

# または
kubectl delete namespace ingress-nginx

トラブルシューティング

問題1: GatewayにExternal IPが割り当てられない

原因: クラウドプロバイダーのLoadBalancer設定の問題

解決策:

# Gatewayのイベントを確認
kubectl describe gateway main-gateway

# Envoy Gatewayのログを確認
kubectl logs -n envoy-gateway-system deployment/envoy-gateway

# LoadBalancerサービスを確認
kubectl get svc -n envoy-gateway-system

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

原因: namespaceの権限設定、または parentRefs の設定ミス

解決策:

# HTTPRouteのステータスを確認
kubectl get httproute <name> -n <namespace> -o yaml

# ReferenceGrantが必要な場合(異なるnamespace間の参照)
cat <<EOF | kubectl apply -f -
apiVersion: gateway.networking.k8s.io/v1beta1
kind: ReferenceGrant
metadata:
  name: allow-gateway-refs
  namespace: default  # Gatewayがあるnamespace
spec:
  from:
  - group: gateway.networking.k8s.io
    kind: HTTPRoute
    namespace: production  # HTTPRouteがあるnamespace
  to:
  - group: ""
    kind: Service
EOF

問題3: TLS証明書が機能しない

原因: cert-managerとの統合設定の問題

解決策:

# Secretが存在することを確認
kubectl get secret <cert-name> -n <namespace>

# 証明書の内容を確認
kubectl get secret <cert-name> -n <namespace> -o jsonpath='{.data.tls\.crt}' | base64 -d | openssl x509 -text -noout

# Gatewayのリスナー設定を確認
kubectl get gateway main-gateway -o yaml

移行チェックリスト

移行作業を進める際のチェックリストとして活用してください:

  • 既存Ingressのバックアップ完了
  • Gateway API CRDインストール完了
  • Envoy Gatewayインストール完了
  • GatewayClassの作成確認
  • Gatewayリソースの作成とExternal IP取得
  • すべてのIngressをHTTPRouteに変換
  • TLS証明書の移行と動作確認
  • 特殊なannotation(CORS、レート制限等)の移行
  • テスト環境での動作確認
  • 負荷テストの実施と結果比較
  • モニタリング・アラートの設定
  • DNSのTTL短縮
  • カナリアリリース(一部トラフィックの切り替え)
  • 全トラフィックの切り替え
  • 1週間の安定稼働確認
  • Ingress NGINXリソースの削除
  • Ingress NGINXコントローラーの削除
  • ドキュメントの更新
  • チームへの引き継ぎ完了

まとめ

Ingress NGINXの廃止は、Kubernetesエコシステムの大きな転換点です。しかし、これは同時に技術スタックを最新化する良い機会でもあります。

重要なポイント:

  1. 今すぐ行動を開始する - 2026年3月まで時間はあるが、準備には相応の期間が必要
  2. Gateway APIへの移行を優先検討 - 将来性とKubernetesコミュニティのサポートを考慮
  3. 段階的に移行 - リスクを最小化するため、計画的に進める
  4. チーム全体で情報共有 - 開発、運用、セキュリティチームで認識を合わせる

2026年3月以降、セキュリティアップデートが提供されないIngress NGINXを使い続けることは、重大なセキュリティリスクとなります。今すぐ移行計画を立て、実行に移しましょう。

参考リンク


執筆日: 2025年11月17日
対象読者: Kubernetesでingress-nginxを使用している開発者・インフラエンジニア・SRE

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?