EKS on Fargate で Pod のメトリクスを取得してみた(ADOT 編)

EKS on Fargate で Pod のメトリクスを取得してみた(ADOT 編)

2026.04.08

はじめに

クラウド事業本部、あきやまです。
日々業務をしている中で運用監視って大事ですよね。
今回はEKS on Fargate 環境で ADOT(AWS Distro for OpenTelemetry)を使って Fargate 上のコンテナメトリクスを CloudWatch Container Insights に送信する方法を検証してみました。

EKS on Fargate では DaemonSet が使えないため、メトリクス収集にも EC2 とは異なるアプローチが必要です。AWS が公式に推奨している StatefulSet パターン で ADOT Collector をデプロイし、Container Insights のメトリクスを収集します。

環境

項目
OS macOS Tahoe 26.3
AWS CLI v2.32.32
kubectl v1.35.2
eksctl v0.222.0
EKS クラスターバージョン 1.31
リージョン ap-northeast-1
ADOT Collector イメージ public.ecr.aws/aws-observability/aws-otel-collector:latest

結論

EKS on Fargate では、ADOT Collector を StatefulSet としてデプロイし、Kubernetes API Server 経由で cAdvisor メトリクスをスクレイプすることで、CloudWatch Container Insights にメトリクスを送信できます。

項目 結果
デプロイ方式 StatefulSet(replicas: 1)
メトリクス取得方法 Kubernetes API Server 経由で各ノードの /metrics/cadvisor をプロキシスクレイプ
収集できるメトリクス CPU / メモリ / ネットワーク / ストレージ(Pod・コンテナ単位)
送信先 CloudWatch Container Insights(EMF 形式)
必要なリソース Namespace / ServiceAccount(IRSA) / 公式テンプレート一式(RBAC / ConfigMap / Service / StatefulSet)

※ Fargate では DaemonSet ベースの CloudWatch Agent が使えないため、Container Insights の Enhanced Observability(Accelerated Compute Metrics 等)は利用できません。基本的な CPU / メモリ / ネットワークメトリクスが対象です。

EKS on Fargate のメトリクス収集アーキテクチャ

EC2 vs Fargate の違い

メトリクス収集において、EC2 と Fargate ではアーキテクチャが大きく異なります。

EKS on EC2(DaemonSet 方式)

EKS on Fargate(StatefulSet ADOT 方式)

比較表

比較軸 EKS on EC2 (DaemonSet) EKS on Fargate (StatefulSet ADOT)
エージェント CloudWatch Agent ADOT Collector
デプロイ方式 DaemonSet(ノードごとに1つ) StatefulSet(クラスターに1つ)
メトリクス取得経路 ノードの kubelet に直接アクセス Kubernetes API Server 経由でプロキシ
Container Insights Enhanced Observability 対応 基本メトリクスのみ
IAM 認証 IRSA / Pod Identity IRSA
設定方法 Helm chart / Add-on YAML マニフェスト
スケーラビリティ ノード数に自動スケール replicas の手動調整が必要

環境準備

検証用の EKS クラスターを eksctl で構築します。Fargate 専用クラスターとして作成し、ADOT Collector 用の fargate-container-insights Namespace と検証ワークロード用の demo Namespace の Fargate Profile も同時に定義します。

EKS クラスターの作成

cluster-config.yaml
apiVersion: eksctl.io/v1alpha5
kind: ClusterConfig

metadata:
  name: fargate-logging-test
  region: ap-northeast-1
  version: "1.31"

iam:
  withOIDC: true

# Fargate 専用のためマネージドノードグループは作成しない
fargateProfiles:
  # kube-system と CoreDNS 用(Fargate 専用クラスターで必須)
  - name: fp-system
    selectors:
      - namespace: kube-system
      - namespace: default

  # 検証用ワークロード
  - name: fp-demo
    selectors:
      - namespace: demo

  # ADOT Collector(メトリクス収集用)
  - name: fp-container-insights
    selectors:
      - namespace: fargate-container-insights
eksctl create cluster -f cluster-config.yaml

※ クラスター作成には 15〜20分ほどかかります。

CoreDNS の Fargate 対応

eksctl で Fargate 専用クラスターを作成した場合、CoreDNS が EC2 ノードを待ち続けて Pending のままになることがあります。以下で Fargate 上で動作するように修正します。

# CoreDNS から EC2 用のアノテーションを削除
kubectl patch deployment coredns \
  -n kube-system \
  --type json \
  -p='[{"op": "remove", "path": "/spec/template/metadata/annotations/eks.amazonaws.com~1compute-type"}]'

# Pod を再起動して Fargate で起動させる
kubectl rollout restart deployment coredns -n kube-system

# CoreDNS が Running になることを確認
kubectl get pods -n kube-system -l k8s-app=kube-dns

検証用アプリケーションのデプロイ

メトリクス収集の対象となるワークロードを demo Namespace にデプロイします。

namespace-demo.yaml
apiVersion: v1
kind: Namespace
metadata:
  name: demo
deployment-web-app.yaml
apiVersion: v1
kind: Service
metadata:
  name: web-app
  namespace: demo
