0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【Kubernetes】Service Ingress is 何

Posted at

はじめに

本記事ではKubernetesリソースのService、Ingressについて解説します。
また、AWS LoadBalancer Controllerについても解説します。

全体像

はじめに各リソースを説明する上で、全体像を先に提示します。
順を追って、この全体像を基に各リソースをマニフェストファイルの内容とともに解説していきます。
image.png

Service とは

Kubernetesクラスター内で複数のPodとして実行されているアプリケーションを公開するためのリソースです。
かつ、「複数のPodとして」という説明の通り、冗長化されたPodに対してトラフィックを分散させる役割も持っています。

マニフェストファイルの例

apiVersion: v1
kind: Service
metadata:
  name: my-service-80
  namespace: app
  annotations:
      alb.ingress.kubernetes.io/healthcheck-path/: '/api/health'
      alb-ingress.kubernetes.io/target-type: ip
spec:
  selector:
    app: my-app # my-appというPodに対してトラフィックを転送する
  ports:
    - protocol: TCP
      port: 80      # Serviceが公開するポート
      targetPort: 9376  # Podがリッスンしているポート

上記マニフェストの場合、my-service-80という名前のServiceが定義され、spec.selector.appで指定されたラベルに一致する全てのPodに対してトラフィックを分散します。

アプリケーションを公開するとはport: 80と定義することで、port: 80でクラスター内部に対して公開する、という意味になります。
後続のPodが冗長化している場合、Serviceでロードバランサーの役割を担い、負荷分散させてトラフィックを流す必要があるため、必須のリソースとなります。

注意点としては外部に対して公開しているわけではいので、http://PodのIPアドレス:80 でアクセスできるわけではありません。

Deploymentのマニフェストファイルで定義されたyaml内に、replicas: 2のように定義されている場合、my-appラベルのPodは2つに冗長化されていることになりますが、その2つのPodに対してトラフィックを分散することになります。

apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-app-deployment-80
spec:
  replicas: 2  # Podのレプリカ数
  selector:
    matchLabels:
      app: my-app
      tier: backend

複数のPodに対してトラフィックを分散させることは可能ですが、targetPortが異なる場合、ServiceはそれぞれのtargetPortに向けたServiceが必要になります。

my-appラベルのPodは2つに冗長化されていることになりますが、その2つのPodに対してトラフィックを分散することになります。

上記で説明した2つに冗長化されているPodとは同じtargetPortに向けた同じ機能を持つPodという意味です。
image.png

異なるtargetPortに向けたService

異なるtargetPortに向けてトラフィックを転送する場合にはそれぞれServiceが必要になります。

以下のマニフェストファイルのようにServiceを2つ定義してそれぞれのPortListenしているPodにトラフィックを転送します。

apiVersion: v1
kind: Service
metadata:
  name: my-service-80
  namespace: app
  annotations:
      alb.ingress.kubernetes.io/healthcheck-path/: '/api/health' # ヘルスチェックパス
      alb-ingress.kubernetes.io/target-type: ip # ターゲットタイプ
spec:
  selector:
    app: my-app # my-appというPodに対してトラフィックを転送する
    tier: backend # バックエンドを示すラベル
  ports:
    - protocol: TCP
      port: 80      # Serviceが公開するポート
      targetPort: 9376  # Podがリッスンしているポート
---
apiVersion: v1
kind: Service
metadata:
  name: my-service-81
  namespace: app
  annotations:
      alb.ingress.kubernetes.io/healthcheck-path/: '/api/health'# ヘルスチェックパス
      alb-ingress.kubernetes.io/target-type: ip # ターゲットタイプ
spec:
  selector:
    app: my-app # my-appというPodに対してトラフィックを転送する
    tier: backend # バックエンドを示すラベル
  ports:
    - protocol: TCP
      port: 81      # Serviceが公開するポート
      targetPort: 9377  # Podがリッスンしているポート

しれっとnamespace, annotations以下の内容が存在していますが、ここについても解説します。

  namespace: app
  annotations:
      alb.ingress.kubernetes.io/healthcheck-path/: '/api/health'
      alb-ingress.kubernetes.io/target-type: ip

namespace: app

クラスターに所属するNamespaceを指定しています。この場合appというNamespace内にこのServiceは存在します。

annotations

