kashinoki38 blog

something like tech blog

【暫定版】 Kubernetesの性能監視で必要なメトリクス一覧とPrometheusでのHowTo

2021/03/01 追記

記載していたリポジトリにあるマニフェスト系があまりに不親切だったので、ちゃんとまとめてみました。
後日、もうちょっとちゃんと記事書こうとは思いますが、大体はREADMEにあるので読んでみてください。
sock-shopをベースにObservability(Prometheus, Loki, Istio(Jaeger, Kiali))とProgressive Delivery&自動負荷試験スタック(Flagger, Jmeter, influxdb)をHelmとKustomizeで詰め込みました。
今回はちゃんと誰もが入れれるようにがんばってみたので、どうぞ。

github.com

この内容でCloudNativeDaysOnline2021に登壇することにしています。

event.cloudnativedays.jp

後、随分前ではありますが、本投稿に関連してKubernetes meetup tokyo #33で「Kubernetesでの性能解析 ~なんとなく遅いからの脱却~」というタイトルで登壇をしました。

www.slideshare.net


GitHubKubernetesの性能監視で必要なメトリクス一覧をまとめた。
また、それに伴って必要なPrometheusのExporter、それらのmetrics endpointに対するScrapeの方針とyamlのサンプル、GrafanaのダッシュボードJsonもまとめた。
改善余地はまだまだあると思うのでPRやコメント等大歓迎です。

監視すべき項目

監視すべき項目はUSE×REDだと認識している。
それを各コンポーネントの粒度でまとめている。
Cluster, Node, Pod/Container, MW(Java, Go, Nodejs, etc), Kubernetesコンポーネント自体

サービス監視(RED)

  • Rate : =Throughput, 秒間リクエスト数, 秒間 PV 数
  • Error Rate : エラー率, 5xx とか
  • Duration : =ResponseTime, %ile 評価が一般的

リソース監視(USE)http://www.brendangregg.com/usemethod.html

  • Utilization : 使用率 E.g. CPU 使用率
  • Saturation : 飽和度, どれくらいキューに詰まっているか
    E.g. ロードアベレージ
  • Errors : エラーイベントの数

前提条件

以下のバージョンを前提に設定のサンプルは用意している。

  • Kubernetes : v1.16.11-gke.5
  • Istio : 1.4.10-gke.4
  • Prometheus : prom/prometheus:v2.18.0
  • Grafana : grafana/grafana:7.0.1
  • NodeExporter : prom/node-exporter:v1.0.0

メトリクス一覧

以下のGitHubにも同様のReadme.mdをおいてます。 github.com

サービス監視(RED)

Jmeter

Grafana Dashboard

性能試験時のクライアント
Jmeter のメトリクスを収集
BackendListner->InfluxDB->Grafana

Grafana Dashboard

https://github.com/kashinoki38/prometheus-sample-yaml/blob/master/grafana/jmeter-metrics-dashboard.json

メトリクス USE x RED
Throughput R
ResponseTime D
Error% E

システムサイド  Istio Telemet

Istio のテレメトリ機能で各 service のメトリクスを収集

Grafana Dashboard

https://github.com/kashinoki38/prometheus-sample-yaml/blob/master/grafana/Istio-Mesh-Dashboard.json
https://github.com/kashinoki38/prometheus-sample-yaml/blob/master/grafana/Istio-Workload-Dashboard.json
https://github.com/kashinoki38/prometheus-sample-yaml/blob/master/grafana/Istio-Service-dashboard.json

メトリクス USE x RED Prometheus
Throughput R o
ResponseTime D o
Error% E o

システムサイド  Prometheus クライアントライブラリを利用

• 各言語のクライアントライブラリ使って Prometheus にメトリクスとして送る(request_duration_seconds をヒストグラム集計) https://github.com/devopsdemoapps/sockshop/search?q=request_duration_seconds&unscoped_q=request_duration_seconds

Grafana Dashboard

TBD

メトリクス USE x RED Prometheus Grafana Dashboard Prometheus metrics
Throughput request_duration_seconds をヒストグラム集計 R o TBD
ResponseTime D o
Error% E o

OS リソース監視(USE)

クラスタ全体

NodeExporter と cAdvisor にて収集

