はじめに: なぜ Ingress は最初から紛らわしいのか
Kubernetes を初めて運用するときに最も多く聞かれる質問の一つが「Service で LoadBalancer を作ればいいのに、なぜ Ingress が必要なのか」というものです。小さなクラスタでサービスが1つや2つなら、LoadBalancer タイプの Service だけでも十分です。しかしサービスが数十個に増えると話は変わります。サービスごとにクラウドのロードバランサを1つずつ立てると、コストが線形に増加し、各ロードバランサごとに別々のパブリック IP と TLS 証明書を管理しなければなりません。
Ingress はこの問題を解決します。単一の入口(通常は1つのロードバランサ)の背後で、ホスト名と URL パスを基準にトラフィックを複数のバックエンドサービスへルーティングします。L7(HTTP/HTTPS)レベルで動作するため、パスベースのルーティング、ホストベースの仮想ホスティング、TLS 終端を一箇所で処理できます。
ところが実務で最大の混乱は「Ingress が2つのものを同時に指す」点にあります。一つは **Ingress リソース**(API オブジェクト)で、もう一つは **Ingress Controller**(実際に動作するプロキシ)です。この2つを区別できないと、「Ingress を作ったのになぜ何も起きないのか」というような罠にはまります。本記事ではこの区別から出発し、動作原理、リソース仕様、TLS、コントローラ比較、そして2026年現在の Gateway API への移行の流れまで順を追って扱います。
Ingress API vs Ingress Controller — 最も重要な区別
まず2つの概念を明確に分けましょう。
- **Ingress リソース(API オブジェクト)**: 「example.com の /api パスは api-service へ送れ」というルーティングルールを宣言的に記述した YAML 仕様です。これ自体は etcd に保存されたデータにすぎず、どのトラフィックも処理しません。
- **Ingress Controller**: クラスタで実際に動作するプログラム(通常はリバースプロキシ)です。Ingress リソースを watch し、変更を検知すると自身の設定をそれに合わせて生成し、入ってくるトラフィックをルールどおりにルーティングします。
核心は **Ingress リソースを作ってもコントローラがクラスタにインストールされていなければ何も起きない** という点です。Deployment を作るとコントロールプレーンが自動的に Pod を立ち上げますが、Ingress は別途インストールしたサードパーティのコントローラがあって初めて意味を持ちます。これが他のリソースと決定的に異なる部分です。
例えるなら Ingress リソースは「注文票」で、Ingress Controller は「厨房」です。注文票だけ積み上げても厨房がなければ料理は出てきません。
代表的なコントローラには ingress-nginx、Traefik、HAProxy Ingress、Contour(Envoy ベース)、Kong、APISIX などがあります。クラウドプロバイダも独自のコントローラ(AWS Load Balancer Controller、GKE Ingress など)を提供しています。
動作の流れ: API watch から reload まで
Ingress Controller の内部動作は、ほとんど次のような制御ループ(control loop)に従います。
Kubernetes API Server
│
(1) watch Ingress / Service / Endpoints / Secret
│
▼
┌───────────────────────────────────────────┐
│ Ingress Controller │
│ │
│ (2) 変更検知 → 内部モデル更新 │
│ (3) ルーティング設定ファイル/オブジェクト生成 │
│ (例: nginx.conf テンプレートのレンダリング) │
│ (4) プロキシ reload または動的 reconfigure │
│ │
│ ┌─────────────┐ ┌──────────────┐ │
│ │ Controller │ ───▶ │ Data Plane │ │
│ │ (watcher) │ cfg │ (nginx/envoy) │ │
│ └─────────────┘ └──────────────┘ │
└───────────────────────────────────────────┘
│
(5) 外部トラフィックのルーティング
▼
Client ─▶ LoadBalancer ─▶ Controller Pod ─▶ Backend Service ─▶ Pod
段階ごとに見ると次のとおりです。
1. **Watch**: コントローラは API サーバに watch 接続を張り、Ingress、Service、Endpoints(または EndpointSlice)、TLS Secret などの変更をリアルタイムに購読します。
2. **モデル更新**: 変更イベントが届くと、コントローラ内部にルーティングモデルを再構成します。
3. **設定生成**: そのモデルをデータプレーンが理解できる形に変換します。ingress-nginx なら nginx.conf をテンプレートでレンダリングし、Envoy ベースのコントローラなら xDS 設定を作ります。
4. **適用(reload/reconfigure)**: nginx のように設定ファイルベースの場合は reload を実行し、Envoy のように動的設定をサポートする場合は無停止で reconfigure します。ingress-nginx も動的な backend 変更(エンドポイントの追加/削除)は Lua モジュールで reload なしに処理します。
5. **トラフィックルーティング**: データプレーンが実際の HTTP リクエストをルールどおりにバックエンドサービスへ転送します。
ここで重要なのは **コントローラがトラフィックをバックエンドサービスの ClusterIP ではなく直接 Pod エンドポイントへ送る場合が多い** という点です。ingress-nginx はデフォルトで Endpoints/EndpointSlice を watch し、個々の Pod IP へ負荷分散します。そのため kube-proxy の iptables ラウンドロビンを経由せず、コントローラ自身のロードバランシング(例: ewma、round_robin)を適用できます。
Ingress リソース仕様の詳細
ここから Ingress リソースの仕様をフィールドごとに見ていきます。次は `networking.k8s.io/v1` を基準とした典型例です。
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: shop-ingress
namespace: shop
spec:
ingressClassName: nginx
defaultBackend:
service:
name: fallback-service
port:
number: 80
rules:
- host: shop.example.com
http:
paths:
- path: /api
pathType: Prefix
backend:
service:
name: api-service
port:
number: 8080
- path: /static
pathType: Prefix
backend:
service:
name: static-service
port:
number: 80
- host: admin.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: admin-service
port:
number: 3000
rules と host
`rules` はルーティングルールの配列です。各ルールは任意で `host` を持てます。`host` が指定されると、リクエストの Host ヘッダが一致するときだけそのルールが適用されます。`host` を省略するとすべてのホストに対して適用されます。ワイルドカードホスト(`*.example.com`)もサポートされますが、単一ラベルのみマッチするという制約があります。つまり `*.example.com` は `a.example.com` にはマッチしますが `a.b.example.com` にはマッチしません。
paths と pathType
各 `host` の下には複数の `paths` を置けます。`pathType` はパスのマッチ方式を決定し、3つの値があります。
- **Prefix**: パスをスラッシュ単位の要素に分け、接頭辞でマッチします。`/api` は `/api`、`/api/v1` にマッチしますが `/apixyz` にはマッチしません。
- **Exact**: パスが正確に一致する必要があります。大文字小文字を区別します。
- **ImplementationSpecific**: マッチ方式をコントローラ実装に委ねます。ingress-nginx はこの場合、正規表現など独自のルールを適用できます。
`pathType` は v1 API で **必須フィールド** です。省略すると Ingress の作成が拒否されます。
backend service と defaultBackend
`backend` はトラフィックの送信先を指定し、サービス名とポート(番号または名前)を明記します。`defaultBackend` はどのルールにもマッチしないリクエストを受けるフォールバックです。指定しないと、マッチしないリクエストはコントローラのデフォルト404ページへ落ちます。
resource backend
サービスの代わりにリソース(例: オブジェクトストレージを指すカスタムリソース)をバックエンドに指定することもできます。`backend.service` と `backend.resource` は相互排他です。
IngressClass と複数コントローラ
1つのクラスタにコントローラを2つ以上インストールできます(例: 内部用と外部用)。このとき「この Ingress リソースを誰が処理するか」を決めるメカニズムが **IngressClass** です。
apiVersion: networking.k8s.io/v1
kind: IngressClass
metadata:
name: nginx
annotations:
ingressclass.kubernetes.io/is-default-class: "true"
spec:
controller: k8s.io/ingress-nginx
Ingress リソースでは `spec.ingressClassName: nginx` でどのクラスを使うか指定します。コントローラは自分が担当するクラスの Ingress だけを処理し、それ以外は無視します。`is-default-class` アノテーションが true の IngressClass があれば、`ingressClassName` を省略した Ingress はそのデフォルトクラスへ自動的に割り当てられます。
かつてはクラスを `kubernetes.io/ingress.class` アノテーションで指定していましたが、この方式は deprecated です。新規環境では `spec.ingressClassName` を使ってください。複数コントローラ運用の詳細は別記事で扱います。
TLS の設定
Ingress で HTTPS を終端するには、TLS Secret と `spec.tls` を使います。
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: shop-ingress-tls
namespace: shop
spec:
ingressClassName: nginx
tls:
- hosts:
- shop.example.com
secretName: shop-tls
rules:
- host: shop.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: shop-service
port:
number: 80
`secretName` が指す Secret は `kubernetes.io/tls` タイプである必要があり、`tls.crt` と `tls.key` を含んでいなければなりません。Secret は Ingress と同じ名前空間に存在する必要があります。
apiVersion: v1
kind: Secret
metadata:
name: shop-tls
namespace: shop
type: kubernetes.io/tls
data:
tls.crt: <base64-encoded-cert>
tls.key: <base64-encoded-key>
実務では証明書を手動で管理せず、**cert-manager** を使って Let's Encrypt などから自動発行・更新します。cert-manager は ACME チャレンジを処理し、発行された証明書を上記の形の Secret として保存します。すると Ingress Controller がその Secret を watch して TLS 終端に使用します。
コントローラ種類の概要比較
代表的な Ingress Controller を比較すると次のとおりです。
| コントローラ | データプレーン | 設定更新方式 | 特徴 | 備考 |
| --- | --- | --- | --- | --- |
| ingress-nginx | NGINX | nginx.conf reload + Lua 動的エンドポイント | 最も広く使われる、アノテーション豊富 | メンテナンスモード寄り、セキュリティパッチ中心 |
| NGINX Ingress (F5) | NGINX / NGINX Plus | 設定 reload | 商用サポート(Plus)、別プロジェクト | ingress-nginx とは別プロジェクト |
| Traefik | Traefik | 動的ホット reconfigure | CRD/アノテーション、自動サービスディスカバリ | ダッシュボード提供 |
| HAProxy Ingress | HAProxy | runtime API + reload | 高性能 L4/L7、精緻なヘルスチェック | 細かいチューニング可能 |
| Contour | Envoy | xDS 動的 | HTTPProxy CRD、委任モデル | CNCF プロジェクト |
| Kong | Kong/NGINX | DB-less 動的 | API ゲートウェイ機能、プラグイン | 認証/レート制限が豊富 |
| APISIX | APISIX | etcd ベース動的 | プラグインエコシステム、高性能 | Apache プロジェクト |
| Emissary | Envoy | 動的 | Mapping CRD ベース | 旧 Ambassador |
選択基準は通常次のとおりです。単純なルーティングと幅広いリファレンスが必要なら ingress-nginx、動的サービスディスカバリと運用の容易さが重要なら Traefik、API ゲートウェイ級の認証/プラグインが必要なら Kong/APISIX、Envoy ベースの精緻なポリシーが必要なら Contour を検討します。
2026年のコンテキスト: Ingress API frozen と Gateway API への継承
ここで必ず押さえるべき2026年現在の流れがあります。**Ingress API は frozen の状態** です。つまり `networking.k8s.io/v1` の Ingress は安定して動き続けますが、新しい機能はもう追加されません。ヘッダベースのルーティング、トラフィック分割(重み付け)、明示的なメソッドマッチングといった高度な機能はすべてコントローラ別のアノテーションで回避するしかなく、この「アノテーション地獄」が Ingress API の根本的な限界として指摘されてきました。
その後継として登場したのが **Gateway API** です。Gateway API は GatewayClass、Gateway、HTTPRoute など役割が分離されたリソースモデルを提供し、標準仕様の中でヘッダマッチング、トラフィックの重み付け分割、クロス名前空間ルーティングなどをサポートします。インフラ運用者(Gateway 管理)とアプリケーション開発者(Route 管理)の責任を分離するよう設計されているのが大きな違いです。
また、これまで事実上の標準のように使われてきた **ingress-nginx** は、メンテナンスモードに近い流れで、新機能よりセキュリティパッチ中心に運用されています。したがって新規プロジェクトなら、最初から Gateway API とそれを実装するコントローラ(例: Envoy Gateway、Traefik、Contour の Gateway サポートなど)を検討するのが合理的です。
とはいえ、今すぐすべての Ingress を捨てろという意味ではありません。Ingress は依然として広く動作し、単純なルーティングには十分です。ただし新しく設計するなら Gateway API を第一候補に置き、既存資産は段階的に移行する戦略が推奨されます。
最初のデプロイ実習
では ingress-nginx で最初の Ingress をデプロイしてみましょう。まずコントローラをインストールします(Helm 使用)。
helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx
helm repo update
helm install ingress-nginx ingress-nginx/ingress-nginx \
--namespace ingress-nginx --create-namespace
インストール後、コントローラが LoadBalancer タイプの Service で外部 IP を受け取ったか確認します。
kubectl get svc -n ingress-nginx
kubectl get pods -n ingress-nginx
次にテスト用のアプリケーションとサービスをデプロイします。
apiVersion: apps/v1
kind: Deployment
metadata:
name: hello
spec:
replicas: 2
selector:
matchLabels:
app: hello
template:
metadata:
labels:
app: hello
spec:
containers:
- name: hello
image: hashicorp/http-echo
args:
- "-text=hello from ingress"
ports:
- containerPort: 5678
apiVersion: v1
kind: Service
metadata:
name: hello-service
spec:
selector:
app: hello
ports:
- port: 80
targetPort: 5678
そして Ingress を作ります。
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: hello-ingress
spec:
ingressClassName: nginx
rules:
- host: hello.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: hello-service
port:
number: 80
ローカルでテストするときは、hosts ファイルにコントローラの外部 IP を hello.example.com としてマッピングするか、curl の Host ヘッダで模倣します。
curl -H "Host: hello.example.com" http://<EXTERNAL-IP>/
`hello from ingress` が出れば成功です。
運用とチューニングのポイント
運用段階でよく触る設定をまとめます。ほとんどは ingress-nginx 基準のアノテーションまたは ConfigMap です。
metadata:
annotations:
nginx.ingress.kubernetes.io/proxy-body-size: "50m"
nginx.ingress.kubernetes.io/proxy-read-timeout: "60"
nginx.ingress.kubernetes.io/ssl-redirect: "true"
nginx.ingress.kubernetes.io/rewrite-target: /$2
- **proxy-body-size**: アップロードサイズ制限。ファイルアップロードサービスで 413 エラーが出たら最初に確認します。
- **proxy-read-timeout**: バックエンド応答の待機時間。長時間処理が 504 で切れるなら増やします。
- **ssl-redirect**: HTTP を HTTPS へ強制リダイレクト。
- **rewrite-target**: パスの書き換え。正規表現のキャプチャグループと併用します。
ConfigMap ではグローバル設定(ワーカープロセス数、keepalive、gzip など)を調整します。コントローラ自体もリソースの requests/limits、HPA、PodDisruptionBudget を設定して安定運用すべきです。コントローラはすべてのトラフィックが通る単一地点なので、十分なレプリカ数とノード分散(topologySpreadConstraints)が重要です。
落とし穴とトラブルシューティング
実務でよく遭遇する問題をまとめます。
**1. Ingress を作ったのに ADDRESS が空。**
コントローラがインストールされていないか、`ingressClassName` が誤っていてどのコントローラもその Ingress を掴んでいない場合です。`kubectl get ingress` で ADDRESS 列を確認し、`kubectl describe ingress` のイベントを見ます。
kubectl get ingress
kubectl describe ingress hello-ingress
**2. 503 Service Temporarily Unavailable。**
バックエンドサービスのセレクタが Pod と合っておらず Endpoints が空の可能性が高いです。次を確認します。
kubectl get endpoints hello-service
空ならサービスセレクタと Pod ラベル、そして Pod の readiness probe の状態を点検します。
**3. コントローラから 404 Not Found が返る。**
Host ヘッダがルールの `host` と異なるか、`pathType`/パスマッチが意図と異なるときです。`Prefix` と `Exact` の違い、ワイルドカードホストの単一ラベル制約を再確認します。
**4. rewrite-target が意図どおり動かない。**
キャプチャグループの正規表現とパス定義がずれている場合です。ingress-nginx で `rewrite-target` を使うときはパスを正規表現キャプチャの形で定義し、`use-regex` アノテーションと一緒に検証します。
**5. TLS が適用されない。**
Secret タイプが `kubernetes.io/tls` でない、Secret が Ingress と別の名前空間にある、`spec.tls.hosts` と `rules.host` が不一致、のいずれかです。cert-manager を使うなら Certificate、CertificateRequest、Order リソースの状態を追跡します。
**6. コントローラの reload が頻繁で遅延が生じる。**
Ingress/Service/Endpoints の変更が頻繁だと設定 reload が頻発することがあります。ingress-nginx は動的エンドポイント更新でほとんどの reload を回避しますが、アノテーションやホストルールの変更は reload を引き起こします。変更をまとめてデプロイし、コントローラログで reload 頻度を監視します。
kubectl logs -n ingress-nginx deploy/ingress-nginx-controller | grep -i reload
おわりに
Ingress をきちんと扱うには、まず **Ingress リソース(宣言)と Ingress Controller(実行)の区別** を体得する必要があります。その上で API watch → 設定生成 → reload に至る制御ループを理解すれば、ルーティングがなぜ動くのか、あるいはなぜ動かないのかを構造的に推論できます。
リソース仕様(rules/paths/pathType/backend/defaultBackend)、IngressClass を通じたコントローラ選択、TLS Secret 連携まで習得すれば、基本的な運用は十分こなせます。ただし2026年現在は Ingress API が frozen で、Gateway API が後継標準として定着していく移行期です。既存の Ingress 資産は安定して維持しつつ、新規設計では Gateway API を積極的に検討することをお勧めします。次のステップとしては、Gateway API への移行と複数コントローラ運用を見ていくとよいでしょう。
参考資料
- Kubernetes 公式ドキュメント — Ingress: https://kubernetes.io/docs/concepts/services-networking/ingress/
- Kubernetes 公式ドキュメント — Ingress Controllers: https://kubernetes.io/docs/concepts/services-networking/ingress-controllers/
- ingress-nginx 公式ドキュメント: https://kubernetes.github.io/ingress-nginx/
- Traefik 公式ドキュメント: https://doc.traefik.io/traefik/
- HAProxy 公式ドキュメント: https://www.haproxy.com/documentation/
- Project Contour 公式ドキュメント: https://projectcontour.io/docs/
- Kong Ingress Controller ドキュメント: https://docs.konghq.com/kubernetes-ingress-controller/
- Apache APISIX Ingress ドキュメント: https://apisix.apache.org/docs/ingress-controller/getting-started/
- Gateway API 公式サイト: https://gateway-api.sigs.k8s.io/
- cert-manager 公式ドキュメント: https://cert-manager.io/docs/
현재 단락 (1/252)
Kubernetes を初めて運用するときに最も多く聞かれる質問の一つが「Service で LoadBalancer を作ればいいのに、なぜ Ingress が必要なのか」というものです。小さなクラ...