Kubernetes 解体新書Part 2 ネットワーク

Ingress の次の HTTP 入口

URL に応じてアプリへ通信を振り分けます。Ingress と Gateway API の違いを見て、自分のルールを作ります。

  • L1 Web ターミナル
  • 更新 2026年10月6日

同じ Web サイトでも、/api へのアクセスは API 用のアプリへ、それ以外は画面を返すアプリへ送りたい。 Kubernetes でも、URL に応じた振り分けを設定できます。

これまで使われてきた Ingress と、より多くの設定や役割分担を扱う Gateway API を比べます。 最後に自分の振り分けルールを 1 つ作り、ブラウザーからアクセスして確かめます。

GOAL この章のゴール

  • Ingress と Gateway API の設定・役割分担の違いが分かる
  • 通信の入口と振り分けルールを別々に設定できる
  • 自分のアプリへのルールを追加し、ブラウザーから開ける

Ingress の限界

たとえば example.com/api を API 用の Service へ送るには、ホスト名、パス、送り先を設定します。 この HTTP / HTTPS の振り分けルールを書くリソースが Ingressイングレスホスト名やパスに応じて、外部からの HTTP / HTTPS 通信を Service へ振り分けるルールを書くリソース。用語集で見る です。 設定の rules に host、path、backend を書くと、Ingress controller がそれを読み、実際のプロキシやロードバランサーに反映します。 ドキュメントは「Ingress リソースを作るだけでは何も起きず、Ingress controller が必要」とも書いています。 小さいことは長所でしたが、運用で必要になる項目の多くが入っていませんでした。

Ingress の限界: 1 つのリソースに、基盤運用者の関心 (LB 自体) と開発者の関心 (ホスト名とパス) が同居するIngress リソースは host / path / backend の最小限の項目しか持たず、TLS の詳細やタイムアウト、LB のプロトコルは実装ごとの annotation に逃がされる。基盤運用者と開発者の役割分担も曖昧になる。Ingress (networking.k8s.io/v1)ingressClassName: nginxrules: host / path / backendtls: [secretName]annotations (実装ごとに違う)nginx.ingress.kubernetes.io/rewrite-targetnginx.ingress.kubernetes.io/proxy-read-timeoutalb.ingress.kubernetes.io/target-typealb.ingress.kubernetes.io/schemeスキーマ無し、移植性無し基盤運用者の関心LB 自体の管理、待ち受けポート、TLS 終端、どのチームがどのホスト名を使えるか→ Ingress には書く場所が無い開発者の関心自分のサービスにホスト名とパスで届けたい、ヘッダの書き換え、重み付け、タイムアウト→ annotation 頼み
図 1Ingress は host / path / backend しか持たず、TLS の詳細やタイムアウト、LB のプロトコルは実装ごとの annotation に逃がされる。

1 つ目の限界は、役割の曖昧さです。 基盤を運用する人は入口の LB 自体を管理したく、アプリの開発者は用意された LB に自分のサービスをつなぎたいのに、Ingress は 1 つのリソースで両方を書かせます。 IngressClass で実装を選べるようにはなりましたが、LB の管理とルーティングの規則は分けられません。

2 つ目は、足りない項目の逃げ場が annotation (リソースに付ける自由形式のメモ欄) だったことです。 公式ドキュメントは「Ingress controller は挙動の設定に annotation をよく使うので、選んだ controller のドキュメントでどの annotation が期待されるかを確認する」よう求めています。 パスの書き換え、タイムアウト、ALB のターゲット種別は、どれも nginx.ingress.kubernetes.io/… や alb.ingress.kubernetes.io/… といった実装固有の annotation で書きます。 annotation にはスキーマも検証も無く、別の Ingress controller に移すと全部書き直しになります。

Ingress API と ingress-nginx の保守は別の話

Ingress API は Kubernetes に残っていますが、その実装の一つであるコミュニティ版 ingress-nginx は 2026 年 3 月に保守を終了しました。 Kubernetes の公式告知は、終了後にバグ修正やセキュリティ更新を提供しないとしています。 Ingress の YAML が使えることと、それを読む controller の保守が続いていることは別に確認する必要があります。 NGINX Gateway Fabric は別のプロジェクトであり、名前に NGINX が含まれる製品をすべて同じ保守状況と考えることもできません。

