Ingress

FEATURE STATE: Kubernetes v1.19 [stable]

クラスター内のServiceに対する外部からのアクセス(主にHTTP)を管理するAPIオブジェクトです。

Ingressは負荷分散、SSL終端、名前ベースの仮想ホスティングの機能を提供します。

用語

簡単のために、このガイドでは次の用語を定義します。

  • ノード: Kubernetes内のワーカーマシンで、クラスターの一部です。
  • クラスター: Kubernetesによって管理されているコンテナ化されたアプリケーションを実行させるノードの集合です。この例や、多くのKubernetesによるデプロイでは、クラスター内のノードはインターネットに公開されていません。
  • エッジルーター: クラスターでファイアウォールのポリシーを強制するルーターです。クラウドプロバイダーが管理するゲートウェイや、物理的なハードウェアの一部である場合もあります。
  • クラスターネットワーク: 物理的または論理的な繋がりの集合で、Kubernetesのネットワークモデルによって、クラスター内でのコミュニケーションを司るものです。
  • Service: ラベルセレクターを使ったPodの集合を特定するKubernetes Serviceです。特に指定がない限り、Serviceはクラスターネットワーク内でのみ疎通可能な仮想IPを持つものとして扱われます。

Ingressとは何か

Ingressはクラスター外からクラスター内ServiceへのHTTPとHTTPSのルートを公開します。トラフィックのルーティングはIngressリソース上で定義されるルールによって制御されます。

全てのトラフィックを単一のServiceに送る単純なIngressの例を示します。

ingress-diagram

図. Ingress

IngressはServiceに対して、外部疎通できるURL、負荷分散トラフィック、SSL/TLS終端の機能や、名前ベースの仮想ホスティングを提供するように設定できます。Ingressコントローラーは通常はロードバランサーを使用してIngressの機能を実現しますが、エッジルーターや、追加のフロントエンドを構成してトラフィックの処理を支援することもできます。

Ingressは任意のポートやプロトコルを公開しません。HTTPやHTTPS以外のServiceをインターネットに公開する場合、Service.Type=NodePortService.Type=LoadBalancerのServiceタイプを一般的には使用します。

Ingressを使用する上での前提条件

Ingressを提供するためにはIngressコントローラーが必要です。Ingressリソースを作成するのみでは何の効果もありません。

ingress-nginxのようなIngressコントローラーのデプロイが必要な場合があります。いくつかのIngressコントローラーの中から選択してください。

理想的には、全てのIngressコントローラーはリファレンスの仕様を満たすはずです。しかし実際には、各Ingressコントローラーは微妙に異なる動作をします。

Ingressリソース

Ingressリソースの最小構成の例は以下のとおりです。

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: minimal-ingress
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: /
spec:
  ingressClassName: nginx-example
  rules:
  - http:
      paths:
      - path: /testpath
        pathType: Prefix
        backend:
          service:
            name: test
            port:
              number: 80

IngressにはapiVersionkindmetadataspecフィールドが必要です。Ingressオブジェクトの名前は、有効なDNSサブドメイン名である必要があります。設定ファイルに関する一般的な情報は、アプリケーションのデプロイコンテナの設定リソースの管理を参照してください。Ingressでは、Ingressコントローラーに依存しているいくつかのオプションの設定をするためにアノテーションを一般的に使用します。例としては、rewrite-targetアノテーションなどがあります。Ingressコントローラーの種類が異なれば、サポートするアノテーションも異なります。サポートされているアノテーションについて学ぶためには、使用するIngressコントローラーのドキュメントを確認してください。

Ingress Specは、ロードバランサーやプロキシーサーバーを設定するために必要な全ての情報を持っています。最も重要なものとして、外部からくる全てのリクエストに対して一致したルールのリストを含みます。IngressリソースはHTTP(S)トラフィックに対してのルールのみサポートしています。

ingressClassNameが省略された場合、デフォルトのIngressClassを定義する必要があります。

デフォルトのIngressClassを定義しなくても動作するIngressコントローラーがいくつかあります。例えば、Ingress-NGINXコントローラーはフラグ --watch-ingress-without-classで設定できます。ただし、下記のようにデフォルトのIngressClassを指定することを推奨します

