- Published on
ingress-nginx ディープダイブ — アーキテクチャ、アノテーション、テンプレートのすべて
- Authors

- Name
- Youngju Kim
- @fjvbn20031
- はじめに
- ingress-nginx vs NGINX Inc. コントローラ — まず区別する
- 内部アーキテクチャの解剖
- 必須アノテーションカタログ
- ConfigMap グローバルチューニング
- snippet アノテーションとセキュリティリスク
- メンテナンスモードと Gateway API への推奨
- IngressClass と複数コントローラ
- pathType と経路マッチング
- デフォルトバックエンドとカスタムエラーページ
- トラブルシューティング
- インストールとデプロイトポロジ
- 要点まとめ
- おわりに
- 参考資料
はじめに
Kubernetes で外部トラフィックをクラスタ内のサービスへルーティングする最も一般的な方法が Ingress リソースであり、その Ingress を実際に実装するコントローラの中で圧倒的に多く使われているのが ingress-nginx です。プラットフォームチームで一度でも Ingress を扱ったことがあれば、ほぼ確実に出会うコンポーネントです。
ところがいざ運用を始めると戸惑う点が多くあります。「nginx ingress」で検索すると 2 つの異なるプロジェクトが出てきて、アノテーションを付けても動かず、rewrite-target 一つで 404 が大量発生し、snippet アノテーションを使うとセキュリティ監査で指摘されます。さらに 2026 年現在、ingress-nginx はメンテナンスモードへ移行し、Ingress API 自体が凍結(frozen)状態で、Gateway API が後継標準として定着しつつあります。
本記事では ingress-nginx の内部構造を解剖し、実務で必ず知っておくべきアノテーションをカタログ形式で整理し、グローバルチューニングとセキュリティリスク、そして今後の移行戦略までを一気に扱います。
ingress-nginx vs NGINX Inc. コントローラ — まず区別する
最初に押さえるべき混乱の元は、「nginx ベースの Ingress コントローラ」が実は 2 つあるという点です。名前が似ているため資料を混ぜて見てしまい、動かないアノテーションを付けることが非常に多いのです。
| 区分 | ingress-nginx(コミュニティ) | NGINX Ingress Controller(F5/NGINX Inc.) |
|---|---|---|
| 主体 | Kubernetes プロジェクト(SIG) | F5 NGINX(商用ベンダー) |
| リポジトリ | kubernetes/ingress-nginx | nginxinc/kubernetes-ingress |
| アノテーション prefix | nginx.ingress.kubernetes.io | nginx.org / nginx.com |
| 設定拡張 | Lua + テンプレート、snippet | VirtualServer/VirtualServerRoute CRD |
| ライセンス | Apache 2.0、完全オープンソース | OSS 版 + 商用 NGINX Plus |
| 動的設定 | Lua ベースで reload を回避 | Plus は API ベース、OSS は reload |
肝心なのはアノテーション prefix です。ネットの資料どおりにやっても動かない場合、十中八九は別プロジェクトのアノテーションを付けています。本記事は完全にコミュニティ版 ingress-nginx(prefix nginx.ingress.kubernetes.io)を扱います。
内部アーキテクチャの解剖
ingress-nginx の Pod は 1 つのコンテナ内で 2 つの役割を同時にこなします。一つはコントローラプロセス、もう一つは実際にトラフィックを処理する nginx プロセスです。
┌──────────────────────────────────────────────┐
│ ingress-nginx Pod │
│ │
K8s API │ ┌────────────┐ ┌───────────────┐ │
─────────▶│ │ Controller │ watch │ nginx master │ │
(watch │ │ (Go) │────────▶│ + workers │ │
Ingress, │ │ │ reload/ │ │ │
Service, │ │ Lua sync │ Lua API │ Lua modules │ │
Endpoints)│ └────────────┘ └───────┬───────┘ │
│ │ │
└──────────────────────────────────┼───────────┘
│
┌────────────────▼────────────────┐
│ Upstream Pods (Endpoints) │
└──────────────────────────────────┘
コントローラプロセスの役割
コントローラは Go で書かれており、Kubernetes API サーバを watch します。Ingress、Service、Endpoints(または EndpointSlice)、Secret、ConfigMap の変化を検知し、nginx が理解できる設定モデルに変換します。変換されたモデルは 2 つの経路で適用されます。
- 構造的な変更(新しいホスト、新しい path、TLS 変更など)は nginx.conf テンプレートを再レンダリングし、nginx を reload します。
- 単純なエンドポイント変更(Pod のスケールイン/アウトなど)は reload せずに Lua を通じて動的に upstream を更新します。
Lua と動的設定 — reload を避ける核心
従来の nginx 運用で最大の問題は、upstream が変わるたびに reload が必要なことでした。Pod が頻繁に起動・停止する Kubernetes 環境では reload が頻発し、reload 中は接続が切れたりメモリ使用量が急増したりします。
ingress-nginx はこれを OpenResty ベースの Lua で解決します。upstream のエンドポイント一覧を Lua 共有メモリに保存し、エンドポイントが変わったら nginx を reload せず Lua データだけを更新します。負荷分散の判断も balancer_by_lua 段階で動的に行われます。その結果、日常的なスケーリングでは reload がほとんど発生しません。
reload が必要なのは次のような場合です。
[ reload 発生 ] [ reload 不要(Lua 動的) ]
- 新しい server/location 追加 - Pod スケールイン/アウト
- TLS 証明書/Secret 変更 - Endpoint IP 変更
- ConfigMap グローバルオプション変更 - 単純な重み更新(canary の一部)
- snippet アノテーション変更
必須アノテーションカタログ
ingress-nginx の真の力はアノテーションにあります。よく使うものをカテゴリ別に整理します。すべてのアノテーション prefix は nginx.ingress.kubernetes.io です。
| アノテーション | 用途 | 代表値 |
|---|---|---|
| rewrite-target | パスの書き換え | キャプチャグループで書き換え |
| ssl-redirect | HTTP を HTTPS へリダイレクト | "true" |
| force-ssl-redirect | TLS 未設定でも強制リダイレクト | "true" |
| backend-protocol | バックエンドプロトコル指定 | HTTPS, GRPC |
| proxy-body-size | リクエストボディ最大サイズ | 50m |
| proxy-read-timeout | バックエンド読み取りタイムアウト(秒) | "60" |
| canary | カナリア Ingress 有効化 | "true" |
| canary-weight | カナリアトラフィック比率 | "20" |
| affinity | セッションアフィニティ方式 | cookie |
| whitelist-source-range | ソース IP 許可リスト | 10.0.0.0/8 |
rewrite-target と正規表現パス
最も間違いやすいアノテーションです。パスの一部を削ってバックエンドへ渡すには、正規表現のキャプチャグループと一緒に使う必要があります。
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: app-rewrite
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /$2
nginx.ingress.kubernetes.io/use-regex: "true"
spec:
ingressClassName: nginx
rules:
- host: app.example.com
http:
paths:
- path: /svc(/|$)(.*)
pathType: ImplementationSpecific
backend:
service:
name: app-svc
port:
number: 80
ここで /svc/foo で来たリクエストは、2 番目のキャプチャグループ((.*))の foo だけがバックエンドへ渡されます。rewrite-target のドル表記は nginx の正規表現キャプチャを指し、必ずコードフェンス内でのみ使わないと MDX ビルドが壊れます。
TLS リダイレクトとバックエンドプロトコル
metadata:
annotations:
nginx.ingress.kubernetes.io/ssl-redirect: "true"
nginx.ingress.kubernetes.io/backend-protocol: "HTTPS"
backend-protocol を HTTPS にすると、コントローラはバックエンドへ HTTPS で接続します。gRPC サービスなら GRPC を指定して初めて HTTP/2 ベースの gRPC プロキシが正しく動作します。
カナリアデプロイ
ingress-nginx は同一ホスト/パスに対してメイン Ingress とカナリア Ingress を同時に置き、トラフィックを分割します。
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: app-canary
annotations:
nginx.ingress.kubernetes.io/canary: "true"
nginx.ingress.kubernetes.io/canary-weight: "20"
spec:
ingressClassName: nginx
rules:
- host: app.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: app-v2
port:
number: 80
weight 以外にもヘッダ/クッキーによる分岐が可能です。
metadata:
annotations:
nginx.ingress.kubernetes.io/canary: "true"
nginx.ingress.kubernetes.io/canary-by-header: "x-canary"
nginx.ingress.kubernetes.io/canary-by-header-value: "always"
ConfigMap グローバルチューニング
アノテーションが Ingress 単位の設定なら、ConfigMap はコントローラ全体に適用されるグローバル設定です。コントローラ配置時に指定した ConfigMap(通常は ingress-nginx-controller)を通じて、nginx の http ブロックレベルのオプションを制御します。
apiVersion: v1
kind: ConfigMap
metadata:
name: ingress-nginx-controller
namespace: ingress-nginx
data:
use-gzip: "true"
gzip-level: "5"
proxy-body-size: "20m"
keep-alive: "75"
keep-alive-requests: "1000"
upstream-keepalive-connections: "320"
ssl-protocols: "TLSv1.2 TLSv1.3"
enable-real-ip: "true"
use-forwarded-headers: "true"
ConfigMap の変更はほぼ常に nginx reload を引き起こすため、頻繁に変えるのではなく GitOps で慎重に管理するのがよいでしょう。
snippet アノテーションとセキュリティリスク
ingress-nginx の最も強力でありながら最も危険な機能が snippet アノテーションです。任意の nginx 設定断片を Ingress に注入できます。
metadata:
annotations:
nginx.ingress.kubernetes.io/configuration-snippet: |
more_set_headers "X-Custom: value";
問題は、この snippet がコントローラの nginx.conf にそのままレンダリングされる点です。Ingress リソースを作成できる権限さえあれば、snippet を通じてコントローラプロセスの権限で任意の設定を注入できます。マルチテナントクラスタではこれが権限昇格の経路になります。
実際、2025 年に報告された一連の CVE(いわゆる IngressNightmare 系)は、admission webhook の処理過程と snippet 注入を悪用してコントローラ権限でのコード実行が可能であることを示しました。その結果、ingress-nginx はデフォルト値を保守的に変更しました。
apiVersion: v1
kind: ConfigMap
metadata:
name: ingress-nginx-controller
namespace: ingress-nginx
data:
allow-snippet-annotations: "false"
annotations-risk-level: "Critical"
最新バージョンでは allow-snippet-annotations のデフォルトが false です。snippet がどうしても必要なら、信頼できる運用者だけが Ingress を作成できるよう RBAC を強く絞り、annotations-risk-level で許可範囲を制限すべきです。
メンテナンスモードと Gateway API への推奨
2026 年時点で最も重要な文脈は、ingress-nginx と Ingress API 自体の未来です。
- Ingress API は凍結(frozen)状態です。新機能はもう追加されず、表現力の限界(L7 ルーティング、トラフィック分割、ヘッダマッチをアノテーションで回避する問題)がそのまま残っています。
- アノテーションと snippet に依存する構造は標準化されず、セキュリティ表面を広げます。
- 後継標準は Gateway API です。Gateway、GatewayClass、HTTPRoute といった一級 CRD でルーティングを表現し、役割分離(インフラ運用者 vs アプリ開発者)とトラフィック分割を標準仕様として提供します。
新規プロジェクトなら、Gateway API ベースの実装(例: Envoy Gateway、Contour、NGINX Gateway Fabric など)を優先的に検討することが推奨されます。既存の ingress-nginx 利用箇所はすぐ捨てる必要はありませんが、snippet 依存を減らし、アノテーションを標準機能中心に整理しながら段階的な移行を計画するのがよいでしょう。
[ ルーティング標準の変遷 ]
Ingress API (frozen) Gateway API (後継標準)
─────────────────── ────────────────────────
単一 Ingress リソース ──▶ GatewayClass / Gateway
アノテーションで拡張 HTTPRoute / TLSRoute
ベンダー別の非標準動作 役割ベースの分離(RBAC 親和)
IngressClass と複数コントローラ
1 つのクラスタに複数の ingress-nginx コントローラを置くことはよくあります。外部用と内部用を分けたり、チームごとにコントローラを分けたりします。このとき、どの Ingress がどのコントローラで処理されるかは IngressClass で決まります。
apiVersion: networking.k8s.io/v1
kind: IngressClass
metadata:
name: nginx-internal
spec:
controller: k8s.io/ingress-nginx
Ingress では spec.ingressClassName で使用するクラスを指定します。
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: internal-app
spec:
ingressClassName: nginx-internal
rules:
- host: internal.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: internal-svc
port:
number: 80
かつてはクラスを kubernetes.io/ingress.class アノテーションで指定していましたが、現在は deprecated であり spec.ingressClassName フィールドを使うべきです。コントローラは自分が担当する IngressClass の Ingress だけを処理するので、複数コントローラ環境での ingressClassName 漏れは「どのコントローラも処理しない」Ingress を生む、よくあるミスです。
デフォルトの IngressClass を指定することもできます。アノテーションで default を示すと、ingressClassName を省略した Ingress がそのクラスで処理されます。ただし明示性のため、できれば全 Ingress に ingressClassName を書くことを推奨します。
pathType と経路マッチング
Ingress スペックの pathType は経路マッチングの方式を決め、意外にも動作差が大きいです。
| pathType | 意味 |
|---|---|
| Exact | 経路が正確に一致する必要がある |
| Prefix | 経路セグメント単位の接頭一致 |
| ImplementationSpecific | コントローラ実装に委任(正規表現など) |
Prefix はセグメント単位で動作します。/foo という Prefix ルールは /foo と /foo/bar にはマッチしますが /foobar にはマッチしません。正規表現や rewrite を使うには ImplementationSpecific と use-regex アノテーションを組み合わせる必要があります。同じホストに複数の path がある場合、ingress-nginx はより具体的な(長い)経路を優先します。
デフォルトバックエンドとカスタムエラーページ
マッチする Ingress がないリクエストはデフォルトバックエンド(default backend)へ行きます。また、バックエンドがエラーを返すときにユーザーフレンドリーなページを見せるには、custom-http-errors と別途のエラーページサービスを連携できます。
apiVersion: v1
kind: ConfigMap
metadata:
name: ingress-nginx-controller
namespace: ingress-nginx
data:
custom-http-errors: "404,503"
proxy-intercept-errors: "true"
custom-http-errors に指定したステータスコードが発生すると、コントローラは default-backend へリクエストを送ってカスタムエラーページを取得します。ブランディングされたメンテナンスページや一貫したエラー UX が必要なサービスに有用です。
トラブルシューティング
運用でよく遭遇する症状と点検ポイントです。
# コントローラがレンダリングした実際の nginx.conf を確認
kubectl exec -n ingress-nginx deploy/ingress-nginx-controller -- cat /etc/nginx/nginx.conf
# Ingress がどのバックエンドへマッピングされたか確認
kubectl describe ingress app-rewrite
# コントローラログ(reload や設定エラーの追跡)
kubectl logs -n ingress-nginx deploy/ingress-nginx-controller --tail=200
| 症状 | よくある原因 | 点検 |
|---|---|---|
| 404 Not Found | rewrite-target 正規表現/path 不一致 | use-regex と path のキャプチャグループ確認 |
| アノテーション無視 | 別プロジェクトの prefix を使用 | nginx.ingress.kubernetes.io か確認 |
| 413 Payload Too Large | proxy-body-size 未設定 | アノテーションまたは ConfigMap 調整 |
| snippet が効かない | allow-snippet-annotations false | RBAC/リスクレベルポリシー確認 |
| reload 頻発 | ConfigMap/Secret の頻繁な変更 | GitOps で変更頻度を管理 |
ほとんどの問題は「どの設定が実際に nginx.conf へレンダリングされたか」を直接確認すれば素早く絞り込めます。アノテーションが無視されているように見えるときは、prefix と ingressClassName をまず疑ってください。
インストールとデプロイトポロジ
ingress-nginx は通常 Helm でインストールし、デプロイトポロジがトラフィックの入り方と外部 IP の保持に大きく影響します。
helm upgrade --install ingress-nginx ingress-nginx \
--repo https://kubernetes.github.io/ingress-nginx \
--namespace ingress-nginx --create-namespace \
--set controller.service.type=LoadBalancer \
--set controller.replicaCount=3
サービスタイプとトラフィックポリシーは次のように分かれます。
| トポロジ | 特徴 | 外部 IP の保持 |
|---|---|---|
| Service LoadBalancer | クラウド LB が前段 | externalTrafficPolicy で制御 |
| Service NodePort | ノードポートで直接公開 | 通常 SNAT が発生 |
| hostNetwork DaemonSet | ノードネットワークを直接使用 | 元 IP の保持が容易 |
externalTrafficPolicy を Local にするとノード間の追加ホップがなくなりクライアントの元 IP が保持されますが、そのノードにコントローラ Pod がないとトラフィックを受けません。Cluster にするとどのノードでも受けますが、SNAT で元 IP が隠れることがあります。IP ベースのポリシー(ホワイトリスト、ロギング)が必要ならこの選択が重要です。
apiVersion: v1
kind: Service
metadata:
name: ingress-nginx-controller
namespace: ingress-nginx
spec:
type: LoadBalancer
externalTrafficPolicy: Local
selector:
app.kubernetes.io/name: ingress-nginx
ports:
- name: https
port: 443
targetPort: https
要点まとめ
本記事で扱った内容を一度に整理すると次のとおりです。
- ingress-nginx(コミュニティ)と NGINX Inc. コントローラは別プロジェクト。アノテーション prefix(nginx.ingress.kubernetes.io)で区別する。
- 1 つの Pod 内でコントローラプロセスが Go で API を watch し、nginx が実際のトラフィックを処理し、Lua が動的設定で reload を回避する。
- rewrite-target/use-regex の正規表現キャプチャ、ssl-redirect、backend-protocol、canary が核心アノテーション。
- ConfigMap はグローバルデフォルト、アノテーションは Ingress ごとのオーバーライド。
- snippet は強力だが危険なので、デフォルト無効にし RBAC とポリシーエンジンで統制する。
- IngressClass で複数コントローラを区別し、pathType とデプロイトポロジ(externalTrafficPolicy)を理解する。
- Ingress API は凍結、ingress-nginx はメンテナンスモード。新規は Gateway API で設計する。
この骨格を押さえておけば、ほとんどの実務状況で素早く原因を絞り、正しい判断を下せます。
おわりに
ingress-nginx は、コントローラプロセスと nginx、そして Lua ベースの動的設定が噛み合って動作する精緻なシステムです。アノテーションカタログを理解し、ConfigMap でグローバル動作を固めれば、ほとんどの要件を満たせます。ただし snippet は強力なぶんセキュリティリスクが大きいので、デフォルトで無効にし RBAC で統制すべきです。
何より 2026 年の大きな絵は明確です。Ingress API は凍結され、ingress-nginx はメンテナンスモードです。稼働中の Ingress を安定して維持しつつ、新規のルーティング要求は Gateway API で設計する二重戦略が現実的です。
参考資料
- Kubernetes Ingress の概念: https://kubernetes.io/docs/concepts/services-networking/ingress/
- ingress-nginx 公式ドキュメント: https://kubernetes.github.io/ingress-nginx/
- ingress-nginx アノテーションリファレンス: https://kubernetes.github.io/ingress-nginx/user-guide/nginx-configuration/annotations/
- ingress-nginx ConfigMap オプション: https://kubernetes.github.io/ingress-nginx/user-guide/nginx-configuration/configmap/
- Gateway API: https://gateway-api.sigs.k8s.io/
- NGINX Gateway Fabric: https://docs.nginx.com/nginx-gateway-fabric/
- Contour(Envoy ベース): https://projectcontour.io/
- Traefik ドキュメント: https://doc.traefik.io/traefik/
- HAProxy Kubernetes Ingress: https://www.haproxy.com/documentation/kubernetes-ingress/
- cert-manager: https://cert-manager.io/docs/