spec:
  selector:
    app: web-app
  ports:
    - port: 80
      targetPort: 80
  type: ClusterIP
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: web-app
  namespace: demo
spec:
  replicas: 2
  selector:
    matchLabels:
      app: web-app
  template:
    metadata:
      labels:
        app: web-app
    spec:
      containers:
      # コンテナ 1: nginx(メインアプリケーション)
      - name: nginx
        image: nginx:1.25
        ports:
        - containerPort: 80
        resources:
          requests:
            cpu: "100m"
            memory: "128Mi"
          limits:
            cpu: "200m"
            memory: "256Mi"

      # コンテナ 2: log-generator(サイドカー / ログ生成用)
      - name: log-generator
        image: busybox:1.36
        command:
        - /bin/sh
        - -c
        - |
          i=0
          while true; do
            i=$((i+1))
            echo "{\"level\":\"info\",\"container\":\"log-generator\",\"msg\":\"heartbeat #${i}\",\"ts\":\"$(date -u +%Y-%m-%dT%H:%M:%SZ)\"}"
            sleep 10
          done
        resources:
          requests:
            cpu: "50m"
            memory: "64Mi"
          limits:
            cpu: "100m"
            memory: "128Mi"
kubectl apply -f namespace-demo.yaml
kubectl apply -f deployment-web-app.yaml

Pod が起動したことを確認します。

kubectl get pods -n demo -o wide

READY2/2NODEfargate- で始まることを確認します。

やってみた

環境が整ったので、ここからは ADOT Collector の構築手順です。

Step 0: Namespace の作成

ADOT Collector をデプロイする fargate-container-insights Namespace を作成します。

namespace-fargate-insights.yaml
apiVersion: v1
kind: Namespace
metadata:
  name: fargate-container-insights
kubectl apply -f namespace-fargate-insights.yaml

Namespace が作成されたことを確認します。

kubectl get namespace fargate-container-insights

Step 1: IRSA(IAM Roles for Service Accounts)の設定

ADOT Collector が CloudWatch にメトリクスを送信するために、IRSA で IAM ロールを ServiceAccount に紐づけます。

# ADOT Collector 用の ServiceAccount を作成(IAM ロールを自動作成)
eksctl create iamserviceaccount \
  --name adot-collector \
  --namespace fargate-container-insights \
  --cluster fargate-logging-test \
  --region ap-northeast-1 \
  --attach-policy-arn arn:aws:iam::aws:policy/CloudWatchAgentServerPolicy \
  --approve

ServiceAccount が作成されたことを確認します。

kubectl get serviceaccount adot-collector -n fargate-container-insights -o yaml

eks.amazonaws.com/role-arn アノテーションに IAM ロール ARN が設定されていれば OK です。

Step 2: 公式テンプレートのダウンロードとカスタマイズ

AWS が提供する ADOT Collector の公式テンプレートをダウンロードし、環境に合わせてカスタマイズします。

:::note info
このテンプレートには RBAC / ConfigMap / Service / StatefulSet がすべて 1 ファイルにまとまっています。kubectl apply -f 一発でデプロイできます。
:::

このテンプレートには以下のリソースがすべて含まれています。

リソース 役割
ClusterRole / ClusterRoleBinding ADOT Collector が Kubernetes API にアクセスするための RBAC 権限
ConfigMap OpenTelemetry パイプラインの設定(Receiver → Processor → Exporter)
Service ADOT Collector のメトリクスエンドポイント(ポート 8888)
StatefulSet ADOT Collector 本体(replicas: 1)
# 公式テンプレートをダウンロード
curl -O https://raw.githubusercontent.com/aws-observability/aws-otel-collector/main/deployment-template/eks/otel-fargate-container-insights.yaml

クラスター名とリージョンを環境に合わせて置換します。

# クラスター名を置換
sed -i '' 's/YOUR-EKS-CLUSTER-NAME/fargate-logging-test/g' otel-fargate-container-insights.yaml

# リージョンを置換(デフォルトは us-east-1)
sed -i '' 's/us-east-1/ap-northeast-1/g' otel-fargate-container-insights.yaml

Step 3: ADOT Collector のデプロイ

kubectl apply -f otel-fargate-container-insights.yaml

テンプレートに含まれる OpenTelemetry パイプラインは、以下の 10 段階のプロセッサを経てメトリクスを加工します。

prometheus (receiver)
  │  Kubernetes API Server 経由で cAdvisor メトリクスをスクレイプ

metricstransform/label_1 ... ラベルのリネーム(name→container_id, compute_type→LaunchType 等)

resourcedetection .......... EKS メタデータ(ClusterName 等)を自動検出

metricstransform/rename .... cAdvisor メトリクスを Pod / Container レベルに分離・リネーム

filter ..................... リネーム済みメトリクス(pod_*, new_container_*)のみ通過

cumulativetodelta .......... 累積値をデルタ値に変換

deltatorate ................ デルタ値をレートに変換(例: bytes → bytes/sec)

