はじめに
Kubernetesで動作するアプリケーションのメトリクスを管理する方法としては、Prometheus + GrafanaやELKスタックがよく挙げられます。
しかしながら、AWSのElastic Kubernetes Service (EKS)の場合は、AWSのマネージド監視サービスであるCloudWatchを利用したい方も多いのではないでしょうか。
AWS Distro for OpenTelemetry を使えば、簡単にEKS上のアプリのメトリクスをCloudWatchに送信できます!PodのCPU/RAM使用率などはもちろん、Prometheus形式のメトリクスも対応可能です。
AWS Distro for OpenTelemetry (ADOT) とは
AWSが公式にメンテナンスしている、OpenTelemetry Collectorのディストリビューションです。名前が長いので、以下では頭文字を取って ADOT という略称で呼びます。
そもそもOpenTelemetry Collectorとは?
アプリケーションのログ・メトリクス・トレースをそれぞれ統一的に扱い、多様な入力・出力に対応するための収集エージェントです。GitHub
特定のクラウドベンダーに依存せずに共通で使うことができるため、昨今かなり活発に開発されています。
Fluent Bitをご存じの方は、(かなり雑に言うと) 似たようなものと思っても良いでしょう。
OpenTelemetry Collectorは Receiver / Processor / Exporter という主に3種類のコンポーネント(下図)を持ちますが、それはFluent Bitが Input / Filter / Output の3要素を持つのと似ています。
Fluent BitのInputにはstatsdやTail、HTTPなど、OutputにはCloudWatchやStackdriverなどがサポートされており、多様なユースケースで利用可能です。また、Filter/Parserを設定することで、柔軟に収集を構成することもできます。
これと同じことがOpenTelemetry Collectorにも言えます。Receiverのリスト, Exporterのリスト
Fluent Bitとの違いを挙げるなら、Fluent Bitはログ収集がメインのユースケースと捉えている方が多いのではないでしょうか。このため、メトリクス収集においては利用者が少なく、まだサポートも弱いように思います。
一方OpenTelemetry Collectorは、メトリクス収集のユースケースがよくサポートされているようです。例えば、AWS Container Insights Receiverというコンポーネントを使うと、EKSのPod/Nodeのメトリクスがまとめて取得でき、そのままCloudWatchのコンソールで可視化が可能です。
ADOTは何のためにある?
ADOTはEKS上で使うために便利なコンポーネントがプリインストールされたOpenTelemetry Collectorのディストリビューションです。このため非常に簡単に利用開始でき、またAWSサービスに統合することができます。プリインストールされたコンポーネント一覧はこちら。
ここもFluent Bitと類推すると、素のFluent Bitに対して、いくつかのプラグインがプリインストールされた AWS for Fluent Bit が提供されているのに似ていますね。
このため、EKSでOpenTelemetry Collectorを使いたい場合は、ADOTを使うのが手っ取り早いでしょう。
その他のディストリビューションとしては、OpenTelemetry 公式のものがありますが、EKSでは明らかに不要なコンポーネントも含まれているようです。ADOTはEKSで使う場合には必要十分な、ちょうどよい選択肢となりそうですね。
なお、ADOT自体はEKSだけでなくECSやEC2上での動作も想定して開発されていますが、この記事では特にEKS上で使う際の話に特化します。
インストール方法
EKSにADOTをインストールするには、いくつか方法があります。
yamlでインストール
こちらのYAML を kubectl apply
することでインストールできます。
手順の詳細はこちらを参照してください。
yamlでインストールすると、構成をフルにカスタマイズ可能なため、柔軟性を求める場合はおすすめです。
Helmでインストール
HelmによるインストールもAWS公式にサポートされています。
手順の詳細はこちらを参照してください。
このHelmチャートにはログ収集のためのFluent Bitも含まれるため、手早くEKSにLog/Metrics収集機能を持たせるには便利でしょう。
ただし、チャートの外から必要な設定をいじれない場合もあるはずなので、完全なカスタマイズ性を求める場合は不向きかもしれません。
また、yaml/helmの手順いずれにしても、ADOTの利用するサービスアカウントのためのIAMロールを別途作成する必要があります。詳細はこちらを参照してください。
基本的には、ADOTの利用するサービスアカウントがOIDCでAssume可能なIAMロール (ポリシーはCloudWatchAgentServerPolicy
を付与) を作成すれば良いです。
構成方法
上記のインストール方法をそのまま利用した場合、CloudWatch Container Insightsのメトリクスが自動的に送信されはじめます。
このため、インストール後しばらくすると、CloudWatchのマネジメントコンソールから下記のようなDashboardを確認できるはずです。
これでは不足している場合、ADOTの構成を変更して、ユースケースに合うようにカスタマイズすることができます。
ADOTの設定
ADOTをyamlでインストールした場合、yaml内に otel-agent-config
という設定があります。
この部分を編集することで、ADOTの構成をカスタマイズすることができます。
Helmでインストールした場合、values.yaml
に従っていくつかの項目を設定できるようです。
ただし、Helmチャートの中身を読み解いて良い感じに記述する必要がありそうです。
この点においては、yamlでインストールしたほうが分かりやすいかも知れません。
ADOTの設定の書き方は、こちらを参照してください。
Prometheusメトリクスの利用
よくありそうなユースケースとして、Prometheus形式のメトリクスをCloudWatchに送信したい場合を考えてみます。
まず、Receiverとして Prometheus receiverを利用できます。以下は簡単な構成例です。
receivers:
prometheus:
config:
# https://prometheus.io/docs/prometheus/latest/configuration/configuration/
scrape_configs:
- job_name: 'otel-collector'
scrape_interval: 60s
kubernetes_sd_configs:
- role: pod
relabel_configs:
# PodのAnnotationからPrometheus metricsエンドポイントを検出する
# https://github.com/prometheus/prometheus/blob/v2.33.4/documentation/examples/prometheus-kubernetes.yml#L157-L178
- source_labels: [__meta_kubernetes_pod_annotation_prometheus_io_scrape]
action: keep
regex: true
- source_labels: [__meta_kubernetes_pod_annotation_prometheus_io_path]
action: replace
target_label: __metrics_path__
regex: (.+)
- source_labels: [__address__, __meta_kubernetes_pod_annotation_prometheus_io_port]
action: replace
regex: ([^:]+)(?::\d+)?;(\d+)
replacement: $$1:$$2
target_label: __address__
# awscontainerinsightreceiverと同一のLabel (Attribute) を付与する
- source_labels: [__meta_kubernetes_namespace]
action: replace
target_label: Namespace
- source_labels: [__meta_kubernetes_pod_node_name]
action: replace
target_label: NodeName
- source_labels: [__meta_kubernetes_pod_name]
action: replace
target_label: PodName
# cluster名は既存の __meta labelから取得できないので、外から渡す
# https://albersdevelopment.net/2019/08/28/prometheus-adding-a-label-to-a-target/
- source_labels: [__address__]
target_label: ClusterName
replacement: "sample-cluster"
# Service名は既存のlabelから取得できない とりあえずコンテナ名を代替にする
- source_labels: [__meta_kubernetes_pod_container_name]
action: replace
target_label: Service
Prometheus receiverの設定では、config
にPrometheus の Configuration (scrape_configs
) を直接記述できます。この例では kubernetes_sd_configs
で pod
のメトリクスを収集するようにしています。
続く relabel_configs
では、まずPodのannotationを見て、メトリクス取得対象PodのAuto discoveryをしています。これはADOTとは直接関係ない、Prometheusでよく知られたハックです。
これにより、これらのAnnotationが設定されたPodは自動的にADOTのメトリクス収集対象となります。
続いて、 Namespace
/ NodeName
/ PodName
/ Service
/ ClusterName
といったラベルを設定しています。ラベル名は、AWS Container Insights Receiver で設定されるラベルと同一になるようにしています。
これらのラベルは、Exporterの awsemf
という設定で参照します。以下の dimensions
の部分に注目してください。
exporters:
awsemf:
namespace: ContainerInsights
log_group_name: '/aws/containerinsights/{ClusterName}/performance'
log_stream_name: '{NodeName}'
metric_declarations:
# labelはこのDimensionで指定する!
- dimensions: [[NodeName, ClusterName]]
metric_name_selectors:
- node_cpu_utilization
- node_memory_utilization
awsemf
は、AWS CloudWatch EMF Exporterの設定です。
このDimesionで設定したラベルにより、CloudWatch上でメトリクスがグルーピングされて集計されます。また、ここで指定されたラベルが存在しないメトリクスは無視され、CloudWatchに送信されません。
CloudWatch上でメトリクスをグルーピングするために、Prometheusメトリクスについても適切にラベルを設定することが必要になります。
ラベルは自由に設定でき、またDimensionの項目も任意ですので、ユースケースに合わせてカスタマイズするのが良いでしょう。
ここではPrometheus形式のメトリクス収集例を紹介しましたが、他にも多くのReceiverが対応されています。
対応されたコンポーネント一覧
これらは同様にconfigファイルを記述することで利用できるため、適宜試してみてください。
コストの節約
デフォルトの設定では、一般的に必要とされるメトリクスを一通り送信しています。
ユースケースに合わせてメトリクスを取捨選択することで、コストの節約が可能です。
詳細はこちらの記事がよくまとまっています。
簡単にまとめると、ADOTのProcessor機能を利用することで、メトリクスのフィルタ・不要なフィールドの削除などを行います。
processors:
# 特定のフィールドをEMFのログから削除する例
resource:
attributes:
- key: Sources
action: delete
- key: kubernetes
action: delete
# 特定の名前をもつメトリクスを処理対象から除外する例
filter/exclude:
metrics:
exclude:
match_type: regexp
metric_names:
- container_.*
- go_.*
- redis_.*
なお、コストの由来はCloudWatch Logsの取り込み料金とCloudWatch Metricsのメトリクスごとの課金が主です。
なぜログ?と思われる方もいるかも知れませんが、ADOTではメトリクスをEMF形式でログとして送信するため、ログの取り込み料金も課金対象になります。
塵も積もればなので、監視に不要なメトリクスは積極的に除外していくのが良さそうです。参考: CloudWatch 利用料金
メトリクスは分かった ログやトレースは?
Observability 3種の神器はログ/メトリクス/トレースですが、ADOTはいずれも対応可能でしょうか?
OpenTelemetry Collector自体には、ログをCloudWatchにエクスポートするプラグインが一応あります。AWS CloudWatch Logs Exporter
しかしながら、こちらは現状Experimentalであり、またADOT自体にはまだ含まれていません。
このため、ログをCloudWatchに送るのは、Fluent Bitなどを利用するのが現状良いでしょう。
トレースに関しては、ADOTにトレースをAWS X-Rayへエクスポートするプラグインが含まれています。AWS X-Ray Tracing Exporter for OpenTelemetry Collector
こちらを利用することで、トレースも扱えるはずです。(ただ私はまだ使ったことないので、利用レポートをお待ちしてます!)
まとめ
AWS Distro for OpenTelemetry (ADOT)を使うことで、簡単にEKSのメトリクスをCloudWatchに収集することが可能です。
AWS公式にメンテナンスされており現在も活発に開発されているため、将来有望な手段です。
すでにCloudWatchにログを収集されている方、メトリクスの収集先・収集方法に困っている方はぜひ試してみてください!