Certified Kubernetes Administrator (CKA) #19 Networking 2: Ingress、IngressClass、TLS
#18 Networking 1 では Service で Pod のまとまりに安定した進入口を付けました。ところが外部に公開するサービスが数十個あったらどうなるでしょうか。NodePort はポート番号でしか分けられず、LoadBalancer はサービスごとにクラウドロードバランサーを 1 つずつ立ち上げてコストが膨らみます。ドメインやパス別にトラフィックを分ける要求も、Service 一層だけでは解けません。
この記事のテーマである Ingress がその負担を一箇所にまとめます。L7 (HTTP/HTTPS) レベルで host と path を見て、トラフィックを適切な Service へ分けてくれるオブジェクトです。ただし Ingress は ルールを書いたマニフェストにすぎず、そのルールに従って実際のトラフィックを処理するのは Ingress Controller です。この二層モデルが試験と運用の両方で最もよくつまずく地点なので、そこに重点を置きます。
二層モデル: Ingress と Ingress Controller #
まず最初に掴むべきは、Ingress オブジェクトと Ingress Controller が互いに別物である という点です。この 2 つを混同すると、試験会場で「Ingress を作ったのになぜ応答がないのか」という罠にはまります。
| 区分 | 正体 | 役割 |
|---|---|---|
| Ingress (オブジェクト) | API リソース (マニフェスト) | 「この host のこの path はあの Service へ」のような ルール宣言 |
| Ingress Controller | 実際に動く Pod (通常 Deployment + Service) | そのルールを読んで トラフィックを実際にルーティングする リバースプロキシ |
Ingress マニフェストはそれ自体では何もしません。クラスターに Ingress Controller が立ち上がっていてこそ、コントローラーが Ingress オブジェクトを監視し、ルールどおりにプロキシ設定を作って外部トラフィックを受けます。コントローラーは種類が複数あります。
- ingress-nginx (Kubernetes プロジェクトが管理する nginx ベース。試験と学習での標準)
- Traefik
- HAProxy
- クラウドマネージド (GKE Ingress、AWS Load Balancer Controller など)
CKA 試験クラスターには通常 ingress-nginx が事前にインストールされているか、インストール用マニフェストが提供されるケースが多いです。運用クラスターを自分で構成するなら、Helm や公式マニフェストでコントローラーを先に入れる必要があります。コントローラーなしで Ingress だけ作ると、ADDRESS は空のままでトラフィックはどこにも届きません。
Ingress オブジェクトの構造 #
Ingress の核となるフィールドは spec.rules です。ルール 1 つは host (任意) と path のリストから成り、各 path はどの Service のどの port へ送るかを指します。
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: shop-ingress
namespace: default
spec:
ingressClassName: nginx
rules:
- host: shop.example.com
http:
paths:
- path: /api
pathType: Prefix
backend:
service:
name: api-service
port:
number: 8080
- path: /
pathType: Prefix
backend:
service:
name: web-service
port:
number: 80上のマニフェストは、shop.example.com へ入ってきたリクエストのうち /api で始まるものを api-service:8080 へ、それ以外の / を web-service:80 へ送ります。1 つのドメインの下でパスによってバックエンドを分ける path ベースのルーティング です。
host ベースのルーティング #
host を複数のルールに分けると、ドメインごとに別の Service へ送れます。1 つの進入口から複数のサイトをホストする構造です。
spec:
ingressClassName: nginx
rules:
- host: app.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: app-service
port:
number: 80
- host: blog.example.com # ドメインごとにルールを追加
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: blog-service
port:
number: 80host を省略すると、すべてのホスト名にルールが適用されます。
pathType: Prefix と Exact #
pathType は v1 Ingress で 必須フィールド です。抜かすとマニフェストが拒否されるため、試験でよく減点される地点です。
| pathType | マッチング方式 | 例 |
|---|---|---|
Prefix | パス要素 (/ 単位) の接頭辞一致 | /api は /api、/api/v1 にマッチ |
Exact | パスが正確に同一 | /api は /api のみにマッチ、/api/v1 は不一致 |
ImplementationSpecific | コントローラーの実装に委任 | コントローラーごとに解釈が異なる |
ほとんどの場合は Prefix を使い、正確に 1 つのパスだけ受ける必要があるときだけ Exact を使います。ImplementationSpecific はコントローラーの動作に依存するため、移植性が必要なら避けるほうが安全です。
defaultBackend #
どのルールにもマッチしないリクエストを受ける既定のバックエンドを置けます。設定しなければ、マッチしないリクエストはコントローラーの既定 404 に落ちます。spec.rules と同じレベルに置きます。
spec:
ingressClassName: nginx
defaultBackend: # rules にマッチしないリクエストの行き先
service:
name: fallback-service
port:
number: 80
rules:
- host: shop.example.com
# ... (上と同じルール)IngressClass: 複数のコントローラーを分ける #
1 つのクラスターに Ingress Controller が複数立ち上がっていることがあります。たとえば内部用 nginx と外部用クラウドコントローラーを一緒に運用するケースです。このとき 各 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-nginxIngress オブジェクトは spec.ingressClassName で自分が従う IngressClass を指定します。上のマニフェストの ingressClassName: nginx がまさにこの IngressClass を指します。両者が名前で結ばれてこそ、ingress-nginx コントローラーがその Ingress を自分のものと認識して処理します。
is-default-class: "true" アノテーションが付いた IngressClass が 1 つあれば、ingressClassName を省略した Ingress は自動的にその既定クラスに紐づきます。コントローラーが複数あったり既定クラスがない環境では、必ず ingressClassName を明示 しなければ意図したコントローラーへ行きません。
かつては
kubernetes.io/ingress.classアノテーションでクラスを指定していました。この方式は deprecated であり、現在はspec.ingressClassNameフィールドを使うのが標準です。試験でもフィールド方式で書きます。
TLS 終端 #
Ingress は HTTPS トラフィックを受けて TLS を終端 (terminate) できます。証明書とキーはクラスターに Secret として保存し、Ingress の spec.tls セクションでその Secret を参照します。
まず kubernetes.io/tls タイプの Secret を作ります。
# 証明書 (tls.crt) とキー (tls.key) で TLS Secret を生成
kubectl create secret tls shop-tls \
--cert=tls.crt \
--key=tls.keyその後 Ingress に tls セクションを追加し、該当する host を紐づけます。
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: shop-ingress
namespace: default
spec:
ingressClassName: nginx
tls:
- hosts:
- shop.example.com
secretName: shop-tls
rules:
- host: shop.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: web-service
port:
number: 80tls[].hosts に書いた host へ入ってくる HTTPS リクエストは、secretName が指す Secret の証明書で終端されます。ここでよくある誤りが 2 つあります。1 つ目は、tls[].hosts のドメインと rules[].host のドメインが 一致しないと 証明書が正しく適用されません。2 つ目は、Secret を Ingress と 別のネームスペース に作ると参照されません。Secret は Ingress と同じネームスペースになければなりません。
検証とトラブルシューティング #
作った後はすぐに状態を確認します。Ingress の ADDRESS が埋まったかが 1 次シグナルです。
# Ingress の一覧と ADDRESS を確認
kubectl get ingress
# ルール・TLS・イベントを詳しく見る
kubectl describe ingress shop-ingress運用と試験で詰まる典型的な原因は次のとおりです。
- ADDRESS が空: Ingress Controller がインストールされていないか、立ち上がっていません。
kubectl get pods -n ingress-nginxでコントローラー Pod の状態を先に見ます。 - 404 に落ちる:
pathTypeや path がずれているか、backend が指す Service・port が間違っています。kubectl get svcで対象の Service と port を照合します。 - TLS が適用されない: Secret の名前・タイプ (
kubernetes.io/tls)・ネームスペース、そしてtls.hostsとrules.hostの一致を確認します。 - 見当違いのコントローラーが処理する:
ingressClassNameが空か、間違ったクラスを指しています。
試験ポイント #
CKA の Services and Networking ドメイン (20%) で Ingress は定番の出題テーマです。次を手に覚えておくと時間を節約できます。
- Ingress は 宣言 (オブジェクト) であり、ルーティングは コントローラー が行うという二層モデル。コントローラーがなければ動作しない点を常に最初に思い出します。
- v1 Ingress で
pathTypeは 必須 です。抜かして減点されないようにします。 - コントローラーの指定はアノテーションではなく
spec.ingressClassNameフィールドで行います。 - TLS は
kubernetes.io/tlsSecret を作ってspec.tlsで参照し、host がrulesと一致してネームスペースが同じである必要があります。 apiVersionはnetworking.k8s.io/v1です。旧バージョンの表記を使わないよう注意します。
kubectl create ingress コマンドで骨組みを素早く作ってから手で編集する方法も有効です。
# コマンドで Ingress の骨組みを生成し YAML を出力
kubectl create ingress shop-ingress \
--class=nginx \
--rule="shop.example.com/api*=api-service:8080" \
--rule="shop.example.com/*=web-service:80" \
--dry-run=client -o yamlIngress の概念をより広い文脈で復習するなら、K8s 中級 #3 Ingress と Ingress Controller を併せて見るとよいです。
まとめ #
この記事で押さえたこと:
- Ingress は host・path ベースの L7 ルーティングルールを宣言するオブジェクト であり、実際のトラフィック処理は Ingress Controller が行います。コントローラーがなければ動作しません。
- ルールは
spec.rulesの host と path で構成し、各 path はpathType(Prefix/Exact) と backend (Service + port) を持ちます。defaultBackendで未マッチのリクエストの既定の行き先を置きます。 - IngressClass が複数のコントローラーを分け、Ingress は
spec.ingressClassNameで自分のクラスを指定します。 - TLS は
kubernetes.io/tlsSecret を作ってspec.tlsで参照し、host の一致と同一ネームスペースが条件です。 - 検証は
kubectl get ingressの ADDRESS とdescribeから始めます。
次へ: Networking 3 #
Ingress で外部からの進入を整理しました。次はクラスター内部の名前解決とトラフィック制御です。
#20 Networking 3: CoreDNS、NetworkPolicy では、Pod と Service が互いを名前で見つける CoreDNS の動作と設定、そしてどの Pod がどの Pod と通信できるかを制御する NetworkPolicy の ingress/egress ルールを運用の観点から整理します。