はじめに
前回は、増減・再作成されるPodに対して、安定した接続先を提供するServiceについて学びました。
Service
├── Rails Pod 1
├── Rails Pod 2
└── Rails Pod 3
ClusterIP型のServiceは、Kubernetesクラスター内部から利用するための接続先です。
それでは、インターネット上のブラウザから送られたHTTP・HTTPSリクエストは、どのように目的のServiceへ届くのでしょうか。
また、次のようにドメイン名やURLパスによって転送先を変えたい場合、どこにルールを書くのでしょうか。
sign.example.com/api
→ api-service
sign.example.com/admin
→ admin-service
そこで登場するのが Ingress(イングレス) です。
この記事では、次の内容を整理します。
- Ingressとは何か
- IngressリソースとIngress Controllerの違い
- Host名・URLパスによるルーティング
- Ingress・Service・Podの関係
- IngressClassとは何か
- HTTPS・TLS証明書との関係
- EKSにおけるAWS Load Balancer ControllerとALB
- ALBのTarget Typeが
instanceとipでどう変わるか - Route 53・WAF・ACM・ALBとのつながり
結論
Ingressとは、クラスター外部から受け取ったHTTP・HTTPSリクエストを、Host名やURLパスに応じてServiceへ振り分けるためのルールを定義するKubernetesリソースです。
外部からのHTTP・HTTPSリクエスト
↓
Ingress
Host名・パスで転送先を判断
┌─────┴─────┐
↓ ↓
api-service admin-service
↓ ↓
API Pod Admin Pod
ただし、Ingressリソースだけを作成しても、実際の通信は処理されません。
Ingressに書かれたルールを監視し、ロードバランサーやプロキシへ反映する Ingress Controller が必要です。
Ingress
= ルーティングルール
Ingress Controller
= ルールを読み取り、実際の通信基盤へ反映するもの
AWS EKSでAWS Load Balancer Controllerを利用する場合、Ingressを作成すると、その内容をもとにALBやTarget Groupなどが構成されます。
Serviceだけでは何が足りないのか
Serviceは、Pod群に安定した接続先を提供します。
rails-service
├── Rails Pod 1
├── Rails Pod 2
└── Rails Pod 3
しかし、ClusterIP Serviceは通常、クラスター内部から利用する接続先です。
インターネット上のブラウザからClusterIPへ直接アクセスすることはできません。
ブラウザ
↓
ClusterIP Service
× 通常は外部から直接到達できない
また、Serviceは通常、HTTPのHost名やURLパスを見て、複数のServiceから転送先を選ぶ役割を持ちません。
/apiならapi-service
/adminならadmin-service
このようなHTTP・HTTPSの入口とルーティングルールを定義するのがIngressです。
Ingressとは
Ingressは、クラスター外部から内部のServiceへHTTP・HTTPS通信を届けるためのルールを定義します。
主に次のようなルーティングを表現できます。
- Host名による振り分け
- URLパスによる振り分け
- HTTPS通信の設定
- 条件に一致しない通信のデフォルト転送先
たとえば、Host名による振り分けは次のようになります。
api.example.com
↓
api-service
admin.example.com
↓
admin-service
URLパスによる振り分けは次のようになります。
example.com/api
↓
api-service
example.com/admin
↓
admin-service
Ingressは、HTTP・HTTPS向けのルーティングを扱います。
任意のTCP・UDPポートを公開する一般的な仕組みではありません。
HTTP・HTTPS以外の通信を外部公開する場合は、NodePortやLoadBalancer型Serviceなどを利用します。
IngressリソースとIngress Controllerの違い
ここがIngressを理解するうえで最も重要です。
Ingressリソースは、ルーティングルールを書いた設定情報です。
Ingress
└── sign.example.com/apiはapi-serviceへ送る
Ingress自体が、リクエストを受信して転送するサーバーとして動くわけではありません。
Ingress ControllerがIngressを監視し、そのルールを実際の通信基盤へ反映します。
Ingress
ルーティングルールを定義
↓ 監視
Ingress Controller
ルールを読み取る
↓ 反映
ロードバランサー・プロキシ
実際に通信を処理する
代表的なIngress Controllerには、次のようなものがあります。
| Ingress Controller | 実際の通信処理の例 |
|---|---|
| AWS Load Balancer Controller | AWS ALBを構成する |
| ingress-nginx | NGINXをプロキシとして動かす |
| Traefik | Traefikをプロキシとして動かす |
どのIngress Controllerを使うかによって、利用できる設定や動作は異なります。
EKSでは誰がALBを作るのか
AWS EKSでは、AWS Load Balancer Controllerを利用できます。
AWS Load Balancer Controllerは、KubernetesのIngressなどを監視し、AWS側のロードバランサー関連リソースを構成するコントローラーです。
Ingressを作成・更新
↓
AWS Load Balancer Controllerが検知
↓
AWS APIを呼び出す
↓
ALB・Listener・Target Groupなどを構成
つまり、IngressリソースそのものがALBではありません。
Ingress
= Kubernetes上のルーティングルール
AWS Load Balancer Controller
= Ingressを監視してAWSへ反映するコントローラー
ALB
= 実際にHTTP・HTTPS通信を受けるAWSのロードバランサー
Ingress・Service・Podの関係
基本的な関係は次のようになります。
外部からのリクエスト
↓
Ingress Controllerが用意した入口
↓
Ingressのルール
↓
Service
↓
Pod
↓
Container
それぞれの役割は次のとおりです。
| 要素 | 役割 |
|---|---|
| Ingress | Host名・URLパスと転送先Serviceの対応を定義する |
| Ingress Controller | Ingressを監視し、ルールを実際の通信基盤へ反映する |
| Service | Pod群を表す安定した接続先を提供する |
| Pod | コンテナを動かす |
| Container | RailsやNginxなどのアプリケーションを実行する |
Ingressが直接Deploymentを選ぶわけではありません。
IngressはServiceを転送先として指定し、Serviceがラベルを使ってPod群を表します。
Ingress
↓ Service名を指定
Service
↓ Podラベルを選ぶ
Pod
Ingressを定義するYAML
以下は、sign.example.comへの通信をrails-serviceへ転送する基本的なIngressです。
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: rails-ingress
spec:
ingressClassName: example-controller
rules:
- host: sign.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: rails-service
port:
number: 80
このIngressは、次の対応を表します。
Host:sign.example.com
Path:/
↓
rails-service:80
YAMLの各項目
apiVersionとkind
apiVersion: networking.k8s.io/v1
kind: Ingress
| 項目 | 意味 |
|---|---|
apiVersion: networking.k8s.io/v1 |
Ingressを扱うKubernetes APIのバージョン |
kind: Ingress |
作成するリソースがIngressであることを示す |
metadata.name
metadata:
name: rails-ingress
Ingress自体の名前です。
kubectlでは、この名前を指定して状態やイベントを確認できます。
ingressClassName
spec:
ingressClassName: example-controller
どのIngress ControllerにこのIngressを処理してもらうかを指定します。
EKSでAWS Load Balancer Controllerを利用する構成では、通常albを指定します。
ingressClassName: alb
Ingress Controllerが複数存在するクラスターでは、どのControllerの設定なのかを明確にするために重要です。
rulesとhost
rules:
- host: sign.example.com
このルールを適用するHost名です。
ブラウザから送られるHTTPリクエストのHostヘッダーが条件として使われます。
Host: sign.example.com
path
paths:
- path: /
URLのどのパスにルールを適用するか指定します。
たとえば、/apiを指定すると、API向けのServiceへ振り分けられます。
pathType
pathType: Prefix
パスをどのように一致させるか指定します。
| pathType | 意味 |
|---|---|
Exact |
URLパスが完全に一致する場合に適用する |
Prefix |
URLパスの先頭が一致する場合に適用する |
ImplementationSpecific |
Ingress Controller固有の方法で判定する |
たとえば、path: /apiとpathType: Prefixを指定すると、次のようなパスが対象になります。
/api
/api/users
/api/documents/1
backend.service
backend:
service:
name: rails-service
port:
number: 80
条件に一致したリクエストを、どのServiceのどのポートへ送るか指定します。
ここで指定する80は、Serviceのspec.ports[].portです。
Ingress
↓ rails-service:80
Service
↓ targetPort:3000
Pod内のRails・Puma
Ingressから、PodのcontainerPort: 3000を直接指定するわけではありません。
Host名によるルーティング
1つの入口から、Host名によって異なるServiceへ振り分けられます。
spec:
rules:
- host: api.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: api-service
port:
number: 80
- host: admin.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: admin-service
port:
number: 80
api.example.com
↓
api-service
admin.example.com
↓
admin-service
URLパスによるルーティング
同じHost名でも、URLパスによって転送先を変えられます。
spec:
rules:
- host: example.com
http:
paths:
- path: /api
pathType: Prefix
backend:
service:
name: api-service
port:
number: 80
- path: /admin
pathType: Prefix
backend:
service:
name: admin-service
port:
number: 80
example.com/api
↓
api-service
example.com/admin
↓
admin-service
defaultBackend
Host名やURLパスのルールに一致しないリクエストの転送先として、defaultBackendを指定できます。
spec:
defaultBackend:
service:
name: default-service
port:
number: 80
どのルールにも一致しない
↓
default-service
具体的なデフォルト動作はIngress Controllerによって異なる場合があります。
Ingressを作成する
YAMLをingress.yamlとして保存した場合、次のコマンドで適用できます。
kubectl apply -f ingress.yaml
Ingressの一覧を確認します。
kubectl get ingress
短縮形も使用できます。
kubectl get ing
Ingressの詳細・ルール・イベントを確認します。
kubectl describe ingress rails-ingress
IngressClassを確認します。
kubectl get ingressclass
AWS Load Balancer Controllerなど、Controller自体のPodを確認する場合は、導入先のNamespaceを指定します。
kubectl get pods -n kube-system
EKSとALBで使うIngressの例
以下は、AWS Load Balancer ControllerでALBを構成するIngressの例です。
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: rails-ingress
annotations:
alb.ingress.kubernetes.io/scheme: internet-facing
alb.ingress.kubernetes.io/target-type: ip
alb.ingress.kubernetes.io/listen-ports: '[{"HTTPS":443}]'
alb.ingress.kubernetes.io/certificate-arn: arn:aws:acm:ap-northeast-1:123456789012:certificate/example
alb.ingress.kubernetes.io/healthcheck-path: /health
spec:
ingressClassName: alb
rules:
- host: sign.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: rails-service
port:
number: 80
このYAMLでは、標準のIngressルールに加え、AWS固有の設定をannotationへ記述しています。
| annotation | 意味 |
|---|---|
scheme: internet-facing |
インターネット向けALBを構成する |
target-type: ip |
Target GroupへPod IPを登録する |
listen-ports |
ALBのHTTPS 443番Listenerを設定する |
certificate-arn |
ACMで管理するTLS証明書をALBへ設定する |
healthcheck-path |
Target Groupのヘルスチェックパスを設定する |
annotationはKubernetes標準のIngress設定ではありません。
AWS Load Balancer Controllerが読み取る、AWS固有の追加設定です。
ALB作成までの流れ
Ingressを適用してからALBが構成されるまでの流れは、次のようになります。
1. kubectl apply -f ingress.yaml
↓
2. Kubernetes APIへIngressを保存
↓
3. AWS Load Balancer ControllerがIngressを検知
↓
4. ControllerがAWS APIを呼び出す
↓
5. ALB・Listener・Rule・Target Groupなどを構成
↓
6. IngressのADDRESSへALBの接続先を反映
ALBが作成されるまで、少し時間がかかる場合があります。
次のコマンドで状態を確認できます。
kubectl get ingress rails-ingress
AWS Load Balancer Controllerで問題が起きている場合は、IngressのイベントやControllerのログも確認します。
kubectl describe ingress rails-ingress
Route 53からPodまでの全体像
EKSとALBを使う構成の一例は、次のようになります。
ブラウザ
↓ sign.example.comへアクセス
Route 53
↓ ALBの接続先を返す
ALB
├── ACMのTLS証明書を提示
├── HTTPSを終端・復号
└── Listener Ruleで転送先を判断
↓
Target Group
↓
Kubernetes側のバックエンド
↓
Rails Pod
↓
Puma・Rails
IngressにはHost名・パスとServiceの対応を書きます。
AWS Load Balancer Controllerは、その情報をALBのListener RuleやTarget Groupなどへ反映します。
そのため、実際のリクエストが毎回「Ingressというサーバー」を通過するわけではありません。
AWS Load Balancer Controllerを使う構成では、IngressはALBを構成するための宣言的なルールです。
WAF・ACM・ALB・Ingressの関係
それぞれの役割を整理すると、次のようになります。
| 要素 | 役割 |
|---|---|
| Route 53 | ドメイン名からALBの接続先を案内する |
| AWS WAF | Web ACLのルールでHTTP・HTTPSリクエストを検査する |
| ACM | ALBへ設定するTLS証明書を発行・管理する |
| ALB | HTTP・HTTPS通信を受信し、Listener Ruleで転送する |
| Ingress | Host名・URLパスとServiceの対応をKubernetes上で定義する |
| AWS Load Balancer Controller | Ingressを読み、ALBなどのAWSリソースへ反映する |
| Service | Pod群を安定したバックエンドとして表す |
| Pod | Railsなどのコンテナを動かす |
流れを簡略化すると、次のようになります。
Route 53:どこへ接続するか
↓
ALB
├── WAF:このリクエストを通してよいか
├── ACMの証明書:正規の接続先であることを示す
└── Listener Rule:どのTarget Groupへ送るか
↓
Target Group
↓
Serviceが表すバックエンド
↓
Pod:アプリケーションを実行する
Ingress
└── AWS Load Balancer Controllerが上記のALB設定へ反映する宣言
Ingressは通信経路上に独立した機器として必ず存在するのではなく、ControllerによってALBなどの設定へ変換されるルールです。
TLSとIngressの関係
一般的なKubernetes Ingressでは、TLS証明書をSecretとして設定する方法があります。
spec:
tls:
- hosts:
- sign.example.com
secretName: sign-tls
この方式は、Ingress Controller自身がTLS終端を担当する構成などで使われます。
一方、EKSでALBがTLS終端を担当する場合は、ACMの証明書をALBへ設定できます。
ブラウザ
↓ HTTPS
ALB
├── ACMの証明書を提示
└── TLS終端
↓ HTTPまたはHTTPS
バックエンド
AWS Load Balancer Controllerでは、annotationにACM証明書のARNを指定できます。
alb.ingress.kubernetes.io/certificate-arn: arn:aws:acm:ap-northeast-1:123456789012:certificate/example
どこでTLSを終端するかは構成によって異なります。
ALBで復号したあとにバックエンドへHTTPで送る構成もあれば、バックエンドまでHTTPSで暗号化する構成もあります。
Target Typeのinstanceとip
AWS Load Balancer Controllerでは、ALBのTarget Groupへ何を登録するかをTarget Typeで指定できます。
主にinstanceとipがあります。
instance
instanceでは、EC2 NodeがTarget Groupへ登録されます。
ALB
↓
Target Group
↓ EC2 NodeのNodePort
Node
↓
Service
↓
Pod
この構成では、ServiceはNodePort型である必要があります。
ip
ipでは、PodのIPアドレスがTarget Groupへ登録されます。
ALB
↓
Target Group
↓ Pod IP
Pod
NodePortを経由せず、ALBからPodへ直接ルーティングできます。
IngressのbackendにはServiceを指定しますが、実際のデータ通信ではClusterIPを経由せず、ControllerがServiceのバックエンドPodをTarget Groupへ登録する構成になります。
alb.ingress.kubernetes.io/target-type: ip
違いをまとめると、次のようになります。
| Target Type | Target Groupへ登録するもの | 主な経路 |
|---|---|---|
instance |
EC2 Node | ALB → NodePort → Pod |
ip |
Pod IP | ALB → Pod |
実際の構成図を読むときは、Target GroupにEC2 NodeとPod IPのどちらが登録されているか確認すると、経路が見えやすくなります。
IngressとLoadBalancer Serviceの違い
IngressとLoadBalancer型Serviceは、どちらも外部公開に使えますが、得意な通信と役割が異なります。
| 比較 | Ingress | LoadBalancer Service |
|---|---|---|
| 主な対象 | HTTP・HTTPS | TCP・UDPを含むService通信 |
| ルーティング | Host名・URLパスを利用できる | 基本的にService単位 |
| 転送先 | 複数のServiceをまとめられる | 1つのService |
| EKSでの例 | ALB | NLB |
たとえば、複数のWebサービスを1つのALBで公開したい場合は、Ingressが適しています。
1つのALB
├── /api → api-service
├── /admin → admin-service
└── / → front-service
一方、HTTPのHost名やパスではなく、TCP・UDPレベルで1つのServiceを外部公開したい場合は、LoadBalancer型Serviceが適する場合があります。
ALBはIngress Controllerなのか
ALB自体はIngress Controllerではありません。
AWS Load Balancer Controller
= Kubernetes内でIngressを監視するController
ALB
= Controllerによって構成され、実際の通信を処理するAWSリソース
名前が似ているため、次の3つを分けて覚えることが重要です。
| 要素 | 実体 |
|---|---|
| Ingress | Kubernetesリソース |
| AWS Load Balancer Controller | Kubernetes上で動くController |
| ALB | AWS上で動くロードバランサー |
Ingressは外部からの入口そのものなのか
Ingressは、入口のルールを表すKubernetesリソースです。
実際の入口は、選択したIngress Controllerの実装によって異なります。
AWS Load Balancer Controller
→ ALBが実際の入口
ingress-nginx
→ NGINXのPodやServiceが実際の入口
したがって、構成図で「Ingress」と書かれていても、実際に何が通信を受信しているかはControllerを確認する必要があります。
Ingressで問題が起きたときの確認順序
Ingress経由でアクセスできない場合は、次の順番で確認すると関係を追いやすくなります。
1. Ingressが存在するか
↓
2. ingressClassNameは正しいか
↓
3. Ingress Controllerが動いているか
↓
4. IngressのHost・Pathルールは正しいか
↓
5. backendのService名・portは正しいか
↓
6. ServiceにEndpointSliceが存在するか
↓
7. PodがReadyか
↓
8. アプリケーションが対象ポートで待ち受けているか
EKSとALBの場合は、さらに次も確認します。
9. ALBが作成されているか
10. Listener・Ruleは正しいか
11. Target GroupにTargetが登録されているか
12. TargetはHealthyか
13. Security Groupで通信が許可されているか
14. Route 53が正しいALBを指しているか
15. ACM証明書のドメインと期限は正しいか
16. WAFでBLOCKされていないか
Kubernetes側で使用する主なコマンドは次のとおりです。
kubectl get ingress
kubectl describe ingress rails-ingress
kubectl get ingressclass
kubectl get svc
kubectl describe svc rails-service
kubectl get endpointslices
kubectl get pods
よくある勘違い
Ingressを作れば、それだけで通信できる?
できません。
Ingressに書いたルールを実現するIngress Controllerが必要です。
Ingressはロードバランサーそのもの?
違います。
IngressはKubernetes上のルーティングルールです。
AWS Load Balancer Controllerを使う場合、ControllerがIngressをもとにALBを構成します。
ALBがIngress Controller?
違います。
ALBは実際に通信を処理するAWSリソースです。
Ingress Controllerは、Ingressを監視してALBへ設定を反映するAWS Load Balancer Controllerです。
Ingressは直接Podを選ぶ?
基本的には選びません。
IngressのbackendにはService名とServiceのポートを指定します。
ただし、EKSのtarget-type: ipでは、実際のALB Target GroupにPod IPが登録され、データ通信がPodへ直接届きます。
IngressがPodを作成する?
作成しません。
Podを作成・維持するのはDeploymentやReplicaSetです。
ServiceがあればIngressは不要?
用途によります。
クラスター内部だけで利用するServiceなら、Ingressは不要です。
外部からHTTP・HTTPSでアクセスし、Host名やパスでルーティングする場合にIngressを利用します。
IngressはTCPやUDPも自由に振り分けられる?
標準のIngressは、HTTP・HTTPSのルーティングを対象としています。
任意のTCP・UDP通信を公開する場合は、LoadBalancer型Serviceなどを検討します。
Ingressを使えばHTTPSになる?
Ingressを作成しただけで、自動的にHTTPSになるとは限りません。
TLS証明書、HTTPS Listener、Ingress Controller固有の設定などが必要です。
Ingressが非推奨で、すぐ使えなくなる?
その理解は正確ではありません。
Kubernetesは新規機能としてGateway APIを推奨しており、Ingress APIの仕様は凍結されています。
ただし、Ingress APIは安定版であり、Kubernetesから削除する予定はないと説明されています。
既存環境では現在も広く利用されています。
まとめ
Ingressについて、重要な点をまとめます。
- Ingressは、HTTP・HTTPSのルーティングルールを定義するKubernetesリソース
- Host名やURLパスによって転送先Serviceを変更できる
- Ingressだけを作成しても通信は処理されない
- Ingressのルールを実現するIngress Controllerが必要
- Ingress Controllerの実装によって実際の入口は異なる
- EKSではAWS Load Balancer ControllerがIngressを監視し、ALBを構成できる
- ALBはIngress Controllerではなく、実際に通信を処理するAWSリソース
- IngressのbackendにはService名とServiceの
portを指定する - Serviceがラベルを使ってPod群を表す
- AWS固有の設定はannotationに記述する
- ALBのTLS証明書にはACMを利用できる
-
target-type: instanceではEC2 NodeとNodePortを経由する -
target-type: ipではPod IPがTarget Groupへ登録される - Ingressは主にHTTP・HTTPS、LoadBalancer ServiceはTCP・UDPを含むService公開に使う
- Route 53・WAF・ACM・ALB・Ingress・Service・Podはそれぞれ別の役割を持つ
- Ingress APIの仕様は凍結されているが、削除予定という意味ではない
最も簡単に覚えるなら、次の関係です。
Ingress
= どのHTTP・HTTPSリクエストを、どのServiceへ送るかというルール
Ingress Controller
= Ingressのルールを実際の通信基盤へ反映する
Service
= 転送先となるPod群を表す
EKSとALBを含めると、次のようになります。
ブラウザ
↓
Route 53
↓
ALB
↓
Target Group
↓
Serviceが表すPod群
↓
Rails・Puma
AWS Load Balancer Controller
└── Ingressを監視し、ALBの構成へ反映する
Serviceを理解したあとにIngressを学ぶと、Kubernetesが「外部から受けたHTTP・HTTPSリクエストを、目的のアプリケーションへどのように届けるのか」が見えやすくなります。