Ingressのルール

各HTTPルールは以下の情報を含みます。

  • オプションで設定可能なホスト名。上記のリソースの例では、ホスト名が指定されていないので、そのルールは指定されたIPアドレスを経由する全てのインバウンドHTTPトラフィックに適用されます。ホスト名が指定されていると(例: foo.bar.com)、そのルールは指定されたホストに対して適用されます。
  • パスのリスト(例: /testpath)。各パスにはservice.nameservice.port.nameまたはservice.port.numberで定義されるバックエンドが関連づけられます。ロードバランサーがトラフィックを関連づけられたServiceに転送するために、外部からくるリクエストのホスト名とパスが条件と一致させる必要があります。
  • バックエンドはServiceドキュメントに書かれているようなService名とポート名の組み合わせ、またはCRDによるカスタムリソースバックエンドです。Ingressで設定されたホスト名とパスのルールに一致するHTTP(とHTTPS)のリクエストは、リスト内のバックエンドに対して送信されます。

Ingressコントローラーでは、defaultBackendが設定されていることがあります。これはSpec内で指定されているパスに一致しないようなリクエストのためのバックエンドです。

デフォルトのバックエンド

ルールが設定されていないIngressは、全てのトラフィックを単一のデフォルトのバックエンドに転送します。.spec.defaultBackendはその場合にリクエストを処理するバックエンドになります。defaultBackendは、Ingressコントローラーのオプション設定であり、Ingressリソースでは指定されていません。.spec.rulesを設定しない場合、.spec.defaultBackendの設定は必須です。defaultBackendが設定されていない場合、どのルールにもマッチしないリクエストの処理は、Ingressコントローラーに任されます(このケースをどう処理するかは、お使いのIngressコントローラーのドキュメントを参照してください)。

HTTPリクエストがIngressオブジェクトのホスト名とパスの条件に1つも一致しない時、そのトラフィックはデフォルトのバックエンドに転送されます。

リソースバックエンド

ResourceバックエンドはIngressオブジェクトと同じnamespaceにある他のKubernetesリソースを指すObjectRefです。 ResourceはServiceの設定とは排他であるため、両方を指定するとバリデーションに失敗します。 Resourceバックエンドの一般的な用途は、静的なアセットが入ったオブジェクトストレージバックエンドにデータを導入することです。

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: ingress-resource-backend
spec:
  defaultBackend:
    resource:
      apiGroup: k8s.example.com
      kind: StorageBucket
      name: static-assets
  rules:
    - http:
        paths:
          - path: /icons
            pathType: ImplementationSpecific
            backend:
              resource:
                apiGroup: k8s.example.com
                kind: StorageBucket
                name: icon-assets

上記のIngressを作成した後に、次のコマンドで参照することができます。

kubectl describe ingress ingress-resource-backend
Name:             ingress-resource-backend
Namespace:        default
Address:
Default backend:  APIGroup: k8s.example.com, Kind: StorageBucket, Name: static-assets
Rules:
  Host        Path  Backends
  ----        ----  --------
  *
              /icons   APIGroup: k8s.example.com, Kind: StorageBucket, Name: icon-assets
Annotations:  <none>
Events:       <none>

パスのタイプ

Ingressのそれぞれのパスは対応するパスのタイプを持ちます。pathTypeが明示的に指定されていないパスはバリデーションに通りません。サポートされているパスのタイプは3種類あります。

  • ImplementationSpecific(実装に特有): このパスタイプでは、パスとの一致はIngressClassに依存します。Ingressの実装はこれを独立したpathTypeと扱うことも、PrefixExactと同一のパスタイプと扱うこともできます。

  • Exact: 大文字小文字を区別して完全に一致するURLパスと一致します。

  • Prefix: /で分割されたURLと前方一致で一致します。大文字小文字は区別され、パスの要素対要素で比較されます。パス要素は/で分割されたパスの中のラベルのリストを参照します。リクエストがパス p に一致するのは、Ingressのパス p がリクエストパス p と要素単位で前方一致する場合です。