Grafana Dashboard

https://github.com/kashinoki38/prometheus-sample-yaml/blob/master/grafana/kubernetes-cluster-dashboard.json

メトリクス USE x RED Prometheus
Node Availability ノード全体の稼働率
各ノードの Ready 時間合計/(集計期間 × ノード数)
Availability
Node 数 Availability o
unschedulable Node 数 Availability o
Node の詳細
kubernetes.node.name,各リソース量
Conf o
Pods Availability Available Pods Availability o
Pods status
Running / Pending / Failed / Unknown
Availability o
Container Availability Containers status
Ready / Terminated / Waiting / Running
Availability o
Deployment Count Deployment Count Availability o
StatefulSet Count StatefulSet Count Availability o
DaemonSet Count DaemonSet Count Availability o
Job Count Job Count Availability o
Failed Job Count Availability o

Node

Node Exporter で収集

Grafana Dashboard

https://github.com/kashinoki38/prometheus-sample-yaml/blob/master/grafana/node-exporter-dashboard.json

メトリクス USE x RED Prometheus
Node Availability ノード全体の稼働率
各ノードの Ready 時間合計/(集計期間 × ノード数)
Availability o
Node 数 Availability o
unschedulable Node 数 Availability o
Node の詳細
kubernetes.node.name,各リソース量
Conf o
pods Pods Allocatable Conf o
Pods Capacity Conf o
Pods Allocation o
CPU CPU 使用率 U o
CPU 使用率コアごと U o
ロードアベレージ S o
CPU Core Capacity Conf o
CPU Core Limits Conf o
CPU Core Requests Conf o
CPU Core Allocatable Conf o
メモリ メモリ使用量 U o
スワップイン量 S o
スワップアウト量 S o
スワップ使用率 S o
スワップサイズ S o
Memory Capacity Conf o
Memory Limits Conf o
Memory Requests Conf o
Memory Allocatable Conf o
ディスク ディスクビジー U o
ディスク I/O 待ち数 S o
ディスク I/O 待ち時間 S o
ディスク読込み量 U o
ディスク書込み量 U o
ディスク読込み回数 U o
ディスク書込み回数 U o
パーティション使用率 U o
パーティションサイズ U o
inode 総数/使用率 U o
ネットワーク 送信トラフィック U o
受信トラフィック U o
ポート/Socket U
Drops E o
Errs E o
ping Availability
ファイルディスクリプタ U o
プロセス プロセス数 U
プロセス数(ゾンビ) U
占有プロセス状況(プロセスキューサイズ) U

Pod/Container

cAdvisor にて収集 (Kubelet バイナリに統合されているので scrape の設定のみで OK)

Grafana Dashboard

https://github.com/kashinoki38/prometheus-sample-yaml/blob/master/grafana/pod_detail-dashboard.json

メトリクス USE x RED Prometheus
Pods Availability Available Pods Availability o
Pods Restarts Availability o
Pods status
Running / Pending / Failed / Unknown
Availability o
Container Availability Restarts Availability o
Errors
Terminated Reason
Waiting Reason
Restart Reason
E o
Containers status
Ready / Terminated / Waiting / Running
Availability o
CPU CPU 使用率 U o
ロードアベレージ S o
Throttle S o
CPU Core Limits Conf o
CPU Core Requests Conf o
メモリ メモリ使用量 U o
スワップイン量 S x
スワップアウト量 S x
スワップ使用量 S o
スワップサイズ S x
Memory Limits Conf o
Memory Requests Conf o
ディスク ディスクビジー U o
ディスク I/O 待ち数 S o
ディスク I/O 待ち時間 S o
ディスク読込み量 U o
ディスク書込み量 U o
ディスク読込み回数 U o
ディスク書込み回数 U o
パーティション使用率 U o
パーティションサイズ U
inode 総数/使用率 U o
ネットワーク 送信トラフィック U o
受信トラフィック U o
ポート/Socket U
Drops E o
Errs E o
ping Availability
ファイルディスクリプタ U

Persistent Volume

kubelet の metics エンドポイントから収集

Grafana Dashboard

https://github.com/kashinoki38/prometheus-sample-yaml/blob/master/grafana/pv-dashboard.json

