スクレイプ設定とリラベリング
目標
Prometheusのスクレイプ設定を、最初から最後まで自分で書き、その設定が実際のクラスターのPodをどう選ぶかを確認します。終わると、他人のprometheus.ymlを見て、どのターゲットが残り、どのメトリクスが捨てられるかを説明できるようになります。
なぜ重要なのか
スクレイプ設定は、Prometheusで唯一「何を見るか」を決める場所です。その後のすべてのクエリとアラートは、ここで残ったデータだけを扱います。リラベルが難しく感じられる理由は、文法ではなく、2つの段階が別の時点で動作することにあります。relabel_configsはスクレイプの前にターゲットの一覧を扱い、metric_relabel_configsはスクレイプのあとに入ってきたメトリクスを扱います。前の段階で捨てたターゲットは、リクエスト自体が出ないのでコストが0で、後の段階で捨てたメトリクスは、すでにネットワークとパースのコストを払ったあとです。この違いが、大規模なクラスターでのPrometheusの生死を分けます。ガードレールも同じ文脈です。sample_limitがなければ、カーディナリティが爆発したサービス1つが、モニタリング全体を止めます。
ステップ
/root/pca-scrape/prometheus.ymlを作成して、globalブロックを書きます。scrape_interval: 15s、evaluation_interval: 30s、scrape_timeout: 10sを設定し、さらにexternal_labelsの下にcluster: homelabを入れます。scrape_configsリストの1つ目の項目にjob_name: prometheus-selfを作成し、metrics_path: /metricsを設定し、static_configsのtargetsにlocalhost:9090を1つだけ入れます。- 2つ目の項目に
job_name: checkout-apiを作成し、scrape_interval: 30s、scrape_timeout: 20s、sample_limit: 20000、label_limit: 24、label_value_length_limit: 256を入れます。 - 3つ目の項目に
job_name: kubernetes-podsを作成し、kubernetes_sd_configsにrole: podを指定してから、namespaces.namesにpca-scrapeだけを入れて、監視の範囲を絞ります。 - 3つ目のジョブの
relabel_configsに、3つのルールを入れます。(a)action: keep、source_labels: [__meta_kubernetes_pod_annotation_prometheus_io_scrape]、regex: "true"(b)action: replace、source_labels: [__meta_kubernetes_pod_ip, __meta_kubernetes_pod_annotation_prometheus_io_port]、target_label: __address__、replacement: '$1:$2'(c)action: replace、source_labels: [__meta_kubernetes_namespace]、target_label: namespace。 - 同じジョブに、
action: labelmap、regex: __meta_kubernetes_pod_label_(.+)のルールを追加し、metric_relabel_configsに2つのルールを入れます。(a)action: drop、source_labels: [__name__]、regex: 'go_gc_duration_seconds.*|python_gc_.*'(b)action: replace、source_labels: [__name__]、regex: 'http_requests_total'、target_label: user_id、replacement: ''。 - ネームスペース
pca-scrapeを作成し、その中にConfigMapprometheus-configを作成します。キー名はprometheus.ymlで、値は今書いたファイルの内容です。 - ネームスペース
pca-scrapeにPodcheckout-apiを作成します。ラベルはapp: checkout-api、アノテーションはprometheus.io/scrape: "true"、prometheus.io/port: "8080"、prometheus.io/path: "/metrics"で、コンテナポートは、名前metricsでcontainerPort: 8080にします。
参考
kubectl create configmap prometheus-config -n pca-scrape --from-file=prometheus.yml=/root/pca-scrape/prometheus.yml- Podは、
kubectl apply -fでマニフェストを適用するほうが、アノテーションを入れやすいです。イメージは何を使ってもかまいません。 - よくある間違い1:
source_labelsを文字列1つで書いてしまうことです。常にリストです。 - よくある間違い2: アノテーションのメタラベル名を、
prometheus.io/scrapeのまま書いてしまうことです。ドットとスラッシュはアンダースコアになります。 - よくある間違い3: ファイルだけを直して、ConfigMapを作り直さないことです。ステップ7の採点は、ConfigMapの中の内容を読みます。
globalブロックを書く
/root/pca-scrape/prometheus.ymlを作成して、globalブロックを書きます。scrape_interval: 15s、evaluation_interval: 30s、scrape_timeout: 10sを設定し、さらにexternal_labelsの下にcluster: homelabを入れます。
prometheus.ymlの最上位のglobalの下に、scrape_interval、evaluation_interval、scrape_timeoutを入れます。external_labelsは、このPrometheusが出力するすべての時系列に付くラベルなので、フェデレーションやリモートストレージで、インスタンスを区別するのに使います。
static_configsのジョブを追加する
scrape_configsリストの1つ目の項目にjob_name: prometheus-selfを作成し、metrics_path: /metricsを設定し、static_configsのtargetsにlocalhost:9090を1つだけ入れます。
scrape_configsはリストです。1つ目の項目に、job_nameとstatic_configsを入れてください。static_configsは、targetsリストを持つ項目のリストなので、角括弧が2回入ります。metrics_pathには既定値がありますが、ここでは明示します。
ガードレールを設定するジョブ
2つ目の項目にjob_name: checkout-apiを作成し、scrape_interval: 30s、scrape_timeout: 20s、sample_limit: 20000、label_limit: 24、label_value_length_limit: 256を入れます。
sample_limitは、1つのターゲットが出すサンプル数の上限で、超えるとそのスクレイプが丸ごと失敗します。label_limitとlabel_value_length_limitも、同じ系統の防御線です。scrape_timeoutはscrape_intervalより大きくできない、という制約を思い出してください。
kubernetes_sdでPodを探す
3つ目の項目にjob_name: kubernetes-podsを作成し、kubernetes_sd_configsにrole: podを指定してから、namespaces.namesにpca-scrapeだけを入れて、監視の範囲を絞ります。
kubernetes_sd_configsもリストです。roleは、node/service/pod/endpoints/endpointslice/ingressのどれかで、Podのコンテナポートを直接スクレイプするにはpodです。namespaces.namesで監視の範囲を絞ると、大規模なクラスターでSDの負荷が大きく減ります。
keepで選び、アドレスを組み立て直す
3つ目のジョブのrelabel_configsに、3つのルールを入れます。(a) action: keep、source_labels: [__meta_kubernetes_pod_annotation_prometheus_io_scrape]、regex: "true" (b) action: replace、source_labels: [__meta_kubernetes_pod_ip, __meta_kubernetes_pod_annotation_prometheus_io_port]、target_label: __address__、replacement: '$1:$2' (c) action: replace、source_labels: [__meta_kubernetes_namespace]、target_label: namespace。
keepは、正規表現にマッチ「しない」ターゲットを捨てます。アノテーションのメタラベル名は、ドットとスラッシュがアンダースコアに変わる、というルールを思い出してください。ソースラベルを2つ使うと、値がセミコロンでつながって正規表現に入ってくるので、replacementでキャプチャグループとして組み立て直します。
labelmapとmetric_relabel_configs
同じジョブに、action: labelmap、regex: __meta_kubernetes_pod_label_(.+)のルールを追加し、metric_relabel_configsに2つのルールを入れます。(a) action: drop、source_labels: [__name__]、regex: 'go_gc_duration_seconds.*|python_gc_.*' (b) action: replace、source_labels: [__name__]、regex: 'http_requests_total'、target_label: user_id、replacement: ''。
relabel_configsはスクレイプの前にターゲットを扱い、metric_relabel_configsはスクレイプのあとにメトリクスを扱います。labeldropはラベル「名」だけを見てマッチして、そのジョブのすべてのメトリクスから消してしまうので、特定のメトリクスからだけ消したいなら、replaceで空の値を入れます。空の値のラベルは、ないラベルと同じです。
設定をConfigMapとして上げる
ネームスペースpca-scrapeを作成し、その中にConfigMapprometheus-configを作成します。キー名はprometheus.ymlで、値は今書いたファイルの内容です。
kubectl create configmapの--from-fileは、키=경로(プレースホルダーはキー名とパスです)の形でキー名を指定できます。ファイルを直したあとは、ConfigMapを作り直さないと反映されません。実際の運用では、config-reloaderサイドカーがこの更新を検知して、Prometheusにリロードをトリガーします。
keepルールが生かすPodを作る
ネームスペースpca-scrapeにPodcheckout-apiを作成します。ラベルはapp: checkout-api、アノテーションはprometheus.io/scrape: "true"、prometheus.io/port: "8080"、prometheus.io/path: "/metrics"で、コンテナポートは、名前metricsでcontainerPort: 8080にします。
前に書いたkeepルールと、__address__の組み立て直しのルールが、このPodを通過させるかを考えながら、アノテーションの値を決めてください。値が文字列のtrueとまったく同じで、ポートのアノテーションの値がコンテナポートと一致する必要があります。labelmapルールが移すPodのラベルも1つ付けます。