Amazon Web Services ブログ

Prometheus と Grafana を使用して AWS Fargate で Amazon EKS をモニタリングする



AWS では、複雑さを軽減することで常に顧客体験の向上を目指しています。お客様は、ビジネス問題の解決に取り組むためにより多くの時間を費やし、インフラストラクチャの保守にかける時間を減らしたいと考えています。2 年前に、Kubernetes クラスターを簡単に操作できるように Amazon EKS をリリースしました。そして昨年の re:Invent 2019 で、Fargate で EKS のサポートを開始することを発表しました。この機能により、EC2 インスタンスを作成および管理せずに Kubernetes ポッドを実行できます。

お客様から、「Prometheus を使用して Fargate で実行されているポッドを監視できますか?」という質問がよく寄せられます。

はい、Prometheus を使用して Fargate で実行されているポッドを監視できます。Fargate でポッドがどのように実行され、関連する Prometheus メトリックがどこで発生するかを詳しく見ていきます。

Fargate で Kubernetes ポッドを実行する

AWS Fargate は、Amazon Elastic Container Service (ECS)Amazon Elastic Kubernetes Service (EKS) の両方で機能するコンテナ用のサーバーレスコンピューティングエンジンです。Fargate で Kubernetes ワークロードを実行する場合、サーバーをプロビジョニングして管理する必要はありません。Fargate を使用すれば、コンテナを実行するための適切な量のコンピューティングを取得できます。Fargate でコンテナを実行できる場合は、ワークロード用に EC2 インスタンスのサイズを設定する必要性を回避できます。Fargate を使用すると、アプリケーションで必要なリソースを指定してその分を支払うだけで済みます。アプリケーションポッドに必要な vCPU とメモリの量を把握するだけで、Fargate がそれを実行します。ポッドのサイズを適切に設定すると、right-size-guideGoldilocks vertical-pod-autoscaler などのツールを使用できます。また、Fargate を使用すれば、ポッドの水平方向のスケーリングも簡単になります。水平方向ポッドオートスケーラーが新しいレプリカを作成すると、Fargate は新しいポッドのノードを作成します。

EKS では、ポッドごとに EC2 または Fargate からコンピューティング容量を取得する場所を選択できます。Fargate の名前空間ですべてのポッドを実行するように Kubernetes に指示するか、Fargate で実行するラベルポッドを指定できます。一部のポッドが EC2 で実行され、他のポッドが Fargate で実行されるクラスターを作成できます。

Fargate プロファイルを使用して、Fargate で実行するポッドを宣言できます。Fargate の容量を必要とする Kubernetes 名前空間とラベルを指定するだけでなく、ポッドが IP アドレスを取得するサブネットを定義することもできます。

他にも、Fargate のポッドは独自の VM 分離環境を取得します。つまり、ポッドはカーネル、CPU、メモリ、ネットワークインターフェイスを他のポッドと共有しないという利点があります。Fargate は、ポッドとともに kubeletkubeproxycontainerd などの Kubernetes プロセスを実行します。Fargate で 5 つのポッドを実行していて、kubectl get nodes を実行すると、各ポッドに 1 つずつ、5 つのワーカーノードが表示されます。Fargate でも kube-system ポッドを実行する EKS クラスターを実行する場合、CoreDNS のノードも表示されます。

ポッドが Fargate でスケジュールされている場合、ポッド仕様内の vCPU とメモリの予約により、ポッドにプロビジョニングする vCPU とメモリの量が決まります。

  • Init コンテナからの最大リクエストは、Init リクエストの vCPU とメモリの要件を決定するために使用されます。
  • すべての長期実行コンテナに対するリクエストが合計され、長期実行リクエストの vCPU およびメモリ要件が決定されます。
  • 上記の 2 つの値のうち大きい方が、ポッドに使用する vCPU とメモリリクエストに選択されます。
  • Fargate は、必要な Kubernetes コンポーネント (kubeletkube-proxy、および containerd) の各ポッドのメモリ予約に 256 MB を追加します。
  • Fargate は、ポッドが実行に必要なリソースを常に確保できるように、vCPU とメモリリクエストの合計に最も近いコンピューティング構成に切り上げます。
  • vCPU とメモリの組み合わせを指定しない場合、使用可能な最小の組み合わせが使用されます (.25 vCPU と 0.5 GB メモリ)。