Serviceに追加の設定をする場合に記述します。ここではAWS LoadBalancer Controllerに関するアノテーションを指定しています。
AWS LoadBalancer Controllerについては後述します。

alb.ingress.kubernetes.io/healthcheck-path/: '/api/health'

ヘルスチェックのパスを指定します。Serviceにおいてhealthcheck-pathを定義していますが、実際にヘルスチェックが行われるのはPodです。
ALBは'/api/health'に対してHTTPリクエストを定期的に送り続け、Serviceがそのリクエストを受信し、後続のPodに転送します。Podがリクエストを受信し、応答が正常であればHTTPステータスコード200を返し、healthy状態であることを確認します。

alb-ingress.kubernetes.io/target-type: ip

ALBがトラフィックを転送する先のターゲットタイプをipを指定してトラフィックを転送します。
ALBがPodのIPアドレスに対してトラフィックを流します。

Ingress とは

Ingressはクラスター外部からクラスター内のServiceに対してトラフィック(HTTP/HTTPS)を転送する役割を担います。
簡単に言うと、外部からのアクセスを適切なServiceに振り分ける仕組みです。
image.png
Ingressを使用する場合、前提としてIngressコントローラーが必要になります。
Ingressコントローラーには様々なコントローラーが存在します。
詳細の内容はKubernetes公式に記載があります。

本記事ではNGINX Ingress Controller, AWS Load Balancer Controllerが登場するため、この2つのコントローラーに絞って内容を記載していきます。

Ingressの主な役割は以下です。

外部からのアクセスを管理

- クラスター外からのHTTP/HTTPSリクエストを受け付け、適切なServiceに転送します

パスベースのルーティング

- リクエストのパスに応じて異なるServiceにトラフィックを振り分けます

例えば以下のようなIngressを定義した場合、rulesセクションで定義しているpathに応じて、どのServiceにリクエストを転送するかを定義します。
my-app.example.comのようなドメインである場合、ユーザがmy-app.example.com/path1でアクセスした場合、リクエストはALB -> Ingressの流れでリクエストが到達します。
Ingressはrulesの内容に従って、path1を解釈し、my-service-80のServiceに対してリクエストを転送します。
path2である場合、my-servce-81のServiceに対してリクエストを転送します。

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: my-ingress
spec:
  rules:
      http:
        paths:
          - path: /path1
            pathType: Prefix # `/`で分割されたURLと前方一致で一致、大文字小文字は区別される
            backend:
              service:
                name: my-service-80
                port:
                  number: 9376
          - path: /path2
            pathType: Prefix
            backend:
              service:
                name: my-service-81
                port:
                  number: 9377

TLSの終端

- こちらは以下を見るとわかりやすいです

ユーザからのリクエストでIngressまでが暗号化された通信となります。
Ingressで暗号化された内容を復号化し、平文をServiceに転送します。

+-------------------+       +-------------------+       +-------------------+       +-------------------+
|    ユーザー        |       |       ALB         |       |      Ingress      |       |      Service       |
|                   |       |                   |       |                   |       |                   |
|  HTTPSリクエスト   | ----> |  HTTPSリクエスト   | ----> |  HTTPSリクエスト   | ----> |  HTTPリクエスト     |
|  (暗号化)          |       |  (暗号化)         |       |  (暗号化)          |       |  (平文)            |
|                   |       |                   |       |                   |       |                   |
+-------------------+       +-------------------+       +-------------------+       +-------------------+

ただし、上記の流れはNGINX Ingress Controllerを使用した場合の例となります。

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: my-ingress
  annotations:
    # NGINX Ingress ControllerがTLS終端を行い、復号されたHTTPリクエストをServiceに転送する。
    nginx.ingress.kubernetes.io/ssl-redirect: "true" 
spec:
  tls:
      secretName: my-tls-secret
  rules:
    - host: my-app.example.com
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: my-service-80
                port:
                  number: 9376

NGINX Ingress Controllerを使用した場合はTLSの終端がIngressとなりますが、AWS LoadBalancer Controllerを使用した場合はTLSの終端はALBとなります。

