Prometheusのlabel_replaceを使ってラベルの変換を行う

kameneko
penguin-lab
Published in
12 min readApr 1, 2020

Prometheusには様々な関数が存在しますが、その中でも異色を放っている関数として label_replace があります。
この関数は、PromQL中に任意のラベルの値を別名としてラベルを作成することができるクエリです。今回は、こちらを簡単にご紹介します🙋

なお、公式のドキュメントはこちらですので併せてお読みいただければ!

label_replaceを使う理由

label_replace は、通常存在しないラベルを作成する関数です。正しくは、指定したラベルの値を正規表現で変換し、別名として作成します。

label_replace を使うケースは少なく、特殊なケースが多いでしょう。また、 label_replace を使う場合は、Scrape時の relabel_configs で対応できないか検討しましょう。こちらのほうがシンプルに構成することができます。 relabel_configs を使う場合は、以下の様に書きます。

relabel_configs:
- source_labels: [job, instance]
separator: ;
regex: (.*);(.*)
replacement: ${1}/${2}
target_label: job_instance

逆に、label_replace を使うべきケースとして次の理由が挙げられます。

  • クエリ用に一時的に任意のラベルを生成したい
  • Targetではなく、Exporterのメトリクスに付与されたラベルを使用したい場合

1つ目はそのままで、わざわざ relabel_configs をいじるほどではなく、一時的に使いたい場合が該当します。問題は2つ目です。通常、Prometheusが扱うターゲットに各種ラベルを付与しますが、いくつかのExporterはそのターゲットではなく、ターゲット(Exporter)が収集したメトリクスにラベルを付与することがあります。