metricsgeneration/1 ........ 派生メトリクス生成(CPU millicore 換算、メモリ使用率 等)

metricsgeneration/2 ........ CPU 使用率(pod_cpu_utilization_over_pod_limit)を算出

metricstransform/label_2 ... Type ラベル追加(Pod / Container)、Namespace / PodName ラベルの正規化

batch ...................... 60 秒間隔でバッチ送信

awsemf (exporter)
  │  CloudWatch Embedded Metric Format で送信

CloudWatch Container Insights
  ロググループ: /aws/containerinsights/{ClusterName}/performance

CloudWatch に送信されるメトリクスとディメンションは以下の通りです。

メトリクス 内容
pod_cpu_utilization_over_pod_limit CPU 使用率(Pod リミット比)
pod_cpu_usage_total CPU 使用量(Millicore)
pod_cpu_limit CPU リミット(Millicore)
pod_memory_utilization_over_pod_limit メモリ使用率(Pod リミット比)
pod_memory_working_set メモリ Working Set
pod_memory_limit メモリリミット
pod_network_rx_bytes ネットワーク受信バイト
pod_network_tx_bytes ネットワーク送信バイト
ディメンション
ClusterName, LaunchType
ClusterName, Namespace, LaunchType
ClusterName, Namespace, PodName, LaunchType

なぜ Deployment ではなく StatefulSet?
ADOT Collector はクラスター全体の cAdvisor メトリクスを 1 台でスクレイプする設計です。Deployment(replicas: 1)でも動作しますが、ローリングアップデート時に一瞬 2 台になりメトリクスが重複する可能性があります。StatefulSet なら古い Pod が完全に終了してから新しい Pod が起動するため、重複収集を防げます。

Step 4: ADOT Collector の起動確認

kubectl get pods -n fargate-container-insights -o wide

期待される出力:

NAME                READY   STATUS    RESTARTS   AGE   IP            NODE
adot-collector-0    1/1     Running   0          2m    10.0.x.xxx    fargate-ip-10-0-x-xxx...

READY1/1STATUSRunning であること、NODEfargate- で始まることを確認します。

ADOT Collector のログを確認して、スクレイプが正常に動作しているかチェックします。

kubectl logs -n fargate-container-insights adot-collector-0 --tail=20

エラーが出ていなければ、メトリクスの収集と CloudWatch への送信が開始されています。

Step 5: CloudWatch でメトリクスを確認

ロググループにメトリクスデータが送信されていることを確認します。

aws logs describe-log-streams \
  --log-group-name /aws/containerinsights/fargate-logging-test/performance \
  --order-by LastEventTime \
  --descending \
  --region ap-northeast-1 \
  --query 'logStreams[*].logStreamName' \
  --output json

CloudWatch コンソールから Container Insights を確認します。

  1. CloudWatch コンソール → Container Insights → Performance monitoring を開く
  2. クラスター fargate-logging-test を選択
  3. Pod / Namespace 単位で CPU / メモリ / ネットワークメトリクスが表示されることを確認

CloudWatch Logs Insights でメトリクスデータを直接クエリすることもできます。

fields @timestamp, PodName, Namespace, pod_cpu_usage_total, pod_memory_working_set
| filter Namespace = "demo"
| sort @timestamp desc
| limit 20

Step 6: アプリケーション Pod のメトリクスが収集されていることを検証

demo Namespace の web-app Pod のメトリクスが収集されていることを確認します。

# demo Namespace の Pod が動作中であることを確認
kubectl get pods -n demo -o wide

注意点・制約

検証を通じて発見した制約やハマりポイントをまとめます。

# カテゴリ 内容
1 DaemonSet 不可 Fargate では DaemonSet が使えないため、ADOT Collector を StatefulSet としてデプロイする必要があります
2 Enhanced Observability 非対応 DaemonSet ベースの CloudWatch Agent が必要な Enhanced Observability(Accelerated Compute Metrics 等)は Fargate では利用できません
3 API Server 経由のスクレイプ kubelet に直接アクセスできないため、Kubernetes API Server をプロキシとして経由します。API Server の負荷に注意が必要です
4 replicas の調整 Pod 数が多い場合、ADOT Collector の replicas を増やす必要がある場合があります。ただし Prometheus receiver の重複スクレイプに注意してください
5 Fargate のリソース課金 ADOT Collector Pod 自体も Fargate で動作するため、CPU / メモリの課金が発生します
6 IRSA が必要 ADOT Collector は独立した Pod としてデプロイするため、IRSA を使って ServiceAccount に IAM ロールを紐づける必要があります
7 resourcedetectioneks ディテクター非対応 公式テンプレートのデフォルトは detectors: [env, eks] だが、Fargate では eks ディテクターが IMDS にアクセスできずクラッシュする。detectors: [env] に変更が必要

まとめ

本記事では、EKS on Fargate で ADOT Collector を StatefulSet としてデプロイし、CloudWatch Container Insights にメトリクスを送信する方法を検証しました。

実運用を考えるともう少し作りこみが必要ですがどなたかの参考になれば幸いです。

参考

この記事をシェアする

関連記事