メトリクス USE x RED Prometheus
ファイルシステム ディスク領域使用量 U o
inode 総数/使用率 U o

MW リソース監視

Nginx

Grafana Dashboard

TBD

メトリクス USE x RED Prometheus
コネクション数 Active / Dropped S
スループット request per sec R
HTTP レスポンスコード E
レイテンシ Response Time D
Network bytes

Java (Jetty on SpringBoot)

SpringBoot2 系以降から実装の、Micrometer Actuator を使用
(pom.xml 変更のみで良いはず)

Grafana Dashboard

https://github.com/kashinoki38/prometheus-sample-yaml/blob/master/grafana/jmx-exporter-dashboard.json

メトリクス USE x RED Prometheus
ヒープメモリ 全体ヒープメモリ使用量 U o
Young U o
Old U o
Metaspace U o
Code Cache U o
GC 頻度(Full/Young) S o
時間(Full/Young) S o
レスポンスタイム レスポンスタイム D ?
レスポンスコード レスポンスコード E ?
スレッド数 スレッド数 S o
空きスレッド数 空きスレッド数 Conf ?
スレッドプール使用率 スレッドプール使用率 S ?
コネクションプール使用数 コネクションプール使用数 S ?

Go

golang クライアントライブラリの promhttp を使用
https://github.com/prometheus/client_golang/tree/master/prometheus/promhttp

Grafana Dashboard

https://github.com/kashinoki38/prometheus-sample-yaml/blob/master/grafana/go-process-dashboard.json

メトリクス USE x RED Prometheus
Process Memory U o
Memory Stats U o
Goroutines S o
GC duration S o | ##### Grafana Dashboard

Nodejs

nodejs クライアントライブラリの prom-client を使用
https://github.com/siimon/prom-client

Grafana Dashboard

https://github.com/kashinoki38/prometheus-sample-yaml/blob/master/grafana/nodejs-dashboard.json

メトリクス USE x RED Prometheus
Process Memory U o
Active Handlers S o

MySQL

Grafana Dashboard

mongodb

Grafana Dashboard

Redis

Grafana Dashboard

Kubernetes コンポーネント

kube-api-server

kube-api-server の metrics エンドポイントから収集

Grafana Dashboard

https://github.com/kashinoki38/prometheus-sample-yaml/blob/master/grafana/kube-apiserver-dashboard.json

メトリクス USE x RED Prometheus
API コール REST リクエスト数 R o
API リクエストレイテンシ D o
API リクエストエラー E o
Controller Manager から ワークキューの追加率 o
ワークキューの待ち時間 o
ワークキューの深さ o
etcd から etcd キャッシュエントリ x
etcd キャッシュのヒット/ミス率 x
etcd キャッシュ期間 x
リソース メモリ使用量 o
CPU 使用量 o
Go routine o

kube-controller-manager

Controller manager の metrics エンドポイントから収集
デフォルトでエンドポイントを公開しないコンポーネントの場合、--bind-address フラグを使用して有効にする

Grafana Dashboard

TBD

メトリクス USE x RED Prometheus
インスタンス kube-controller-manager インスタンスの数
ワークキュー情報 ワークキューのレイテンシー
ワークキューレート
ワークキューの深さ
kube-api kube-api リクエストレート
kube-api リクエストレイテンシ
リソース メモリ使用量
CPU 使用量
Go routine

etcd

kube-scheduler の metrics エンドポイントから収集
デフォルトでエンドポイントを公開しないコンポーネントの場合、--bind-address フラグを使用して有効にする

Grafana Dashboard

TBD

メトリクス USE x RED Prometheus
Leader Leader 変更回数
Database 系 DB サイズ
Disk 同期レイテンシ
Disk 操作 (fsync, commit)
Network Client Trafic
Peer Trafic
Raft Proposal
Proposal Committed
Proposal Pending
grpc
snapshot snapshot レイテンシ

Grafana Dashboard

kube-scheduler

Grafana Dashboard

TBD

メトリクス USE x RED Prometheus
Scheduling Scheduling レート
Scheduling レイテンシ
kube-api kube-api リクエストレート
kube-api リクエストレイテンシ
リソース メモリ使用量
CPU 使用量
Go routine
Leader Leader 変更回数

kube-proxy