タイプパスリクエストパス一致するか
Prefix/(全てのパス)はい
Exact/foo/fooはい
Exact/foo/barいいえ
Exact/foo/foo/いいえ
Exact/foo//fooいいえ
Prefix/foo/foo, /foo/はい
Prefix/foo//foo, /foo/はい
Prefix/aaa/bb/aaa/bbbいいえ
Prefix/aaa/bbb/aaa/bbbはい
Prefix/aaa/bbb//aaa/bbbはい、末尾のスラッシュは無視
Prefix/aaa/bbb/aaa/bbb/はい、末尾のスラッシュと一致
Prefix/aaa/bbb/aaa/bbb/cccはい、パスの一部と一致
Prefix/aaa/bbb/aaa/bbbxyzいいえ、接頭辞と一致しない
Prefix/, /aaa/aaa/cccはい、接頭辞/aaaと一致
Prefix/, /aaa, /aaa/bbb/aaa/bbbはい、接頭辞/aaa/bbbと一致
Prefix/, /aaa, /aaa/bbb/cccはい、接頭辞/と一致
Prefix/aaa/cccいいえ、デフォルトバックエンドを使用
Mixed/foo (Prefix), /foo (Exact)/fooはい、Exactが優先

複数のパスとの一致

リクエストがIngressの複数のパスと一致することがあります。そのような場合は、最も長くパスが一致したものが優先されます。2つのパスが同等に一致した場合は、完全一致が前方一致よりも優先されます。

ホスト名のワイルドカード

ホストは正確に一致する(例えばfoo.bar.com)かワイルドカード(例えば*.foo.com)とすることができます。 正確な一致ではHTTPヘッダーのhosthostフィールドと一致することが必要です。 ワイルドカードによる一致では、HTTPヘッダーのhostがワイルドカードルールに沿って後方一致することが必要です。

HostHostヘッダー一致するか
*.foo.combar.foo.com共通の接尾辞により一致
*.foo.combaz.bar.foo.com一致しない。ワイルドカードは単一のDNSラベルのみを対象とする
*.foo.comfoo.com一致しない。ワイルドカードは単一のDNSラベルのみを対象とする
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: ingress-wildcard-host
spec:
  rules:
  - host: "foo.bar.com"
    http:
      paths:
      - pathType: Prefix
        path: "/bar"
        backend:
          service:
            name: service1
            port:
              number: 80
  - host: "*.foo.com"
    http:
      paths:
      - pathType: Prefix
        path: "/foo"
        backend:
          service:
            name: service2
            port:
              number: 80

Ingress Class

Ingressは異なったコントローラーで実装されうるため、しばしば異なった設定を必要とします。 各Ingressはクラス、つまりIngressClassリソースへの参照を指定する必要があります。IngressClassリソースには、このクラスを実装するコントローラーの名前などの追加設定が含まれています。

apiVersion: networking.k8s.io/v1
kind: IngressClass
metadata:
  name: external-lb
spec:
  controller: example.com/ingress-controller
  parameters:
    apiGroup: k8s.example.com
    kind: IngressParameters
    name: external-lb

IngressClassの.spec.parametersフィールドを使って、そのIngressClassに関連する設定を持っている別のリソースを参照することができます。

使用するパラメーターの種類は、IngressClassの.spec.controllerフィールドで指定したIngressコントローラーに依存します。

IngressClassスコープ

Ingressコントローラーによっては、クラスター全体で設定したパラメーターを使用できる場合もあれば、1つのNamespaceに対してのみ設定したパラメーターを使用できる場合もあります。

IngressClassパラメーターのデフォルトのスコープは、クラスター全体です。

.spec.parametersフィールドを設定して.spec.parameters.scopeフィールドを設定しなかった場合、または.spec.parameters.scopeClusterに設定した場合、IngressClassはクラスタースコープのリソースを参照します。 パラーメーターのkind(およびapiGroup)はクラスタースコープのAPI(カスタムリソースの場合もあり)を指し、パラメーターのnameはそのAPIの特定のクラスタースコープのリソースを特定します。

例えば:

---
apiVersion: networking.k8s.io/v1
kind: IngressClass
metadata:
  name: external-lb-1