Gateway API の役割分担

Gateway API は、SIG Network が Ingress の限界を踏まえて作り直した仕様です。 公式ドキュメントは設計の特徴を「役割指向 (role-oriented)」と呼び、3 つの役割を定義しています。 複数のクラスタを複数のテナントに提供する基盤を管理する Infrastructure Provider、ポリシーやネットワークアクセス、アプリの権限を管理する Cluster Operator、アプリの設定と Service の組み合わせを管理する Application Developer です。 3 つのリソースが、この役割に対応します。

Gateway API の役割分担: 基盤運用者が GatewayClass、クラスタ管理者が Gateway、開発者が HTTPRouteGatewayClass は LB の実装 (controllerName) を表し基盤運用者が提供する。Gateway はその実装で作る LB のフロントエンド (listener) でクラスタ管理者が作る。HTTPRoute はホスト名やパスをサービスに向ける規則で開発者が書き、parentRef で Gateway に取り付ける。基盤運用者GatewayClasscontrollerName:io.cilium/gateway-controller「どの実装か」Ingress controller やCCM の Service controllerに相当する立場クラスタ管理者GatewaygatewayClassNamelisteners: port 80 / 443 hostname: *.example allowedRoutes「LB のフロントエンド」利用できる入口を先に生やしておく開発者HTTPRouteparentRefs: [Gateway]hostnames: [web.…]rules: matches: path / backendRefs: [svc]「自分のサービスへ」TCPRoute / GRPCRoute も同じ形参照parentRef
図 2GatewayClass は実装、Gateway は LB のリスナー、HTTPRoute は経路。それぞれ基盤運用者、クラスタ管理者、開発者が書く。
  • GatewayClass:公式ドキュメントの定義では「共通の設定と振る舞いを持つ Gateway の集合を定義する」cluster-scoped のリソース。controllerName に「このクラスの Gateway を管理する controller の名前」(この演習クラスタでは io.cilium/gateway-controller) が入る。基盤の運用者が提供する。
  • Gateway:「通信を処理する基盤のインスタンス」で、クラウドの LB やクラスタ内のプロキシを表す。ALB のリスナーに相当し、待ち受けるポートとプロトコル、ホスト名、どの namespace の Route を受け付けるか (allowedRoutes) を listeners に書く。既定では同じ namespace の Route しか受け付けない。クラスタ管理者が先に作っておく。
  • HTTPRoute:「Gateway の listener から backend への HTTP リクエストの経路」を書く。parentRefs で取り付け先の Gateway を指し、hostnames と rules の matches で一致条件を、backendRefs で Service を指す。開発者が自分の namespace に書く。gRPC には GRPCRoute、TLS の SNI で振り分けるなら TLSRoute、TCP / UDP のストリームには TCPRoute / UDPRoute がある。

Ingress では annotation だった項目 (ヘッダの書き換え、重み付け、リダイレクト、タイムアウト) は、HTTPRoute の filters や rules としてスキーマ付きで定義されています。 公式ドキュメントはこれを「Ingress ではカスタム annotation でしかできなかったヘッダによる振り分けや重み付けを表現できる」と説明しています。 実装を変えても HTTPRoute はそのまま使えます。

誰がプロキシや LB を作るのか

GatewayClass の controllerName は、Service の loadBalancerClass (第 9 章) と同じく、この Gateway を実装する controller を指します。