kube-proxy の metrics エンドポイントから収集
デフォルトでエンドポイントを公開しないコンポーネントの場合、--bind-address フラグを使用して有効にする

Grafana Dashboard

TBD

メトリクス USE x RED Prometheus
Proxy ルール Sync Proxy ルール Sync レート R
Proxy ルール Sync レイテンシ D
Network Programming Network Programming レート R
Network Programming レイテンシ D
kube-api kube-api リクエストレート
kube-api リクエストレイテンシ
リソース メモリ使用量
CPU 使用量
Go routine

kubelet

各ノードの 10255 ポート

Grafana Dashboard

https://github.com/kashinoki38/prometheus-sample-yaml/blob/master/grafana/kubelet-dashboard.json

メトリクス USE x RED Prometheus
インスタンス kubelet インスタンスの数 Availability o
ボリュームの数 Availability o
error error E o
オペレーション 各タイプのランタイムオペレーションの総数 U o
オペレーションのエラーの数
※コンテナランタイムの問題など、ノード内の低レベルの問題を示す良い指標
E o
オペレーションの間隔時間 S o
Pod の管理 ポッドのスタートレートと間隔時間
コンテナのランタイムまたはイメージへのアクセスの問題を示している可能性がある
S o
ポッドスタートオペレーションの数 U o
ストレージ ストレージオペレーション数 U o
ストレージオペレーションエラー E o
ストレージオペレーション時間 S o
Cgroup マネージャ Cgroup マネージャのオペレーション数 U o
Cgroup マネージャのオペレーション時間 S o
ポッドライフサイクルイベントジェネレータ ポッドライフサイクルイベントジェネレーター(PLEG):
relist レート、relist インターバル、relist 間隔時間。これらの値のエラーまたは過度の遅延は、ポッドの Kubernetes ステータスに問題を引き起こす可能性があ
U o

Prometheus

Grafana Dashboard

以下のGitHubにも同様のReadme.mdをおいてます。 github.com

必要な Exporter

Exporter Link
Node Exporter NodeExporter
https://github.com/kashinoki38/microservices-demo/blob/master/deploy/kubernetes/manifests-monitoring/node-exporter-ds.yml
kube-state-metrics kube-state-metrics
https://github.com/kubernetes/kube-state-metrics/tree/master/docs

各 Exporter に対する Scrape 方針

Exporter Scrape Target Endpoint Scrape Config Sample の job name
cadvisor apiserver の以下 metrics パス
https://kubernetes.default.svc:443/api/v1/nodes/gke-cn-horiuchiysh-s-cn-horiuchiysh-s-2b141725-5coq/proxy/metrics/cadvisor
kubernetes-cadvisor
NodeExporter 各 pod のコンテナポートの/metrics へ投げる
nodexporter/metrics
kubernetes-pods
go 各 pod のコンテナポートの/metrics へ投げる
go/metrics
kubernetes-service-endpoints
nodejs 各 pod のコンテナポートの/metrics へ投げる
nodejs/metrics
kubernetes-service-endpoints
mongodb 各 pod のコンテナポートの/metrics へ投げる
mongodb/metrics
kubernetes-pods
Istio Mesh istio-telemetry サービスの endpoint port name が prometheus
http://10.48.2.14:42422/metrics
istio-mesh
kubelet 各ノードの 10255 ポート
http://10.30.3.20:10255/metrics10255
kubernetes-nodes
kube-apiserver default namespace に api server 向けの svc と endpoint がある
https://104.198.95.200:443/metrics
kubernetes-service-endpoints
kube-state-metrics 各サービスの/metrics へ投げる
http://kube-state-metrics:8080/metrics
kubernetes-service-endpoints
prove /api/v1/nodes/gke-cn-horiuchiysh-s-cn-horiuchiysh-s-2b141725-5coq/proxy/metrics/probes
ベット job が必要
kube-controll-manager デフォルトでエンドポイントを公開しないコンポーネントの場合、--bind-address フラグを使用して有効にする
/metrics
kube-proxy デフォルトでエンドポイントを公開しないコンポーネントの場合、--bind-address フラグを使用して有効にする
/metrics
kube-scheduler デフォルトでエンドポイントを公開しないコンポーネントの場合、--bind-address フラグを使用して有効にする
/metrics

