はじめに
本記事ではKubernetesリソースのService、Ingressについて解説します。
また、AWS LoadBalancer Controllerについても解説します。
全体像
はじめに各リソースを説明する上で、全体像を先に提示します。
順を追って、この全体像を基に各リソースをマニフェストファイルの内容とともに解説していきます。
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という意味です。
異なるtargetPortに向けたService
異なるtargetPort
に向けてトラフィックを転送する場合にはそれぞれServiceが必要になります。
以下のマニフェストファイルのようにServiceを2つ定義してそれぞれのPort
でListen
している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に振り分ける仕組みです。
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公式が出している内容を基にハンズオンしていくと良いかなと思っていますので、機会があれば執筆できたらとおもってい
参考