EKSのIngressにてターゲットタイプがipとinstanceの場合におけるALBメトリクス挙動の差異を調べてみた
こんにちはカスタマーソリューション部のこーへいです!
前回の記事にてEKSのIngressにてALBのターゲットタイプにipとinstanceがあり、ヘルスチェックの違いを検証してみました。
今回はALBのメトリクスの違いを調べてみます!
結論
- メトリクスの観点においてもIngressのターゲットはipで指定すべき
- Ingressのターゲットをipにした場合、podの数に沿って「HealthyHostCount」「UnHealthyHostCount」が安定な動きで推移するため、アラームの設定が可能
- 一方でIngressのターゲットをinstanceにした場合、一部のpodがUnhealthy状態になった際のALBのメトリクス「HealthyHostCount」「UnHealthyHostCount」が共に不安定な動きで推移するため、アラームの設定が実質不可能
前提
- EKS Cluster作成済み
- AWS Load Balancer Controllerを使用できる状態
上記を前提といたします。今回は本題ではないので省略しますが、EKS初心者の方は下記記事による構築がすごくわかりやすかったです。
事前準備
AWS Load Balancer Controllerを使用できる状態まで完了していると、残りは以下のリソース作成が必要となります。
- Ingress
- Service
- deployment
サンプルとはなってしまいますが、検証の際に自分が用いたyamlファイルを置いておきます。
ターゲットタイプがipの場合のサンプルファイル
Ingress.yaml
apiVersion: networking.k8s.io/v1 kind: Ingress metadata: annotations: alb.ingress.kubernetes.io/scheme: internet-facing # 外部からのトラフィックを許可 alb.ingress.kubernetes.io/target-type: ip # Ipをターゲットに設定 name: sample-ingress spec: ingressClassName: alb # ingressのクラス名を定義 rules: - http: # httpルール paths: - path: / pathType: Prefix backend: service: name: sample-service # 接続するService port: number: 80
service.yaml
apiVersion: v1 kind: Service metadata: name: sample-service spec: ports: # Podへのアクセスに使用するport - port: 80 targetPort: 80 protocol: TCP type: ClusterIP # クラスター内Pod通信 selector: app: nginx
deployment.yaml
apiVersion: apps/v1 kind: Deployment metadata: name: sample-app # 作成するリソースの名前 spec: replicas: 2 # Deploymentが管理するPodのレプリカ数 selector: # 適用するリソースの選択 matchLabels: # ラベルの一致を条件とする app: nginx template: # 作成するpodの定義 metadata: labels: app: nginx spec: containers: # pod内のコンテナの仕様 - name: nginx # コンテナの名前 image: public.ecr.aws/nginx/nginx:1.23 # コンテナイメージ ports: # コンテナが公開するポート(内部向け) - name: tcp containerPort: 80
ターゲットタイプがinstanceの場合のサンプルファイル
ターゲットタイプがinstanceなため、サービスタイプをNodeportにしています。
このトラフィックモードを使用するには、Kubernetes サービスで NodePort または「LoadBalancer」 タイプを指定する必要があります。
参考:https://docs.aws.amazon.com/ja_jp/eks/latest/userguide/alb-ingress.html
Ingress.yaml
apiVersion: networking.k8s.io/v1 kind: Ingress metadata: annotations: alb.ingress.kubernetes.io/scheme: internet-facing # 外部からのトラフィックを許可 alb.ingress.kubernetes.io/target-type: instance # instanceをターゲットに設定 name: sample-ingress spec: ingressClassName: alb # ingressのクラス名を定義 rules: - http: # httpルール paths: - path: / pathType: Prefix backend: service: name: sample-service # 接続するService port: number: 80
service.yaml
apiVersion: v1 kind: Service metadata: name: sample-service spec: ports: - port: 80 # サービスポート targetPort: 80 # ポッドのポート protocol: TCP type: NodePort # NodePortタイプのサービス selector: app: nginx # このサービスにトラフィックをルーティングするPodのラベルセレクター
deployment.yaml
apiVersion: apps/v1 kind: Deployment metadata: name: sample-app # 作成するリソースの名前 spec: replicas: 2 # Deploymentが管理するPodのレプリカ数 selector: # 適用するリソースの選択 matchLabels: # ラベルの一致を条件とする app: nginx template: # 作成するpodの定義 metadata: labels: app: nginx spec: containers: # pod内のコンテナの仕様 - name: nginx # コンテナの名前 image: public.ecr.aws/nginx/nginx:1.23 # コンテナイメージ ports: # コンテナが公開するポート(内部向け) - name: tcp containerPort: 80
調べる
それぞれのターゲットタイプの場合のメトリクスを見てみましょう。
ターゲットタイプがipの場合
この場合、ターゲットグループに登録されているのはpodとなります。
正常なpodを2つ立ててメトリクスを確認してみましょう。ALB(ターゲットグループ)のヘルスチェックは最初は2台ともHealthy状態です。
以下はCloudWatchのメトリクス画面です。ALBのメトリクス「HealthyHostCount」はカウント2、「UnHealthyHostCount」はカウント0と想定通りカウントされています。
その後、片方のpodのindex.htmlを削除して意図的にUnhealthy状態にします。
k get pods -n default -o wide # pod名を確認 k exec -it [pod名] -- /bin/bash # podにログイン rm /usr/share/nginx/html/index.html # podのindex.htmlを削除
しばらくすると「HealthyHostCount」「UnHealthyHostCount」共にカウント1で安定しました。想定通りの結果となりました。
ターゲットタイプがinstanceの場合
podが2台の場合
この場合、ターゲットグループに登録されているのはノード(EC2インスタンス)となります。
正常なpodを2つ立ててメトリクスを確認してみましょう。ALB(ターゲットグループ)のヘルスチェックはインスタンス一台がHealthy状態です。
どちらのpodもHealthyの状態では「HealthyHostCount」はカウント1、「UnHealthyHostCount」はカウント0で安定していましたが、片方のpodのindex.htmlを削除すると「HealthyHostCount」「UnHealthyHostCount」それぞれのカウントが安定しなくなりました。
18分に2つ目のpodのindex.htmlを削除すると、「HealthyHostCount」が0、「UnHealthyHostCount」が1で安定しました。
この時点での私の思考の流れは以下の通りです。
- instance自体はターゲットグループでhealthyなので片方のpodのindex.htmlを削除しても「HealthyHostCount」は1のままで、両方のpodのindex.htmlを削除すると「UnHealthyHostCount」が1となると予想
- 実際に試してみると片方のpodのindex.htmlを削除した段階で、それぞれのカウントが0~1(0.5含む)の間で不安定に推移した。0.5という値があるため実態はpodのhealthy状態をカウントしている可能性が浮上(2台あるpodのうち1台という計算)
- 次はpodが3台の場合で検証して確かめよう
podが3台の場合
deployment.yamlのreplica数を2→3に変更し、検証します。
spec: replicas: 3 # Deploymentが管理するPodのレプリカ数 selector: # 適用するリソースの選択
上記と同様の流れで、28分時点で1台目、35分時点で2台目、46分時点で全て(3台目)のpodのindex.htmlを削除しました。
予想ではCount数の小数点が0.33や0.66(全3台あるうちのpod数の1or2台の意)が記録されるかと思いましたが、実際には予想と異なり、0~0.5~1で不安定的に推移するという結果となりました。
また申し訳ないですが、なぜ0.5なのかや推移が不安定なのかの原因解明はできなかったです(分かり次第追記します)。
結論(再掲載)
- メトリクスの観点においてもIngressのターゲットはipで指定すべき
- Ingressのターゲットをipにした場合、podの数に沿って「HealthyHostCount」「UnHealthyHostCount」が安定な動きで推移するため、アラームの設定が可能
- 一方でIngressのターゲットをinstanceにした場合、一部のpodがUnhealthy状態になった際のALBのメトリクス「HealthyHostCount」「UnHealthyHostCount」が共に不安定な動きで推移するため、アラームの設定が実質不可能
まとめ
Ingressのターゲットがinstance時の、メトリクスの値や推移については謎が解けませんでした(すみません)。
しかし、前回の記事と合わせてもターゲットはipを指定することが良いことが分かったので満足しました。