spec:
  controller: example.com/ingress-controller
  parameters:
    # このIngressClassのパラメーターは「external-config-1」という名前の
    # ClusterIngressParameter(APIグループk8s.example.net)で指定されています。この定義は、Kubernetesに
    # クラスタースコープのパラメーターリソースを探すように指示しています。
    scope: Cluster
    apiGroup: k8s.example.net
    kind: ClusterIngressParameter
    name: external-config-1

FEATURE STATE: Kubernetes v1.23 [stable]

.spec.parametersフィールドを設定して.spec.parameters.scopeフィールドをNamespaceに設定した場合、IngressClassはNamespaceスコープのリソースを参照します。また.spec.parameters内のnamespaceフィールドには、使用するパラメーターが含まれているNamespaceを設定する必要があります。

パラメーターのkind(およびapiGroup)はNamespaceスコープのAPI(例えば:ConfigMap)を指し、パラメーターのnamenamespaceで指定したNamespace内の特定のリソースを特定します。

Namespaceスコープのパラメーターはクラスターオペレーターがワークロードに使用される設定(例えば:ロードバランサー設定、APIゲートウェイ定義)に対する制御を委譲するのに役立ちます。クラスタースコープパラメーターを使用した場合は以下のいずれかになります:

  • クラスターオペレーターチームは、新しい設定変更が適用されるたびに、別のチームの変更内容を承認する必要があります。
  • クラスターオペレーターは、アプリケーションチームがクラスタースコープのパラメーターリソースに変更を加えることができるように、RBACのRoleやRoleBindingといった、特定のアクセス制御を定義する必要があります。

IngressClass API自体は常にクラスタースコープです。

以下はNamespaceスコープのパラメーターを参照しているIngressClassの例です:

---
apiVersion: networking.k8s.io/v1
kind: IngressClass
metadata:
  name: external-lb-2
spec:
  controller: example.com/ingress-controller
  parameters:
    # このIngressClassのパラメーターは「external-config」という名前の
    # IngressParameter(APIグループk8s.example.com)で指定されています。
    # このリソースは「external-configuration」というNamespaceにあります。
    scope: Namespace
    apiGroup: k8s.example.com
    kind: IngressParameter
    namespace: external-configuration
    name: external-config

非推奨のアノテーション

Kubernetes 1.18でIngressClassリソースとingressClassNameフィールドが追加される前は、Ingressの種別はIngressのkubernetes.io/ingress.classアノテーションにより指定されていました。 このアノテーションは正式に定義されたことはありませんが、Ingressコントローラーに広くサポートされています。

Ingressの新しいingressClassNameフィールドはこのアノテーションを置き換えるものですが、完全に等価ではありません。 アノテーションは一般にIngressを実装すべきIngressのコントローラーの名称を示していましたが、フィールドはIngressClassリソースへの参照であり、Ingressのコントローラーの名称を含む追加のIngressの設定情報を含んでいます。

デフォルトのIngressClass

特定のIngressClassをクラスターのデフォルトとしてマークすることができます。 IngressClassリソースのingressclass.kubernetes.io/is-default-classアノテーションをtrueに設定すると、ingressClassNameフィールドが指定されないIngressにはこのデフォルトIngressClassが割り当てられるようになります。

Ingressコントローラーの中には、デフォルトのIngressClassを定義しなくても動作するものがあります。 例えば、Ingress-NGINXコントローラーはフラグ --watch-ingress-without-classで設定することができます。ただし、デフォルトIngressClassを指定することを推奨します:

apiVersion: networking.k8s.io/v1
kind: IngressClass
metadata:
  labels:
    app.kubernetes.io/component: controller
  name: nginx-example
  annotations:
    ingressclass.kubernetes.io/is-default-class: "true"
spec:
  controller: k8s.io/ingress-nginx

Ingressのタイプ

単一ServiceのIngress

Kubernetesには、単一のServiceを公開できるようにする既存の概念があります(Ingressの代替案を参照してください)。ルールなしでデフォルトのバックエンド を指定することにより、Ingressでこれを実現することもできます。

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: test-ingress
spec:
  defaultBackend:
    service:
      name: test
      port:
        number: 80