同じ Gateway / HTTPRoute を、違う実装が受け取る: Cilium、Envoy Gateway、GKE、Istio、AWS Load Balancer Controller開発者が書く HTTPRoute は共通で、GatewayClass の controllerName によって Cilium の Envoy、Envoy Gateway、GKE の Cloud Load Balancing、Istio のメッシュ、AWS の ALB が実装になる。HTTPRoute (共通)hostnames / rules / backendRefsCiliumEnvoy を Gateway ごとに起動Envoy GatewayCNCF、Envoy 公式GKE GatewayCloud Load BalancingIstioingress / mesh (GAMMA)AWS LBCALB / NLBGatewayClass.controllerName で担当が決まるIngress の annotation だった項目が、共通スキーマと実装の選択に分かれた
図 3HTTPRoute は共通。GatewayClass の controllerName で、Cilium の Envoy、Envoy Gateway、GKE の LB、Istio、AWS の ALB のどれが HTTPRoute を受け取るかが決まる。

Gateway API の実装一覧には、Cilium、Envoy Gateway、GKE、Istio、AWS Load Balancer Controller、NGINX Gateway Fabric などが適合実装として並んでいます。 Cilium は Envoy (HTTP プロキシ) で Gateway を実装し、ドキュメントによれば「既定では Gateway ごとに type: LoadBalancer の Service を作る」構成です。 GKE は Cloud Load Balancing で、AWS Load Balancer Controller は L7 の Route を ALB、L4 の Route を NLB で実装します。 開発者が書く HTTPRoute は、どの実装でも同じです。

実装の対応範囲を調べる

Gateway API の公式実装一覧には、Envoy Gateway、Cilium、NGINX Gateway Fabric など、異なるデータプレーンや運用方法を持つ実装が並びます。 「Gateway API 対応」の一言で選ばず、使用する API のバージョン、Gateway と Mesh のどちらに対応するか、必要な Route と拡張機能の conformance report を確認します。 共通 API の試験に通ったことは、独自の認証設定や監視機能まで同じであることを意味しません。 この教材の Cilium で動いた設定を別の製品へ移すときも、この対応範囲を確認します。

演習クラスタの Gateway に HTTPRoute を取り付ける

演習クラスタには、kube-classroom が Gateway を用意しています。 kube-classroom-gateway namespace の tenant という Gateway は、listener http (port 80) で *.<あなたの ID>.kube.inductor.dev を受け、全 namespace からの Route を許可しています。 GatewayClass は kube-classroom です。

演習クラスタの Gateway: kube-classroom が用意した Gateway tenant に、自分の HTTPRoute を取り付けるブラウザからの *.<user>.kube.inductor.dev は cloudflared 経由でノードの NodePort に届く。Cilium が Gateway ごとに起動した Envoy が HTTPRoute の規則でホスト名を見て、自分の namespace の Service へ転送する。ブラウザweb.you.kube.inductor.devcloudflared(kube-classroom 側)演習クラスタのノード10.0.1.11NodePort :3xxxxCiliumGatewayClassConfigGatewayClass kube-classroomio.cilium/gateway-controllerns: kube-classroom-gatewayGateway tenantlistener http :80 *.you.kube.inductor.devcilium-gateway-tenant (Envoy)envoyns: default (あなた)HTTPRoute webparentRef: tenantService web→ Pod取り付け転送
図 4ブラウザからの通信は cloudflared 経由でノードの NodePort に届き、Cilium の Envoy が HTTPRoute の規則で自分の Service に転送する。

Cilium は既定だと Gateway ごとに type: LoadBalancer の Service を作りますが、第 9 章のとおりこのクラスタには LB を作る controller が居ません。 Cilium には GatewayClass の parametersRef から参照する CiliumGatewayClassConfig という CRD があり、spec.service.type で生成する Service の type を変えられます。 演習クラスタではこれで NodePort にしてあり、その NodePort に kube-classroom の cloudflared が外からの通信を流し込みます。

まず、用意されているものを確認します。

GatewayClass と Gateway を見る
kubectl get gatewayclass
kubectl -n kube-classroom-gateway get gateway tenant -o yaml | yq '.spec.listeners, .status.conditions[] | select(.type=="Programmed")'
kubectl -n kube-classroom-gateway get svc

出力例

NAME             CONTROLLER                     ACCEPTED   AGE
kube-classroom   io.cilium/gateway-controller   True       2h
- allowedRoutes:
    namespaces:
      from: All
  hostname: '*.you.kube.inductor.dev'
  name: http
  port: 80
  protocol: HTTP