Scrape Config Sample

kubernetes-pods

- job_name: kubernetes-pods
  honor_timestamps: true
  scrape_interval: 15s
  scrape_timeout: 10s
  metrics_path: /metrics
  scheme: http
  kubernetes_sd_configs:
  - role: pod
  relabel_configs:
  - source_labels: [__meta_kubernetes_pod_annotation_prometheus_io_scrape]
    separator: ;
    regex: ""true""
    replacement: $1
    action: keep
  - source_labels: [__meta_kubernetes_pod_node_name]
    separator: ;
    regex: (.*)
    target_label: node
    replacement: $1
    action: replace
  - source_labels: [__meta_kubernetes_namespace]
    separator: ;
    regex: (.*)
    target_label: namespace
    replacement: $1
    action: replace
  - source_labels: [__meta_kubernetes_pod_name]
    separator: ;
    regex: (.*)
    target_label: pod_name
    replacement: $1
    action: replace

kubernetes-nodes

各ノードの 10255 ポート

- job_name: kubernetes-nodes
  honor_timestamps: true
  scrape_interval: 15s
  scrape_timeout: 10s
  metrics_path: /metrics
  scheme: http
  kubernetes_sd_configs:
    - role: node
  bearer_token_file: /var/run/secrets/kubernetes.io/serviceaccount/token
  tls_config:
    insecure_skip_verify: true
  relabel_configs:
    - separator: ;
      regex: (.*)
      target_label: __scheme__
      replacement: https
      action: replace
    - source_labels: [__meta_kubernetes_node_label_kubernetes_io_hostname]
      separator: ;
      regex: (.*)
      target_label: instance
      replacement: $1
      action: replace
    - source_labels: [__address__]
      separator: ;
      regex: ^(.+?)(?::\d+)?$
      target_label: __address__
      replacement: $1:10255
      action: replace

kubernetes-cadvisor

apiserver の以下 metrics パス
/api/v1/nodes/gke-cn-horiuchiysh-s-cn-horiuchiysh-s-2b141725-5coq/proxy/metrics/cadvisor

- job_name: kubernetes-cadvisor
  honor_timestamps: true
  scrape_interval: 15s
  scrape_timeout: 10s
  metrics_path: /metrics
  scheme: https
  kubernetes_sd_configs:
    - role: node
  bearer_token_file: /var/run/secrets/kubernetes.io/serviceaccount/token
  tls_config:
    ca_file: /var/run/secrets/kubernetes.io/serviceaccount/ca.crt
    insecure_skip_verify: false
  relabel_configs:
    - separator: ;
      regex: __meta_kubernetes_node_label_(.+)
      replacement: $1
      action: labelmap
    - separator: ;
      regex: (.*)
      target_label: __address__
      replacement: kubernetes.default.svc:443
      action: replace
    - source_labels: [__meta_kubernetes_node_name]
      separator: ;
      regex: (.+)
      target_label: __metrics_path__
      replacement: /api/v1/nodes/${1}/proxy/metrics/cadvisor
      action: replace

istio-mesh

istio-telemetry サービスの endpoint port name が prometheus の port

- job_name: istio-mesh
  honor_timestamps: true
  scrape_interval: 15s
  scrape_timeout: 10s
  metrics_path: /metrics
  scheme: http
  kubernetes_sd_configs:
    - role: endpoints
      namespaces:
        names:
          - istio-system
  relabel_configs:
    - source_labels:
        [__meta_kubernetes_service_name, __meta_kubernetes_endpoint_port_name]
      separator: ;
      regex: istio-telemetry;prometheus
      replacement: $1
      action: keep

kubernetes-service-endpoints