具体的には、 sakuracloud_exporter がまさにそれで、このExporterは /metrics にアクセスするとさくらのクラウドのAPIを叩き、クラウド上のインスタンスの情報を収集します。その際、インスタンスのタグやハイパーバイザーのホスト情報などをメトリクスに付与します。
このため、 relabel_configs を使ってラベルを取得することができません。こういった場合は、 label_replaceを使ってラベルを生成します。( metrics_relabel_configs で解決できるかもしれないけど、書いてる途中で思い出したので検証していないです

label_replaceの使い方

label_replaceの書き方

label_replace は以下のように書きます。とっつきにくいですが、難しくはありません。

label_replace( [METRICS_NAME], [CONVERSION_LABEL_NAME], [REGEX_MATCH], [FROM_LABEL_NAME], [REGEX])
  • METRICS_NAME :
    対象ラベルが含まれるメトリクス名を指定します。prometheus_build_info とか node_memory_active_bytes など。また、単にメトリクス名だけに限らず、 promethues_build_info{job="prometheus-k8s"} のようにラベルを指定する事もできます。
  • CONVERSION_LABEL_NAME :
    変換後のラベル名を指定します。 relabel_configs での target_label と同様です。ダブルクォーテーション( " )で括ります。
  • REGEX_MATCH :
    後述する正規表現で抽出された結果を元に、ラベルの値を指定します。 ${1} などや任意の文字列を組み合わせることができます。relabel_configs での replacement と同様です。ダブルクォーテーション( " )で括ります。
  • FROM_LABEL_NAME :
    変換元のラベル名を指定します。relabel_configs での source_labels と同様です。ダブルクォーテーション( " )で括ります。
  • REGEX:
    FROM_LABEL_NAME で指定したラベルの値に対する正規表現を指定します。また、 () を使ってマッチング変数を利用できます。relabel_configs での regex と同様です。ダブルクォーテーション( " )で括ります。

例えば、 prometheus_build_infoinstance からIPアドレスを抜き出す場合は以下のようにします。まずはメトリクスをそのまま実行した場合

#Query
prometheus_build_info
# Result
prometheus_build_info{app="prometheus-k8s",branch="HEAD",endpoint="web",goversion="go1.12.5",instance="10.233.104.43:9090",job="prometheus-k8s",namespace="monitoring",pod="prometheus-k8s-1",revision="d20e84d0fb64aff2f62a977adc8cfb656da4e286",service="prometheus-k8s",version="2.10.0"} 1

続いて、 label_replace を利用した場合。分かりづらいですが、 ip=10.233.104.43 が変換されています。あとは、通常のラベルと同様に利用できます。

#Query
label_replace(prometheus_build_info, "ip", "${1}", "instance", "(.*):\\d*")
# Result
prometheus_build_info{app="prometheus-k8s",branch="HEAD",endpoint="web",goversion="go1.12.5",instance="10.233.104.43:9090",ip="10.233.104.43",job="prometheus-k8s",namespace="monitoring",pod="prometheus-k8s-1",revision="d20e84d0fb64aff2f62a977adc8cfb656da4e286",service="prometheus-k8s",version="2.10.0"} 1

さくらのクラウドのサーバのタグの値を変換してみる

使用するメトリクス

今回は、 sakuracloud_exporter の以下のサンプルを使用します。

# Query
sakuracloud_server_info
# Result
sakuracloud_server_info{
app="sakuracloud-exporter",cpus="2",disks="1",host="sac-is1b-sv541",id="114444129751",instance="10.233.75.89:9542",job="sakuracloud-exporter",memories="4",name="k8s-node01",namespace="monitoring",nics="1",tags=",@auto-reboot,@cluster=k8s-cluster,@group=a,@instance-type=master,@ssh_user=ubuntu",zone="is1b"
} 1
sakuracloud_server_info{
app="sakuracloud-exporter",cpus="4",disks="1",host="sac-is1b-sv460",id="113244123758",instance="10.233.75.89:9542",job="sakuracloud-exporter",memories="8",name="k8s-node02",namespace="monitoring",nics="1",tags=",@auto-reboot,@cluster=k8s-cluster,@group=c,@instance-type=worker,@ssh_user=ubuntu",zone="is1b"
} 1

※簡易化のために一部のラベルを削除しています。

さくらのクラウドには、「タグ」を指定することができるのですが、この中に instance-type を指定しました。このままでは tags ラベルに含まれてしまい、そのままでは使いづらいので、これを別名として変換します。

さらに、最終的にインスタンスタイプ別にハイパーバイザーのホストを抽出してみます。

実践してみる

まずは、変換するクエリです。以下の通り instanceType が変化されました。 tags ラベルの中には、複数のタグが含まれるため、 regex.*@instance-type=(\\w*),.* と指定しました。 @instance-type= 以降の文字列を変数に格納しています。

なお、文字列を指定するための正規表現 \w はそのままでは利用できないので、 \\w としてバックスラッシュをエスケープする必要があります。

# Query
label_replace(
sakuracloud_server_info,
"instanceType",
"${1}",
"tags",
".*@instance-type=(\\w*),.*"
)
# Result
sakuracloud_server_info{
app="sakuracloud-exporter",cpus="2",disks="1",host="sac-is1b-sv541",id="114444129751",instance="10.233.75.89:9542",instanceType="master",job="sakuracloud-exporter",memories="4",name="k8s-node01",namespace="monitoring",nics="1",tags=",@auto-reboot,@cluster=k8s-cluster,@group=a,@instance-type=master,@ssh_user=ubuntu",zone="is1b"
} 1
sakuracloud_server_info{
app="sakuracloud-exporter",cpus="4",disks="1",host="sac-is1b-sv460",id="113244123758",instance="10.233.75.89:9542",instanceType="worker",job="sakuracloud-exporter",memories="8",name="k8s-node02",namespace="monitoring",nics="1",tags=",@auto-reboot,@cluster=k8s-cluster,@group=c,@instance-type=worker,@ssh_user=ubuntu",zone="is1b"
} 1

さらに、取得したサンプルを使って、ホスト・InstanceType別に集計してみます。こうすることで、InstanceTypeごとのハイパーバイザーの重複を確認することができます。

# Query
sum(
label_replace(
sakuracloud_server_info,
"instanceType",
"${1}", "tags",
".*@instance-type=(\\w*),.*")
)
by (host, instanceType)
# Result
{host="sac-is1b-sv460",instanceType="worker"} 1
{host="sac-is1b-sv541",instanceType="master"} 1

Valueの値が、該当のホストに乗っているインスタンスの数になりますので、アラートなどで仕込む場合はこれが1を超えているものを指定すればOKです。以下のように。

# Query
sum(
label_replace(
sakuracloud_server_info,
"instanceType",
"${1}", "tags",
".*@instance-type=(\\w*),.*")
)
by (host, instanceType) > 1

終わりに

label_replace を使うことで、任意のラベルの値を別名として正規表現を使って変換することができました。とても便利ではありますが、クエリが複雑になるため出来るだけ利用は控えると良いと思います。

--

--

kameneko
penguin-lab

PrometheusとかKubernetesとか物理、配信とかが好きなしがないエンジニアです。さくらインターネットという会社であれこれしています。ペンギンがとても、とても好き。