Fargate または EC2 のどちらを使用するかに関係なく、vCPU とメモリリクエストの宣言を検討してください。これにより、Kubernetes は、少なくとも各ポッドにリクエストされたリソースがコンピューティングリソースで利用できるようになります。

CPU とメモリ使用率の監視

Fargate で実行されているポッドの vCPU とメモリリクエストを定義すると、Fargate の CPU とメモリの使用率を正しく監視するのにも役立ちます。CPU とメモリ使用率の計算に使用される式は、Grafana ダッシュボードによって異なります。たとえば、一部の Grafana ダッシュボードは、ポッドのメモリ使用率を次のように計算します。

Pod のメモリ使用率 = 
(Pod 内のすべてのコンテナによって使用されるメモリ/
 ワーカーノードの合計メモリ) x 100

上記で説明したように、ポッドのリソース使用量はそのコンテナで宣言された vCPU とメモリリクエストの合計に制限されるため、この式では Fargate でのメモリ使用量が正しくありません。Fargate では、ポッドのリソース使用量は、Fargate ノードの CPU とメモリに対してではなく、次のようなコンテナの定義されたリクエストに対して計算する必要があります。

Pod のメモリ使用率 = 
(Pod 内のすべてのコンテナによって使用されるメモリ/
 最大 (ポッド内のコンテナによってリクエストされたメモリの合計、
    ポッド内のすべての初期化コンテナによってリクエストされたメモリの最大値)
    x 100

この式は、ポッドのコンピューティングリソースを監視し、コンテナのリソースリクエストを調整するタイミングを特定するのに役立ちます。リソースリクエストで宣言する値は、ポッドに割り当てる CPU とメモリの量を Fargate に指示します。ポッドのメモリと CPU 使用率が常にリソースリクエストで宣言した値に近づいていることに気付いたときは、リクエストされたリソースを確認するタイミングが近づいているのかもしれません。

Fargate がリソースを割り当てる方法について考えてみると、ポッドはコンテナ (個々の Init コンテナまたはすべての長期実行コンテナの合計のうち大きい方) でリクエストされた合計メモリ + 256 MB を次の Fargate 構成に切り上げます (下の表を参照)。たとえば、3.5 GB のメモリをリクエストすると、Fargate は 4 GB のメモリを割り当てます。3.5 GB + 250 MB は切り上げられます。メモリの値を宣言しない場合、Fargate は 0.5 GB を割り当てます。ポッド内のコンテナは、コンテナでメモリ制限を指定しない限り、利用可能なすべてのメモリを使用できます。

何を測定するべきかがわかったところで、次に、測定方法を見てみましょう。

Prometheus アーキテクチャ

Prometheus は、元々 SoundCloud で構築された時系列ベースのオープンソースシステム監視ツールです。Prometheus は、2016 年に、Kubernetes に続く 2 番目のホストプロジェクトとして Cloud Native Computing Foundation に参加しました。したがって、Prometheus が Kubernetes とシームレスに連携するのは当然のことです。

Prometheus は、HTTP 上のプルモデルを介してメトリックを収集します。Kubernetes では、Prometheus は Kubernetes API を使用してターゲットを自動的に検出できます。ターゲットは、ポッド、DaemonSet、ノードなどにすることができます。Kubernetes での Prometheus インストールには、一般的に次のコンポーネントが含まれます。

  • Prometheus サーバー
  • Node Exporter
  • プッシュゲートウェイ
  • アラートマネージャー
  • kube-state-metrics (stable/prometheus helm チャートを使用する場合、デフォルトでインストール)

Kubernetes では、Prometheus サーバーは、メトリックエンドポイントからメトリックをスクラップする責任を持つポッドとして実行されます。

Node Exporter は DaemonSet として実行され、実行されるホストのメトリックを収集します。これらのメトリックのほとんどは、vCPU、メモリ、ネットワーク、ディスク (コンテナではなくホストマシン)、ハードウェア統計などの低レベルオペレーティングシステムのメトリックです。AWS はホストマシンの状態に責任があるため、Fargate のお客様はこれらのメトリックにアクセスできません。

Fargate で実行されているポッドのパフォーマンスを測定するには、vCPU、メモリ使用量、ネットワーク転送などのメトリックが必要です。Prometheus は、cAdvisor と kube-state-metrics の 2 つのソースからこれらのメトリックを収集します。

cAdvisor

cAdvisor (コンテナアドバイザーの略) は、ノードで実行中のコンテナでのリソース使用量とパフォーマンスデータを分析して公開します。Kubernetes では、cAdvisor が Kubelet バイナリの一部として実行されます。kubectl を使用して、cAdvisor によって生成されたメトリックを表示できます。

kubectl get —raw /api/v1/nodes/[NAME-OF-A-NODE]/proxy/metrics/cadvisor

cAdvisor は、ポッドがリソースをどのように使用しているかを理解するのに役立つノードとポッドの使用統計を提供します。公開するメトリックは次のとおりです。

cadvisor_version_info  -- カーネルバージョン、OS バージョン、Docker バージョン、cadvisor バージョン、cadvisor リビジョンでラベル付けされた定数「1」の値を持つメトリック。
container_cpu_load_average_10s  -- 直近 10 秒間のコンテナ CPU 負荷の平均値。
container_cpu_system_seconds_total  -- 使用された累積システム CPU 時間 (秒単位)。
*container_cpu_usage_seconds_total  -- 使用された累積 CPU 時間 (秒単位)。*
container_cpu_user_seconds_total  -- 使用された累積ユーザー CPU 時間 (秒単位)。
container_fs_inodes_free  -- 利用可能な i ノードの数
container_fs_inodes_total  -- i ノードの数
container_fs_io_current  -- 現在進行中の I/O 数
container_fs_io_time_seconds_total  -- I/O の実行に費やされた累積秒数
container_fs_io_time_weighted_seconds_total  -- 累積加重 I/O 時間 (秒単位)
container_fs_limit_bytes  -- このファイルシステム上のコンテナが使用できるバイト数。
container_fs_read_seconds_total  -- 読み取りに費やされた累積秒数
container_fs_reads_bytes_total  -- 読み込まれた累積バイト数
container_fs_reads_merged_total  -- マージされた読み取りの累積数
container_fs_reads_total  -- 完了した読み取りの累積数
container_fs_sector_reads_total  -- 完了したセクター読み取りの累積数
container_fs_sector_writes_total  -- 完了したセクター書き込みの累積数
container_fs_usage_bytes  -- このファイルシステムのコンテナによって使用されるバイト数。
container_fs_write_seconds_total  -- 書き込みに費やされた累積秒数
container_fs_writes_bytes_total  -- 書き込まれたバイトの累積数
container_fs_writes_merged_total  -- マージされた書き込みの累積数
container_fs_writes_total  -- 完了した書き込みの累積数
container_last_seen  -- exporter がコンテナを最後に見た時刻
container_memory_cache  -- ページキャッシュメモリのバイト数。
container_memory_failcnt  -- メモリ使用量のヒット制限
container_memory_failures_total  -- メモリ割り当てエラーの累積数。
container_memory_mapped_file  -- メモリマップファイルのサイズ (バイト単位)。
*container_memory_max_usage_bytes  -- 記録された最大メモリ使用量 (バイト単位)*
container_memory_rss  -- RSS のサイズ (バイト単位)。
container_memory_swap  -- コンテナのスワップ使用量 (バイト)。
container_memory_usage_bytes  -- アクセスされたタイミングに関係なく、すべてのメモリを含む現在のメモリ使用量 (バイト単位)
container_memory_working_set_bytes  -- 現在のワーキングセット (バイト単位)。
*container_network_receive_bytes_total  -- 受信したバイトの累積数*
container_network_receive_errors_total  -- 受信中に発生したエラーの累積数
container_network_receive_packets_dropped_total  -- 受信中にドロップされたパケットの累積数
container_network_receive_packets_total  -- 受信したパケットの累積数
*container_network_transmit_bytes_total  -- 送信されたバイトの累積数*
container_network_transmit_errors_total  -- 送信中に発生したエラーの累積数
container_network_transmit_packets_dropped_total  -- 送信中にドロップされたパケットの累積数
container_network_transmit_packets_total  -- 送信されたパケットの累積数
container_scrape_error  -- コンテナメトリックの取得中にエラーが発生した場合は 1、それ以外の場合は 0
container_spec_cpu_period  -- コンテナの CPU 期間。
container_spec_cpu_shares  -- コンテナの CPU シェア。
container_spec_memory_limit_bytes  -- コンテナのメモリ制限。
container_spec_memory_reservation_limit_bytes  -- コンテナのメモリ予約制限。
container_spec_memory_swap_limit_bytes  -- コンテナのメモリスワップ制限。
container_start_time_seconds  -- UNIX エポック以降のコンテナ開始時刻 (秒単位)。
container_tasks_state  -- 特定の状態のタスク数
machine_cpu_cores  -- マシン上の CPU コア数。
machine_memory_bytes  -- マシンにインストールされているメモリの量。

cAdvisor は、ノードの合計 CPU とメモリも公開します。たとえば、Fargate でポッドをスケジュールし、200 m の vCPU をリクエストしました。

kubectl get --raw /api/v1/nodes/fargate-ip-192-168-102-240.us-east-2.compute.internal/proxy/metrics/cadvisor
...
machine_cpu_cores 2
machine_memory_bytes 4.134506496e+09

メトリックに反映されているように、ポッドを実行する Fargate ノードには 2 つの vCPU と 4GiB RAM があります。この場合、少し混乱することになります。

ノードには 2 vCPU と 4 GiB RAM がありますが、ポッドは 200 m (または、リクエストが構成されていない場合は 0.25 vCPU、0.5 GiB RAM) に制限されています。Farpod ノードの残りの未使用容量ではなく、ポッドが使用するリソースに対して請求が行われます。

Fargate が Firecracker microVM を使用すると、microVM のコンピューティングリソースは、Fargate で実行されているポッドの要件にぴったり一致します。お客様はそれまで Fargate ノードのコストについて責任を負いませんが、未使用の容量が表示されることを期待する必要があります。

ポッドの監視を目的としたほとんどの Grafana ダッシュボードは、cAdvisor によって生成された以下のメトリックを使用します。

  • container_cpu_usage_seconds_total
  • container_memory_usage_bytes
  • container_network_*_bytes_total

ポッドの使用状況を監視するためのいくつかの Grafana ダッシュボードは cAdvisor メトリックのみに基づいていますが、kube-state-metrics などの他のソースからのメトリックを組み合わせるものもあります。

kube-state-metrics

kube-state-metrics は、Kubernetes API サーバーのリッスンとメトリックの生成を担当するオープンソースプロジェクトです。Kubernetes サービスを作成し、Prometheus テキスト形式でメトリックを公開します。次のリソースのメトリックを収集します。

  • nodes
  • pods
  • replicationcontrollers
  • services
  • endpoints
  • namespaces
  • limitranges
  • resourcequotas
  • persistentvolumes
  • persistentvolumeclaims
  • configmaps
  • secrets

ポート 8080 でリッスンするサービスを作成し、kubectl を使用して、公開するすべてのメトリックを確認できます。

kubectl get --raw /api/v1/namespaces/prometheus/services/prometheus-kube-state-metrics:8080/proxy/metrics

ポッドモニタリングの Grafana ダッシュボードは通常、kube-state-metrics を使用して、ポッドのコンピューティングリソースのリクエストと制限を決定します。関連するメトリックは次のとおりです。

  • kube_pod_container_resource_requests — コンテナによってリクエストされたリクエストリソース数。
  • kube_pod_container_resource_requests_cpu_cores — コンテナによってリクエストされた CPU コア数。
  • kube_pod_container_resource_limits_cpu_cores — コンテナが使用する CPU コアの制限。Fargate では CPU 制限が無視されます
  • kube_pod_container_resource_requests_memory_bytes — コンテナによってリクエストされたメモリバイト数
  • kube_pod_container_resource_limits_memory_bytes — コンテナが使用するメモリの制限 (バイト単位)。Fargate ではメモリ制限が無視されます

Prometheus は、cAdvisor と kube-state-metrics から収集されたデータを組み合わせることにより、全体像を提供します。Fargate で実行されているポッドを監視するために役立つ Grafana ダッシュボードをいくつか見てみましょう。

チュートリアル

Prometheus と Grafana のセットアップについて説明します。既に Prometheus と Grafana を使用している場合は、チュートリアルをスキップできます。

EKS クラスターを作成し、Prometheus と Grafana をインストールします。Prometheus はデータを保存するために永続的なボリュームを必要とし、Fargate 上の EKS は現在永続的なストレージをサポートしていないため、クラスターには EC2 によってサポートされるワーカーノードが必要です。prometheus 名前空間のすべてのポッドが EC2 で実行されます。

Fargate でポッドをスケジュールする前に、起動時に Fargate を使用するポッドを指定する Fargate プロファイルを定義する必要があります。

Fargate プロファイルを使用すると、管理者は Fargate で実行するポッドを宣言できます。この宣言は、プロファイルのセレクタを介して行われます。各プロファイルには、名前空間とオプションのラベルを含む最大 5 つのセレクタを含めることができます。すべてのセレクタに名前空間を定義する必要があります。ラベルフィールドは、複数のオプションのキーと値のペアで構成されます。(セレクタの名前空間とセレクタで指定されたすべてのラベルを一致させることにより) セレクタに一致するポッドは、Fargate でスケジュールされます。名前空間セレクタがラベルなしで定義されている場合、Amazon EKS はプロファイルを使用して、その名前空間で実行されるすべてのポッドを Fargate にスケジュールしようとします。スケジュール対象のポッドが Fargate プロファイルのセレクタのいずれかに一致する場合、そのポッドは Fargate でスケジュールされます。

既存の EKS クラスターの eksctl を使用して Fargate プロファイルを作成できます。このチュートリアルでは、eksctl を使用して、Fargate プロファイルを持つ新しい EKS クラスターを作成します。デフォルトおよび kube-system 名前空間で定義されたすべてのポッドは、Fargate で実行されます。

アーキテクチャ

クラスターの構築:

EKS クラスターがない場合は、eksctl を使用して作成できます。eksctl を使用して、Fargate のデフォルトの名前空間と kube-system 名前空間ですべてのポッドを実行するクラスターを作成できます。

eksctl create cluster --fargate

eksctl を使用して、Prometheus の実行に必要なノードグループを作成することもできます。

eksctl create nodegroup --cluster=<clusterName> 

Prometheus のインストール

まず、Prometheus の名前空間を作成します。

kubectl create namespace prometheus

Helm を使い、stable/prometheus チャートを使用して Prometheus をインストールします。Helm をインストールしていない場合は、Amazon EKS での Helm の使用をご覧ください。

prometheus-storageclass.yaml ファイルを作成し、次の内容を含めます。

kind: StorageClass
apiVersion: storage.k8s.io/v1
metadata:
  name: prometheus
  namespace: prometheus
provisioner: kubernetes.io/aws-ebs
parameters:
  type: gp2
reclaimPolicy: Retain
mountOptions:
  debug

ストレージクラスを作成します。

kubectl apply -f prometheus-storageclass.yaml

次に、2 つの永続的なボリュームクレームを作成します。

  1. Prometheus-Server – 16.0 GiB
  2. Prometheus-alertmanager – 4.0 GiB

prometheus_values.yml ファイルをダウンロードします。

wget https://raw.githubusercontent.com/jonnalagadda35153/EKS-Fargate/master/EKS_Fargate_Monitoring/Monitoring/prometheus_values.yml

Prometheus をインストールします。

helm install prometheus -f prometheus_values.yml \
stable/prometheus --namespace prometheus

出力は次のようになります。

Prometheus は ClusterIP タイプのサービスとして実行されます。

Grafana のインストール

Helm を使用して Grafana をインストールします。grafana-values.yml をダウンロードします。

wget https://raw.githubusercontent.com/jonnalagadda35153/EKS-Fargate/master/EKS_Fargate_Monitoring/Monitoring/grafana-values.yaml

Grafana をインストールします。

helm install grafana -f grafana-values.yaml \
stable/grafana ——namespace prometheus

Grafana をインストールし、LoadBalancer サービスを作成します。

ロードバランサーの DNS 名を使用して Grafana にアクセスできます。

ユーザー名: admin
パスワードは次のコマンドで取得できます。

kubectl get secret --namespace prometheus grafana \
 -o jsonpath="{.data.admin-password}" | \
 base64 --decode ; echo

サンプルダッシュボード 7249 をインストールします。

このダッシュボードは、Prometheus メトリックに基づいてデプロイされたワークロードのクラスターレベルの概要を提供します。

Fargate で実行中のポッドがある場合は、ダッシュボードに表示されます。ポッドがない場合は、次のようなポッドを作成できます。

次のコマンドを使用してサンプルアプリケーションをデプロイします。

kubectl apply -f https://github.com/jonnalagadda35153/EKS-Fargate/raw/master/EKS_Fargate_Monitoring/Monitoring/sampleapp.yaml

結果は次のようになります。

ng/sampleapp.yaml
service/appf created
deployment.apps/appf created
ingress.extensions/appf created
horizontalpodautoscaler.autoscaling/appf created

$ kubectl get pods 
NAME READY STATUS RESTARTS AGE
appf-5cc9c4655-gfm8r 0/1 Pending 0 7s
appf-5cc9c4655-nk97x 0/1 Pending 0 7s
appf-5cc9c4655-vtwpn 0/1 Pending 0 7s

この設定により、図のようにポッドのメモリ使用量を監視できます。

同様に、CPU 使用率は次のように計算できます。

リクエストに対する CPU とメモリの使用状況を追跡するために、Grafana ダッシュボード 12421 を作成しました。

CPU 使用率の計算に使用する式は次のとおりです。

sum(rate(container_cpu_usage_seconds_total[5m])) 
/ sum(kube_pod_container_resource_requests{resouce="cpu"}) * 100

メモリ使用量の計算式は次のとおりです。

sum(container_memory_working_set_bytes) 
/ sum(kube_pod_container_resource_requests{resource="memory"}) * 100

構文が読みやすく変更されました。

ダッシュボードの現在のバージョンでは、initContainers のリクエストは考慮されていません。これは、kube-state-metrics が initContainers によってリクエストされたリソースを公開しないのが原因です。

長期実行コンテナのいずれもリソースを要求しない場合、グラフのリクエストメトリックは存在しません。リクエストメトリックを、ポッドが自由に使用できる CPU とメモリの合計と混同しないでください。上記で説明したように、ポッドの CPU とメモリは、計算されたポッドの Fargate 構成によって決まります。

ポッドモニタリングダッシュボードで使用されるいくつかの一般的なメトリックとメトリックのソースは次のとおりです。

  • kube_pod_info [kube-state-metrics]
  • kube_pod_status_phase [kube-state-metrics]
  • kube_pod_container_status_restarts_total [kube-state-metrics]
  • CPU
    • container_cpu_usage_seconds_total [cAdvisor]
    • kube_pod_container_resource_requests_cpu_cores [kube-state-metrics]
  • メモリ
    • container_memory_working_set_bytes [cAdvisor]
    • kube_pod_container_resource_requests_memory_bytes [kube-state-metrics]
    • kube_pod_container_resource_limits_memory_bytes [kube-state-metrics]
  • ネットワーク
    • container_network_transmit_bytes_total [cAdvisor]
    • container_network_receive_bytes_total [cAdvisor]

まとめ

示されているように、Fargate で node-exporter を DaemonSet として実行できないことによって、Fargate で実行されている Kubernetes ワークロードを監視する機能を妨げることはありません。Fargate でポッドを監視するには、cAdvisor によって提供されるメトリックと kube-state-metrics で十分です。

Fargate では、コンテナにリクエストを実装することが重要です。実装しない場合、Fargate のデフォルトの構成プロファイルが取得され、アプリケーションのパフォーマンスを正しく測定できなくなります。

Michael Fischer の Grafana ダッシュボードで EKS コントロールプレーンのパフォーマンスを監視することもできます。

参考文献

Amazon CloudWatch での Prometheus メトリクスの使用
EKS ワークショップ — Prometheus と Grafana のデプロイチュートリアル

Jaswanth Kumar Jonnalagadda

Jaswanth Kumar Jonnalagadda

Jaswanth Kumar は、アマゾン ウェブ サービスのアプリケーションアーキテクトです。彼は、AWS のお客様が AWS コンテナサービスを使用して、スケーラブルで安全なアプリケーションを設計するのを支援しています。彼はニューヨークを拠点としています。
@jjonna