EKSのIngressにてターゲットタイプがipとinstanceの場合におけるALBメトリクス挙動の差異を調べてみた

2024.02.27

こんにちはカスタマーソリューション部のこーへいです!

前回の記事にて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で安定しました。

この時点での私の思考の流れは以下の通りです。

  1. instance自体はターゲットグループでhealthyなので片方のpodのindex.htmlを削除しても「HealthyHostCount」は1のままで、両方のpodのindex.htmlを削除すると「UnHealthyHostCount」が1となると予想
  2. 実際に試してみると片方のpodのindex.htmlを削除した段階で、それぞれのカウントが0~1(0.5含む)の間で不安定に推移した。0.5という値があるため実態はpodのhealthy状態をカウントしている可能性が浮上(2台あるpodのうち1台という計算)
  3. 次は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を指定することが良いことが分かったので満足しました。