- job_name: kubernetes-service-endpoints
  honor_timestamps: true
  scrape_interval: 15s
  scrape_timeout: 10s
  metrics_path: /metrics
  scheme: http
  kubernetes_sd_configs:
    - role: endpoints
  bearer_token_file: /var/run/secrets/kubernetes.io/serviceaccount/token
  tls_config:
    ca_file: /var/run/secrets/kubernetes.io/serviceaccount/ca.crt
    insecure_skip_verify: false
  relabel_configs:
    - source_labels: [__meta_kubernetes_service_label_component]
      separator: ;
      regex: apiserver
      target_label: __scheme__
      replacement: https
      action: replace
    - source_labels:
        [__meta_kubernetes_service_label_kubernetes_io_cluster_service]
      separator: ;
      regex: "true"
      replacement: $1
      action: drop
    - source_labels: [__meta_kubernetes_service_annotation_prometheus_io_scrape]
      separator: ;
      regex: "false"
      replacement: $1
      action: drop
    - source_labels: [__meta_kubernetes_pod_container_port_name]
      separator: ;
      regex: .*-noscrape
      replacement: $1
      action: drop
    - source_labels: [__meta_kubernetes_service_annotation_prometheus_io_scheme]
      separator: ;
      regex: ^(https?)$
      target_label: __scheme__
      replacement: $1
      action: replace
    - source_labels: [__meta_kubernetes_service_annotation_prometheus_io_path]
      separator: ;
      regex: ^(.+)$
      target_label: __metrics_path__
      replacement: $1
      action: replace
    - source_labels:
        [__address__, __meta_kubernetes_service_annotation_prometheus_io_port]
      separator: ;
      regex: ^(.+)(?::\d+);(\d+)$
      target_label: __address__
      replacement: $1:$2
      action: replace
    - separator: ;
      regex: ^__meta_kubernetes_service_label_(.+)$
      replacement: $1
      action: labelmap
    - source_labels: [__meta_kubernetes_namespace]
      separator: ;
      regex: (.*)
      target_label: namespace
      replacement: $1
      action: replace
    - source_labels: [__meta_kubernetes_pod_name]
      separator: ;
      regex: (.*)
      target_label: pod_name
      replacement: $1
      action: replace

prometheus.yaml の relabel_config

  • https://prometheus.io/docs/prometheus/latest/configuration/configuration/#relabel_config
  • relabel_configs で取得すべき項目のラベルを作っている

    • source_labels:元ネタ
    • regex正規表現抽出した項目について replace、keep、drop、labelmap、labeldrop,labelkeep でアクションする
    • replace:regex 連結され source_labels たと照合します。次に、設定 target_label に replacement 一致グループの参照(と、${1}、${2}、...)で replacement、その値によって置換されました。regex 一致しない場合、置換は行われません。
      → 一致した部分を target_label に挿入
    • keep:regex 連結に一致しないターゲットをドロップします source_labels。
    • dropregex 連結に一致するターゲットを削除し source_labels ます。
    • hashmod:連結されたハッシュのに設定さ target_label れ modulus ます source_labels。
    • labelmap:regex すべてのラベル名と照合します。その後で与えられたラベル名に一致するラベルの値をコピー replacement 一致グループの参照を(${1}、${2}中、...)replacement その値によって置換されています。
    • labeldrop:regex すべてのラベル名と照合します。一致するラベルは、ラベルのセットから削除されます。
    • labelkeep:regex すべてのラベル名と照合します。一致しないラベルは、ラベルのセットから削除されます。
  • 元ネタには以下のような meta タグを使用する

__meta_kubernetes_namespace: The namespace of the service object.
__meta_kubernetes_service_annotation_<annotationname>: Each annotation from the service object.
__meta_kubernetes_service_annotationpresent_<annotationname>: "true" for each annotation of the service object.
__meta_kubernetes_service_cluster_ip: The cluster IP address of the service. (Does not apply to services of type ExternalName)
__meta_kubernetes_service_external_name: The DNS name of the service. (Applies to services of type ExternalName)
__meta_kubernetes_service_label_<labelname>: Each label from the service object.
__meta_kubernetes_service_labelpresent_<labelname>: true for each label of the service object.
__meta_kubernetes_service_name: The name of the service object.
__meta_kubernetes_service_port_name: Name of the service port for the target.
__meta_kubernetes_service_port_protocol: Protocol of the service port for the target.
__meta_kubernetes_service_type: The type of the service.

検討必要事項

  • メモリを食うので VictoriaMetrics とかで工夫するかメトリクスを減らす必要がある
  • バージョンによって設定項目が変わってしまうので、設定を Code として git 上に残していくことが重要

Jmeter との連携

https://github.com/kubernauts/jmeter-operator