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