AWS LoadBalancer Controllerを使用したマニフェストファイルの例が以下です。

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: my-ingress
  annotations:
    kubernetes.io/ingress.class: alb  # AWS Load Balancer Controllerを使用
    alb.ingress.kubernetes.io/scheme: internet-facing  # インターネット向けALB
    alb.ingress.kubernetes.io/listen-ports: '[{"HTTP": 80}, {"HTTPS":443}]'  # HTTPとHTTPSのリスナー
    alb.ingress.kubernetes.io/certificate-arn: arn:aws:acm:region:account-id:certificate/certificate-id  # TLS証明書のARN
    alb.ingress.kubernetes.io/actions.ssl-redirect: '{"Type": "redirect", "RedirectConfig": { "Protocol": "HTTPS", "Port": "443", "StatusCode": "HTTP_301"}}'  # HTTPをHTTPSにリダイレクト
spec:
  rules:
      http:
        paths:
          - path: /path1  # パス
            pathType: Prefix  # パスのマッチングタイプ
            backend:
              service:
                name: my-service-80  # 転送先のService
                port:
                  number: 9376  # Serviceのポート番号

ALBがTLSの終端となる場合に必要な記述は以下のannotationsセクションとなります。

  annotations:
    kubernetes.io/ingress.class: alb  # AWS Load Balancer Controllerを使用
    alb.ingress.kubernetes.io/scheme: internet-facing  # インターネット向けALB
    alb.ingress.kubernetes.io/listen-ports: '[{"HTTP": 80}, {"HTTPS":443}]'  # ALBがリッスンするポートを指定、HTTPとHTTPSのリスナー
    alb.ingress.kubernetes.io/certificate-arn: arn:aws:acm:region:account-id:certificate/certificate-id  # TLS証明書のARN
    alb.ingress.kubernetes.io/actions.ssl-redirect: '{"Type": "redirect", "RedirectConfig": { "Protocol": "HTTPS", "Port": "443", "StatusCode": "HTTP_301"}}'  # HTTPをHTTPSにリダイレクト

alb.ingress.kubernetes.io/listen-ports

'[{"HTTP": 80}, {"HTTPS":443}]'の記載でALBがポート80, 443でListenしている状態です。

alb.ingress.kubernetes.io/actions.ssl-redirect

リダイレクトの内容を記載しているため、仮にhttp://my-app.example.comでアクセスしてきた場合でも、ALBが80番ポートでLinstenしているため、ALBがHTTPS(ポート443)にリダイレクトします。

alb.ingress.kubernetes.io/certificate-arn

ALBがパブリックに公開されている場合には、HTTPS通信を実現するためにACMを使用してTLS証明書を発行し、ALBに関連付けをすることで暗号化通信を実現するための記述です。

AWS LoadBalancer Controller

ここまで温めてきたAWS LoadBalancer Controllerについて満を持してご説明します。
ここまで温めてきたのは最初にServiceとIngressの内容を理解した上で、AWS LoadBalancer Controllerの説明をした方が理解し易いためです。
AWS LoadBalancer Controllerをクラスターにインストールすることで、ServiceやIngressのリソースを基に、ALBやNLBを自動作成してくれるすぐれものコンポーネントです。

Ingressリソースでは前述してきた通り、IngressのマニフェストファイルでannotationsセクションにALBの内容を記載することでAWS LoadBalancer Controllerが自動的にALBを構築します。

では、NLBは誰が作るの?という話ですが、NLBはServiceリソースで定義することで作成されます。
マニフェストファイルの例が以下です。

apiVersion: v1
kind: Service
metadata:
  name: my-service-80
  annotations:
    service.beta.kubernetes.io/aws-load-balancer-type: "nlb"  # NLBを作成
    service.beta.kubernetes.io/aws-load-balancer-internal: "true" 
spec:
  type: LoadBalancer
  selector:
    app: my-app
  ports:
    - protocol: TCP
      port: 80
      targetPort: 9376

service.beta.kubernetes.io/aws-load-balancer-type

annotationsセクションでservice.beta.kubernetes.io/aws-load-balancer-type: "nlb"を指定することでServiceリソースを基にNLBが作成されます。

最後に

EKSクラスター上でAWS LoadBalancer ControllerをインストールしService, IngressをデプロイしALBの構築なども別記事でできたらと思っています。

以下AWS公式が出している内容を基にハンズオンしていくと良いかなと思っていますので、機会があれば執筆できたらとおもってい

参考

0
1
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
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?