入門Prometheus
まずはおうちk8sにPrometheusを構築する
環境
- k8s server: ubuntu 20.04
- k8s version: 1.24
kube-prometheus
Prometheus, Grafana, node-exporter, kube-state-metrics全部入りのkube-prometheusを使う
インストールは QuickStart の通りCRDとmanifestをapplyする
❯❯❯ kubectl apply --server-side -f manifests/setup
❯❯❯ kubectl wait \ ⎈ (kubernetes-admin@kubernetes/default)
--for condition=Established \
--all CustomResourceDefinition \
--namespace=monitoring
kubectl apply -f manifests/
UIへのアクセス
Ingressがない場合はport-forwardでアクセスする
- prometheus
kubectl --namespace monitoring port-forward svc/prometheus-k8s 9090
- Grafana
kubectl --namespace monitoring port-forward svc/grafana 3000
- Alert Manager
kubectl --namespace monitoring port-forward svc/alertmanager-main 9093
Metrics
Prometheusは4種類をサポートする
- Coutner
- リクエスト数など単調増加するメトリクス向け
- 気温やメモリ使用量など 減少する値 には使えない
- Gauge
- 任意に増減できるメトリクス
- 気温やメモリ使用量などに使える
- Histogram
- 分位数のメトリクス
- レイテンシなどエンドユーザの体感を推測する時に使う
- イベントの内,上位x%が一定の数値に収まっていることを表現する
- Summary
- 任意の数をインクリメントできるメトリクス
- レイテンシなど,時間の差分を知りたい時に使う
- Counterはイベントなど1刻みで増える場合に使う
- <summary>_countでイベントの回数,<summary>_sumである時点の合計値を表す
曖昧なメトリクスの意味
メトリクスは文脈によって別のものを意味することがある.
メトリクスの集合であるメトリクスファミリや,親子関係で言う子,時系列データのどれかを意味する.
何を計測するべきか
オンライン配信システム
人間や他サービスがレスポンスを待つシステムで,Webサーバやデータベースが当てはまる.
- REDメソッド
- Request Rate
- Errors
- Duration
- (Latency)
オフラインシステム
待っている人,他のサービスが無いシステムでログ処理システムなどがこれに当たる
- USEメソッド
- Utilsation: 使用率
- Saturation: 飽和...キューの待ち行列の長さ
- Error
バッチジョブ
バッチシステムがこれに当たる.継続的に実行するオフラインシステムとの違いは定期処理として実行される.
スクレイピングは役に立たないので,Pushgatewayなどのテクニックを使い,処理が終了した時にメトリクスを記録する.
PushGateway
バッチジョブのような定期実行される処理は,一般にPrometheusの実行間隔よりライフサイクルが短い.
そこで,バッチ処理より長生きするPushGatewayというキャッシュにメトリクスを保存する.
PrometheusはPushGatewayをスクレイプすれば,ジョブのメトリクスを取得できる.
BacthJob -(push)-> Pushgateway <-(scrape)- Promtheus
ラベル
メトリクスに付けられるK-V形式のメタ情報
アプリケーションやライブラリが自ら付ける インストルメーションラベル と,Prometheusが計測対象のまとまりに対して付ける ターゲットラベル の2つに分類される.
- インストルメーションラベル
- HTTPリクエストのタイプ,データベースの名前
- ターゲットラベル
- アプリケーション,リージョン,チーム
Node Exporter
メトリクスを開示するコンポーネント
- OSカーネルが開示するCPU,メモリ,ディスクスペース,ディスクI/O,ネットワーク帯域幅などを提供する
- WindowsならWMI exporterを使う
取得できるメトリクス
コレクタ | 内容 |
---|---|
cpu | CPUのメトリクス |
filesystem | マウントされているファイルシステムのメトリクス |
diskstask | Disk I/O のメトリクス |
netdev | ネットワークデバイスのメトリクス |
meminfo | メモリ関連のメトリクス |
hwmon | 温度やファンのハードウェア関連のメトリクス |
stat | /proc/stat のメトリクス |
uname | 実行環境のメトリクス |
loadavg | 負荷のメトリクス |
textfile | ユーザ自身が収集するメトリクス |
参考
node-exporterについてるラベル
kubectl get po -A -owide --show-labels | grep node-exporter ⎈ (kubernetes-admin@kubernetes/default)
monitoring node-exporter-676v5 2/2 Running 0 3d2h 192.168.5.110 k8s1 <none> <none> app.kubernetes.io/component=exporter,app.kubernetes.io/name=node-exporter,app.kubernetes.io/part-of=kube-prometheus,app.kubernetes.io/version=1.5.0,controller-revision-hash=5bddcf7c9d,pod-template-generation=1
monitoring node-exporter-nnsq2 2/2 Running 0 3d2h 192.168.5.111 k8s2 <none> <none> app.kubernetes.io/component=exporter,app.kubernetes.io/name=node-exporter,app.kubernetes.io/part-of=kube-prometheus,app.kubernetes.io/version=1.5.0,controller-revision-hash=5bddcf7c9d,pod-template-generation=1
monitoring node-exporter-z544q 2/2 Running 0 3d2h 192.168.5.112 k8s3 <none> <none> app.kubernetes.io/component=exporter,app.kubernetes.io/name=node-exporter,app.kubernetes.io/part-of=kube-prometheus,app.kubernetes.io/version=1.5.0,controller-revision-hash=5bddcf7c9d,pod-template-generation=1
Service Discovery
閑話休題:Prometheus-Operatorの設定方法
今回利用した Prometheus-Operatorは,Operatorがprometheus.yamlを生成する.
ユーザはCRDに対して設定を行い,OperatorはCRDを参照してprometheus.yamlを生成する.
prometheus CRDとservicemonitors CRDから監視するアプリケーションを決定する.
kubectl get prometheus k8s -oyaml | yq .spec ⎈ (kubernetes-admin@kubernetes/monitoring)
alerting:
alertmanagers:
- apiVersion: v2
name: alertmanager-main
namespace: monitoring
port: web
enableFeatures: []
evaluationInterval: 30s
externalLabels: {}
image: quay.io/prometheus/prometheus:v2.41.0
nodeSelector:
kubernetes.io/os: linux
podMetadata:
labels:
app.kubernetes.io/component: prometheus
app.kubernetes.io/instance: k8s
app.kubernetes.io/name: prometheus
app.kubernetes.io/part-of: kube-prometheus
app.kubernetes.io/version: 2.41.0
podMonitorNamespaceSelector: {}
podMonitorSelector: {}
probeNamespaceSelector: {}
probeSelector: {}
replicas: 2
resources:
requests:
memory: 400Mi
ruleNamespaceSelector: {}
ruleSelector: {}
scrapeInterval: 30s
securityContext:
fsGroup: 2000
runAsNonRoot: true
runAsUser: 1000
serviceAccountName: prometheus-k8s
serviceMonitorNamespaceSelector: {}
serviceMonitorSelector: {}
version: 2.41.0
Prometheus-Operatorはendpointオブジェクトから監視対象を列挙する
kubectl get servicemonitors.monitoring.coreos.com ⎈ (kubernetes-admin@kubernetes/monitoring)
NAME AGE
alertmanager-main 3d3h
blackbox-exporter 3d3h
coredns 3d3h
grafana 3d3h
kube-apiserver 3d3h
kube-controller-manager 3d3h
kube-scheduler 3d3h
kube-state-metrics 3d3h
kubelet 3d3h
node-exporter 3d3h
prometheus-adapter 3d3h
prometheus-k8s 3d3h
prometheus-operator 3d3h
kubectl get secret prometheus-k8s -ojsonpath='{.data.prometheus\.yaml\.gz}' | base64 -d | gunzip | yq .scrape_configs[].job_name
serviceMonitor/monitoring/alertmanager-main/0
serviceMonitor/monitoring/alertmanager-main/1
serviceMonitor/monitoring/blackbox-exporter/0
serviceMonitor/monitoring/coredns/0
serviceMonitor/monitoring/grafana/0
serviceMonitor/monitoring/kube-apiserver/0
serviceMonitor/monitoring/kube-controller-manager/0
serviceMonitor/monitoring/kube-scheduler/0
serviceMonitor/monitoring/kube-state-metrics/0
serviceMonitor/monitoring/kube-state-metrics/1
serviceMonitor/monitoring/kubelet/0
serviceMonitor/monitoring/kubelet/1
serviceMonitor/monitoring/kubelet/2
serviceMonitor/monitoring/node-exporter/0
serviceMonitor/monitoring/prometheus-adapter/0
serviceMonitor/monitoring/prometheus-k8s/0
serviceMonitor/monitoring/prometheus-k8s/1
serviceMonitor/monitoring/prometheus-operator/0
列挙したServiceMonitorオブジェクトがsecretの prometheus-<cluster name>
の中で prometheus.yaml
が生成される.
kubectl get secret prometheus-k8s -ojsonpath='{.data.prometheus\.yaml\.gz}' | base64 -d | gunzip | head
global:
evaluation_interval: 30s
scrape_interval: 30s
external_labels:
prometheus: monitoring/k8s
prometheus_replica: $(POD_NAME)
rule_files:
- /etc/prometheus/rules/prometheus-k8s-rulefiles-0/*.yaml
scrape_configs:
- job_name: serviceMonitor/monitoring/alertmanager-main/0
- ```
cAdvisor
cgroupsについてのメトリクスを提供するexporter
cAdvisorをdockerで起動して, localhost:8080/metrics で見れる
docker run \
--volume=/:/rootfs:ro \
--volume=/var/run:/var/run:rw \
--volume=/sys:/sys:ro \
--volume=/var/lib/docker/:/var/lib/docker:ro \
--volume=/dev/disk/:/dev/disk:ro \
--publish=8080:8080 \
--detach=true \
--name=cadvisor \
google/cadvisor:v0.28.3
取得できるメトリクスはcgourpに属するCPUとメモリのメトリクスが取れる
cpu
- ユーザモード,カーネルモード,両者の合計の3つが取れる
memory
①container_memory_cache
ページキャッシュ
②container_memory_rss
常駐セットサイズだが memory-mapped file
は含まないため,プロセスのRSSとは一致しない
-
memor-mapped fileの解説
③container_memory_usage_bytes
①+②
④container_memory_working_set_bytes
は ③ - inactive_file()
(補足)④がOOMで監視されるが,これはカーネルが保持するスラブ・ページキャッシュも保持されているため不正確
プロセスが生成する process_resident_memory_bytes
の方が良いが,公開されていないければ使えない
Sercie Discovery
Prometheusがk8sでサポートするのは次の5種類
- node
- kubernetesのnodeを探す
- endpoints
- Serviceを構成する個々のPodが見える
- service
- ロードバランスが働くので,個々のPodを見るには不向き
- pod
- serviceの一部になっていないPodを見つける
- ingress
- ロードバランサであるため,ブラックボックスモニタリングだけに使うべきである
kube-state-metrics
kubeletなどのアプリケーションが開示するのは自分自身のパフォーマンスの情報で,kubeletが知り得るPod,Deploymentなどのリソースの情報は吐き出さない.
これらのメトリクスは他のエンドポイントから入手するか,適切なexporterを使って入手する.
Kubernetesでは kube-state-metrics がその役割に該当する.
よく使われるexporter
Blackbox exporter
E2Eで監視するときに使える
サポートするプロトコルは多岐に渡る
- ICMP
- TCP
- HTTP
- DNS
他のシステムとの連携
- influxDB
- StatsD
PromQL
Aggergation query
- ゲージ
- 状態のスナップショット
- 用途は合計,平均,最小,最大値を計算するなど
- 増減する
- カウンタ
- イベントの数やサイズ
- 開始からの合計を示す
- 用途はカウンタの時間経過に伴う増分(rate関数を使う)など
- サマリ
- _sum, _count の2つのデータを含み,ともにカウンタである
- ヒストグラム
- 分布を表す
-用途はパーセンタイルの計算など
- 分布を表す
Selctor
metrics_name{key="value"}
で絞り込む
key="value"
の箇所はマッチャと呼ばれる.
メトリクス名は __name__
というラベルで格納されており,process_resident_memory_bytes{job="node"}
は{__name__="process_resident_memory_bytes",job="node"}
として表せる.
インスタントベクトル
最新のサンプルの時系列データのリスト.
範囲ベクトル
一つのサンプルを返すインスタントベクトルに対して,一つの時系列データのためにサンプルを返すことができる.
例えば, container_cpu_user_seconds_total[1m]
は1分未満のすべてのサンプルを返す.
オフセット
container_cpu_user_seconds_total offset 1h
とすると,1時間前のメモリ使用量を返す.
API
PrometheusはAPIからもクエリが引ける
- /api/v1/query
指定された時刻でPromQLを実行して結果を返す
% curl -s http://localhost:9090/api/v1/query\?query=process_resident_memory_bytes ⎈ (kubernetes-admin@kubernetes/monitoring)
{
"status": "success",
"data": {
"resultType": "vector",
"result": [
{
"metric": {
"__name__": "process_resident_memory_bytes",
"container": "alertmanager",
"endpoint": "web",
"instance": "172.16.109.72:9093",
"job": "alertmanager-main",
"namespace": "monitoring",
"pod": "alertmanager-main-1",
"service": "alertmanager-main"
},
"value": [
1680081858.524,
"44109824"
]
},
{
"metric": {
"__name__": "process_resident_memory_bytes",
"container": "alertmanager",
"endpoint": "web",
"instance": "172.16.166.230:9093",
"job": "alertmanager-main",
"namespace": "monitoring",
"pod": "alertmanager-main-2",
"service": "alertmanager-main"
},
"value": [
1680081858.524,
"43188224"
]
},
...
]
}
}
- query_range
範囲ベクトルの指定
集計演算子
PromQL doc 参照
便利そうな関数
-
stddevとstdvar
標準偏差,標準分散 -
topk, bottomk
上位/下位N個の時系列データを返す -
quantile
グループ内の分位数を返す
便利そうな演算子
- bool
process_open_fds > bool 10
のように bool
をつけると,フィルタリングをせずに個々の比較結果を真偽で返す
カウンタ
単調増加するデータ
カウンタで使う関数は引数として範囲ベクトルを取り,インスタントベクトルを返す
- rate()
引数の範囲ベクトルに含まれる個々の時系列データについて,1秒あたりどのくらいのペースで増えているかを返す
カウンタに減少が見られた場合は,リセットと判断する.
[5,10,4,6]
というデータは [5,10,14,16]
と解釈される.
範囲ベクトルの範囲を指定する場合は,スクレイプインターバルの4倍が望ましい.
スクレイプインターバルに対して十分なサンプルが取れなければ,ログデータでデバッグするのが良い.
- irate()
rate()
より単純化され,渡された範囲ベクトルの最後の2個のサンプルしかみていない.
応答が早くなり,スクレイプインターバルの関係をあまり気にしなくて良いが,解像度は落ちて不正確なデータとなる.
また,グラフの変動が激しく,読みづらくなる.
レコーディングルール
PromQL式を定期的に評価させて,その結果をインジェストする.
用途はダッシュボードの高速化など
レコーディングルールのメリット
- 範囲ベクトルの定期評価によるカーディナリティの削減
- 範囲ベクトル関数の入力を中間生成する
-
rate()
関数の出力はインスタントベクトルとなるので,max_over_time()
で扱えないが,レコーディングルールでrate()
を評価しておけば,範囲ベクトルで扱える - sumしてからrateするような処理ではカウンタのリセットや欠損が発生するたびに大きなスパイクが起きる点に注意
- irate, increaseも同じこと
-
ルールの禁じ手
- ラベルの代わりにレコーディングでフィルタすること
- 例えばdeviceラベルが増えるたびにレコーディングルールが作られてしまう
- インターバルを長くする
- 15m -> 1hとすると,Prometheusは1hの中で任意時点で実行することを保証するため直感のタイミングとずれてしまう(1hの最初に実行してほしいが,任意時点となってしまう)
アラート
PrometheusとAlertmanagerのアーキテクチャ
Prometheusで発火したアラートをAlertmanagerが送信先に通知する
このアーキテクチャにより,複数の異なるPrometheusサーバからアラートに基づいて一つの通知を送ることができる.
グルーピングを使えば,複数のPrometheusからのアラートを一つに集約できる
ルールの要素
-
for
一定期間状態が継続したら発火させる -
label
severity
をつけて優先度をつける -
annocation
アラートのサマリなど付加情報を提供する -
external label
PrometheusがAlertmanager,フェデレーション,リモート呼び出し/書き込みで外部システムとやり取りするときに適用されるラベル
通知パイプライン
Alertmanagerが持つ機能は次の通り.
複数のチームで運用するための機能も提供する.
- 抑止
- 他のアラートが発火しているときに,一部のアラートを発火していないものとして扱える機能
- データセンタの障害などの大規模な問題だけで使うようにすべき
- サイレンス
- メンテナンスで発生するアラートは事前にサイレンスを設定しておく
- ルーティング
- `route フィールドで木構造を定義して複数の通知先を設定する
-
severity
などラベルに応じた条件分岐を設定する
- グルーピング
- 一つのルートに送られたすべてのアラートを一つのグループに集約する
-
group_by
でラベルをまとめて集約する
- スロットリングと再送
-
group_wait
でAlertmanagerは最初の通知までにデフォルトで30秒待つ - 30秒が重要な意味を持つなら最初の30秒で自動化できないか を考える契機になる
-
group_interval
はグループで別のアラートが出たときに通知するまでの待ち時間
-
- 通知
-
receiver
で通知先を定義する - テンプレートを使うとカスタマイズが楽になる
- GroupLabels, CommonLabelsなど ref
-
デプロイ
大規模な導入の前に小さく導入するのを推奨する.
推奨はNode exporterとPromtheusの組み合わせから.
以降の導入順序の目安
Node exporter -> Dashboard, Alert -> App/Middle exporter(SNMP, Kafka, Cassandra) -> E2E monitoring -> 組織構造に合わせたアプリケーションのモニタリング,アラートルールの設定
Prometheusのスケーリング
Promtheusはモニタリングの対象と同じネットワークで実行することを想定して作られている.
これはエラーが発生する経路が絞られ,障害ドメインが揃えられ,レイテンシが低く帯域幅広い環境だからである.
複数の組織が使うためには
- ラベルやスクレイプインターバルをカスタマイズを設定してメトリクスやアラートのオーナーを自明にする
- 垂直シャーディングでネットワーク,インフラ,アプリケーションでPrometheusを分割する
- 複数のデータセンタを跨ぐならフェデレーションで集約する
- 水平シャーディング
-
hashmod
で分散させることもできる
-
など組織に合わせた設計が必要になる
長期記憶ストレージ
数年分のメトリクスを取るための設定
-
/api/v1/admin/tsdb/snapshot
エンドポイントでスナップショットを取る - 一部のメトリクスを残し,
/api/v1/admin/tsdb/delete
で定期削除する- start, endパラメータが使える
- 長期保存用ストレージに
remote_write
で書き込む- Prometheusを一次キャッシュ,リモートストレージを永続化ストレージと割り切ることができる
デプロイ先のスペック見積もり
-
rate(prometheus_tsdb_head_samples_append_total[5m])
で1秒にインジェストされるサンプル数を確認できる - 1サンプルで1.3バイト,大きめに2倍としてに圧縮されるため,次の計算で求まる
- 1秒間のサンプル数 x 2 x (606024(1day)) x 保存期間
- RAMは12時間のサンプルを保持できるのが出発点
- クエリの実行中に使われるRAMも考慮が必要
- 1秒あたり10万サンプルなら8GB
- 他にも消費する要素
- ネットワーク
- ファイルディスクリプタ
障害対策
-
クラスタリング
AlertManger間でクラスタリング機能を利用すると,gossip
プロトコルで通知をシステムとして集約できる -
メタモニタリング
Prometheus自身が動作しているかをモニタリングする
パフォーマンス
- コストが高いメトリクスを見つける
カーディナリティが高いメトリクスはtopk
などで見つける.
ただし,すべての時系列データを参照するため非常に高コストになる.
/tsdb-status
の Top 10 series count by metric names
は目安になる
action: hasmod
と drop
を使うと全体のN%にまとめることができる.