kubectl apply -fを実行してIngressを作成すると、その作成したIngressの状態を確認することができます。

kubectl get ingress test-ingress
NAME           CLASS         HOSTS   ADDRESS         PORTS   AGE
test-ingress   external-lb   *       203.0.113.123   80      59s

203.0.113.123はIngressコントローラーによって割り当てられたIPで、作成したIngressを利用するためのものです。

リクエストのシンプルなルーティング

ファンアウト設定では単一のIPアドレスのトラフィックを、リクエストされたHTTP URIに基づいて1つ以上のServiceに転送します。Ingressによってロードバランサーの数を少なくすることができます。例えば、以下のように設定します。

ingress-fanout-diagram

図. Ingressファンアウト

Ingressを以下のように設定します。

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: simple-fanout-example
spec:
  rules:
  - host: foo.bar.com
    http:
      paths:
      - path: /foo
        pathType: Prefix
        backend:
          service:
            name: service1
            port:
              number: 4200
      - path: /bar
        pathType: Prefix
        backend:
          service:
            name: service2
            port:
              number: 8080

Ingressをkubectl apply -fによって作成したとき:

kubectl describe ingress simple-fanout-example
Name:             simple-fanout-example
Namespace:        default
Address:          178.91.123.132
Default backend:  default-http-backend:80 (10.8.2.3:8080)
Rules:
  Host         Path  Backends
  ----         ----  --------
  foo.bar.com
               /foo   service1:4200 (10.8.0.90:4200)
               /bar   service2:8080 (10.8.0.91:8080)
Events:
  Type     Reason  Age                From                     Message
  ----     ------  ----               ----                     -------
  Normal   ADD     22s                loadbalancer-controller  default/test

IngressコントローラーはService(service1service2)が存在する限り、Ingressの条件を満たす実装固有のロードバランサーを構築します。 構築が完了すると、ADDRESSフィールドでロードバランサーのアドレスを確認できます。

名前ベースのバーチャルホスティング

名前ベースのバーチャルホストは、HTTPトラフィックを同一のIPアドレスの複数のホスト名に転送することをサポートしています。

ingress-namebase-diagram

図. Ingress名前ベースのバーチャルホスティング

以下のIngress設定は、ロードバランサーに対して、Hostヘッダーに基づいてリクエストを転送するように指示するものです。

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: name-virtual-host-ingress
spec:
  rules:
  - host: foo.bar.com
    http:
      paths:
      - pathType: Prefix
        path: "/"
        backend:
          service:
            name: service1
            port:
              number: 80
  - host: bar.foo.com
    http:
      paths:
      - pathType: Prefix
        path: "/"
        backend:
          service:
            name: service2
            port:
              number: 80

rules項目でのホストの設定がないIngressを作成すると、IngressコントローラーのIPアドレスに対するwebトラフィックは、要求されている名前ベースのバーチャルホストなしにマッチさせることができます。

例えば、以下のIngressはfirst.bar.comに対するトラフィックをservice1へ、second.foo.comに対するトラフィックをservice2へ、リクエストにおいてホスト名が指定されていない(リクエストヘッダーがないことを意味します)トラフィックはservice3へ転送します。

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: name-virtual-host-ingress-no-third-host
spec:
  rules:
  - host: first.bar.com
    http:
      paths:
      - pathType: Prefix
        path: "/"
        backend:
          service:
            name: service1
            port:
              number: 80
  - host: second.bar.com
    http:
      paths:
      - pathType: Prefix
        path: "/"
        backend:
          service:
            name: service2
            port:
              number: 80
  - http:
      paths:
      - pathType: Prefix
        path: "/"
        backend:
          service:
            name: service3
            port:
              number: 80

TLS

TLSの秘密鍵と証明書を含んだSecretを指定することにより、Ingressをセキュアにできます。Ingressは単一のTLSポートである443番ポートのみサポートし、IngressでTLS終端を行うことを想定しています。IngressからServiceやPodへのトラフィックは平文です。IngressのTLS設定のセクションで異なるホストを指定すると、それらのホストはSNI TLSエクステンション(IngressコントローラーがSNIをサポートしている場合)を介して指定されたホスト名に対し、同じポート上で多重化されます。TLSのSecretはtls.crttls.keyというキーを含む必要があり、TLSを使用するための証明書と秘密鍵を含む値となります。以下がその例です。

