0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Ingressとは何か?

0
Posted at

はじめに

前回は、増減・再作成される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リクエストを、目的のアプリケーションへどのように届けるのか」が見えやすくなります。

参考資料

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?