status: "True"
type: Programmed
NAME                    TYPE       CLUSTER-IP     EXTERNAL-IP   PORT(S)        AGE
cilium-gateway-tenant   NodePort   10.96.33.201   <none>        80:31234/TCP   2h

cilium-gateway-tenant は、Cilium が Gateway のために作った Envoy の Service で、NodePort なのは CiliumGatewayClassConfig の効果です。 次に、第 5 章の web Service に向けて HTTPRoute を書きます。 hostnames は listener のワイルドカードに収まる名前にします。

HTTPRoute を作る
ME=$(kubectl -n kube-classroom-gateway get gateway tenant -o jsonpath='{.spec.listeners[0].hostname}' | sed 's/^\*\.//')
echo "hostname suffix: $ME"
kubectl apply -f - <<EOF
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: web
spec:
  parentRefs:
    - name: tenant
      namespace: kube-classroom-gateway
  hostnames:
    - web.$ME
  rules:
    - matches:
        - path:
            type: PathPrefix
            value: /
      backendRefs:
        - name: web
          port: 80
EOF
kubectl get httproute web -o yaml | yq '.status.parents[0].conditions[] | {type, status, reason}'

出力例

hostname suffix: you.kube.inductor.dev
type: Accepted
status: "True"
reason: Accepted
type: ResolvedRefs
status: "True"
reason: ResolvedRefs

Gateway API の仕様では、Accepted は「Route が Gateway に受け入れられたか拒否されたか」、ResolvedRefs は「controller が Route の参照先 (ここでは backendRefs の Service) を全て解決できたか」を表す条件です。 どちらも True なら、ブラウザで http://web.<あなたの ID>.kube.inductor.dev/ を開くと nginx の画面が出ます。 ターミナルからは、Gateway の Service にホスト名付きで送っても確認できます。

Gateway 経由で届くことを確認する
GW=$(kubectl -n kube-classroom-gateway get svc cilium-gateway-tenant -o jsonpath='{.spec.clusterIP}')
curl -s -o /dev/null -w '%{http_code}\n' -H "Host: web.$ME" "http://$GW/"
curl -s -o /dev/null -w '%{http_code}\n' -H "Host: other.$ME" "http://$GW/"

出力例

200
404

web. のホスト名は HTTPRoute に一致して nginx に届き、other. はどの Route にも一致しないので Envoy が 404 を返します。 クラスタ管理者が用意した Gateway に、開発者が HTTPRoute だけを足した形です。

片付け
kubectl delete httproute web

この Part のまとめ

Part 2 では、docker0 から始めて、ノードをまたぐ Pod ネットワーク、Service の ClusterIP の書き換え表、ELB からの経路、コンテナネイティブ LB、クラウド連携のコンポーネント、Gateway API まで追いました。 Pod の NIC は CNI プラグインが、ClusterIP の書き換え表は kube-proxy か Cilium が、LB は CCM や AWS Load Balancer Controller が、HTTP の入口は GatewayClass の controller が作っていました。 どれも Kubernetes 本体とは別のプログラムです。 Part 4 (インターフェース) では、この任せ方の取り決めそのものを扱います。

ふりかえり

QGateway API で開発者が書くリソースは?

GatewayClass は基盤運用者が実装として提供し、Gateway はクラスタ管理者がフロントエンドとして用意します。開発者は HTTPRoute で自分のサービスへの経路だけを書きます。

Q2026 年時点の Ingress の状況として正しいのは?

kubernetes.io は Ingress API が凍結されたと明記しています。GA の安定性保証は続き削除予定もありませんが、新機能は Gateway API 側にだけ入ります。

Q演習クラスタの Gateway の Service が NodePort なのはなぜ?

Cilium の既定は type: LoadBalancer ですが、第 9 章のとおりこのクラスタには Service controller が居ません。GatewayClass の parametersRef から CiliumGatewayClassConfig を参照して NodePort にし、kube-classroom 側の cloudflared がそこへ通信を届けています。

参考

読み切ると称号を獲得

パケットの行き先を視る者

この Part を読み切りました。

称号一覧