apiVersion: v1
kind: Secret
metadata:
  name: testsecret-tls
  namespace: default
data:
  tls.crt: base64 encoded cert
  tls.key: base64 encoded key
type: kubernetes.io/tls

IngressでこのSecretを参照すると、クライアントとロードバランサー間の通信にTLSを使用するようIngressコントローラーに指示することになります。作成したTLS Secretは、https-example.foo.comの完全修飾ドメイン名(FQDN)とも呼ばれる共通名(CN)を含む証明書から作成したものであることを確認する必要があります。

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: tls-example-ingress
spec:
  tls:
  - hosts:
      - https-example.foo.com
    secretName: testsecret-tls
  rules:
  - host: https-example.foo.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: service1
            port:
              number: 80

負荷分散

Ingressコントローラーは、負荷分散アルゴリズムやバックエンドの重みスキームなど、すべてのIngressに適用されるいくつかの負荷分散ポリシーの設定とともにブートストラップされます。発展した負荷分散のコンセプト(例: セッションの永続化、動的重み付けなど)はIngressによってサポートされていません。代わりに、それらの機能はService用のロードバランサーを介して利用できます。

ヘルスチェックの機能はIngressによって直接には公開されていませんが、Kubernetesにおいて、同等の機能を提供するReadiness Probeのようなコンセプトが存在することは注目に値します。コントローラーがどのようにヘルスチェックを行うかについては、コントローラーのドキュメントを参照してください(例えばnginx、またはGCE)。

Ingressの更新

リソースを編集することで、既存のIngressに対して新しいホストを追加することができます。

kubectl describe ingress test
Name:             test
Namespace:        default
Address:          178.91.123.132
Default backend:  default-http-backend:80 (10.8.2.3:8080)
Rules:
  Host         Path  Backends
  ----         ----  --------
  foo.bar.com
               /foo   service1:80 (10.8.0.90:80)
Annotations:
  nginx.ingress.kubernetes.io/rewrite-target:  /
Events:
  Type     Reason  Age                From                     Message
  ----     ------  ----               ----                     -------
  Normal   ADD     35s                loadbalancer-controller  default/test
kubectl edit ingress test

このコマンドを実行すると既存の設定をYAMLフォーマットで編集するエディターが表示されます。新しいホストを追加するには、リソースを修正してください。

spec:
  rules:
  - host: foo.bar.com
    http:
      paths:
      - backend:
          service:
            name: service1
            port:
              number: 80
        path: /foo
        pathType: Prefix
  - host: bar.baz.com
    http:
      paths:
      - backend:
          service:
            name: service2
            port:
              number: 80
        path: /foo
        pathType: Prefix
..

変更を保存した後、kubectlはAPIサーバー内のリソースを更新し、Ingressコントローラーに対してロードバランサーの再設定を指示します。

変更内容を確認してください。

kubectl describe ingress test
Name:             test
Namespace:        default
Address:          178.91.123.132
Default backend:  default-http-backend:80 (10.8.2.3:8080)
Rules:
  Host         Path  Backends
  ----         ----  --------
  foo.bar.com
               /foo   service1:80 (10.8.0.90:80)
  bar.baz.com
               /foo   service2:80 (10.8.0.91:80)
Annotations:
  nginx.ingress.kubernetes.io/rewrite-target:  /
Events:
  Type     Reason  Age                From                     Message
  ----     ------  ----               ----                     -------
  Normal   ADD     45s                loadbalancer-controller  default/test

修正されたIngressのYAMLファイルに対してkubectl replace -fを実行することで、同様の結果を得られます。

アベイラビリティーゾーンをまたいだ障害について

障害のあるドメインをまたいでトラフィックを分散する手法は、クラウドプロバイダーによって異なります。詳細に関して、Ingress コントローラーのドキュメントを参照してください。

Ingressの代替案

Ingressリソースを直接含まずにサービスを公開する方法は複数あります。

次の項目