🔍

k8s内のミドルウェアのメトリクスをOpenTelemetry Collectorで取得

2023/05/19に公開

はじめに

Kubernetesをモニタリングでもするかとなったとき、コンテナで動かしているNginxやRedisなども監視したい!という要望が当然出てくると思います。
そこで問題になるのは、Podは増減してIPアドレスも自動割り振りである点です。
PrometheusだとSidecarでExporterをデプロイしてlocalhostに対してモニタリングしてね、という感じだと思いますが、構成が手間だったりリソースが重複したりと無駄が多かったりします。

OpenTelemetry Collector(Otel Collector)はこの課題を「Receiver Creator」で解決しています。
この記事ではReceiver Creatorは何をしてくれるものか、どう設定するのかを見てきたいと思います。

Otel CollectorのReceiver Creatorとは

簡単に言うと任意のReceiverを動的に構成してくれるReceiverです。
詳細はこちら。
https://github.com/open-telemetry/opentelemetry-collector-contrib/tree/main/receiver/receivercreator

Extensionの「k8s_observer」が指定した条件のエンドポイントを検出し、receiver_creatorがそのエンドポイントに対するReceiverの設定(IPアドレス、ポート)を構成してくれます。

k8s_observer

extensionにはいくつかの「observer」シリーズがあります。
k8s_observerの他にもdocker_observer、host_observerなど。基本的にreceiver_creatorのためのものだと思われます。
今回使うk8s_observerはNodeまたはPodを検出してくれます。

https://github.com/open-telemetry/opentelemetry-collector-contrib/tree/main/extension/observer/k8sobserver

k8s_observerのオプション
extensions:
  k8s_observer:
    auth_type: serviceAccount #k8s APIの認証方法。デフォルト=serviceAccount。
    node: ${env:K8S_NODE_NAME} #探索範囲のNodeの制限。デフォルト=空。
    observe_pods: true #Podの検出。デフォルト=true。
    observe_nodes: true #Nodeの検出。デフォルト=false。

特別な要件がなければデフォルト値でOKだと思います。

extensions:
  k8s_observer:

receiver_creator

receiver_creatorは上記で説明した通りreceiverの自動構成の他、メトリクスにAttributeの付与も可能です。PodのLabelやAnnotationから値を引っ張ることができます。例えばサービス名やチーム名をLabelに入れ込んでいた場合にメトリクスにも付与できたら便利ですね。

receiver_creatorはreceiverの一種なので以下のように構成します。

receiver_creator
receivers:
  receiver_creator:
    watch_observers: [k8s_observer]
    receivers:
      <receiver名>: -- 1
        rule: <observe rule> -- 2
        config: -- 3
          <各receiverのコンフィグ>
        resource_attributes: -- 4
          <attribute>: <attribute string value>
	
    resource_attributes: -- 5
      <pod or port>
        <attribute>: <attribute string value>
	  
  • 1. receiver名
    構成したいreceiver名です。nginxredisなどです。

  • 2. observe rule
    例:rule: type == "port" && port == 80 && pod.name matches "nginx-proxy"
    まずtypeをportpodなど指定し、各typeに応じた条件を指定します。利用可能な条件はGithubをご覧ください。
    上記の例では、ポート80を公開し、pod名にnginx-proxyを含むPodを検出します。
    type=portではpod.labelspod.annotaionspod.namespaceなども使えます。

  • 3. 各receiverのコンフィグ
    構成したいreceiverで指定すべきコンフィグです。
    もしそのreceiverでendpointを指定するようになっている場合、receiver_creatorが検出したIPアドレス、ポート番号を元に自動的に設定してくれます。
    endpoint以外のコンフィグにエンドポイント情報の設定が必要な場合、手動で設定することもできます。
    IPアドレスは`endpoint`、ポート番号は`kubelet_endpoint_port`で取得できます。

  • 4. resource_attributes
    Attributeのキーと値のセットを指定します。
    ruleと同じ書式で値を取れます。type=portでは`pod.labels["label名"]`、`pod.annotations["annotation名"]`などです。

  • 5. receiver_creator.resource_attributes
    receiver_creator.resource_attributesを使うと全てのreceiverにまたがった付与が可能です。

yaml例

上記を組み合わせて、以下のようにすればOKです。nginx receiverで利用可能なコンフィグはendpointcollection_intervalであり、endpointは自動構成、collection_intervalはデフォルト値(10秒)のままにするため、configをまるっと排除しています。

Otel Collector yaml例
extensions:
  k8s_observer:

receivers:
  receiver_creator:
    watch_observers: [k8s_observer]
    receivers:
      nginx:
        rule: type == "port" && port == 80 && pod.name matches "nginx-proxy"
        resource_attributes:
          team: "`pod.labels['service_name']`"

service:
  pipelines:
    metrics:
      receivers: [receiver_creator]
      processors: [<任意のprocessor>]
      exporters: [<任意のexporter>]

試してみる

Splunk Observability Cloudに送ってみたいと思います。
OpenTelemetry CollectorをKubernetes用に色々と整備したSplunk OpenTelemetry Collector for Kubernetesが用意されておりますので、こちらを使います。

詳しくはこちら。
https://zenn.dev/symmr/articles/b7bf8daf6a3282

Splunk Otel for k8sはHelm Chartが用意されておりOtel Collectorの設定もvalues.yamlから行えます。
(通常のOtelを使う場合は最近だとOpenTelemetry Operator for Kubernetesがいいのではないかと思います)
extensions.k8s_observerとpipelineはデフォルトで用意されているので、receiver_creatorのみの設定だけ行えばOKです。

my_values.yamlで設定をまとめます。ついでに他の必須設定も入れておきます。

  • Otel Collectorの設定はagent.config配下で設定できます。
  • smartagent/redissmartagent/nginxはSplunk Otelで用意されているreceiverです。
  • resource_attributesをreceiver_creatorの配下にセットし、共通的にAttribute付与しています。
my_values.yaml
clusterName: <クラスタ名>

splunkObservability:
  realm: <REALM>
  accessToken: <アクセストークン>

agent:
  config:
    receivers:
      receiver_creator:
        receivers:
          smartagent/redis:
            rule: type == "port" && port == 6379 && pod.name matches "redis"
            config:
              type: collectd/redis
          smartagent/nginx:
            rule: type == "port" && port == 80 && pod.name matches "nginx-proxy"
            config:
              type: collectd/nginx
        resource_attributes:
          port:
            k8s.pod.name: "`pod.name`"
            k8s.pod.uid: "`pod.uid`"
            k8s.namespace.name: "`pod.namespace`"
            service_name: "`pod.labels['service_name']`"
            team: "`pod.labels['team']`"

HELMでインストールします。

Splunk Otel for k8sのインストール
helm repo add splunk-otel-collector-chart https://signalfx.github.io/splunk-otel-collector-chart
helm install my-test splunk-otel-collector-chart/splunk-otel-collector -f ./my_values.yaml

Otel collectorのログを確認すると、nginxの方は「"endpoint": "10.244.2.231:80"」が検出できていました。このIPアドレスはPodに割り当てられたものです。

Otel Collectorログ
2023-05-19T11:58:25.628Z        info    receivercreator@v0.76.3/observerhandler.go:101  starting receiver       {"kind": "receiver", "name": "receiver_creator", "data_type": "metrics", "name": "smartagent/nginx", "endpoint": "10.244.2.231:80", "endpoint_id": "k8s_observer/4943d62f-460f-4b87-bd79-ec1b10d233a6/(80)"}

Splunk Observability Cloudを確認すると無事メトリクスが取れておりダッシュボードで表示されました。

Attributeも無事設定されていました。いいですね。

次にnginxのdeploymentのreplica数を1⇒3に変えてみます。
そうするとOtel CollectorもPod増加に伴いreceiver_creatorが新たに2件を検出、メトリクス取得開始してくれました。

2023-05-19T11:59:06.627Z        info    receivercreator@v0.76.3/observerhandler.go:101  starting receiver       {"kind": "receiver", "name": "receiver_creator", "data_type": "metrics", "name": "smartagent/nginx", "endpoint": "10.244.2.233:80", "endpoint_id": "k8s_observer/b41e31ae-9107-436d-a0d1-10d934efe0f4/(80)"}
2023-05-19T11:59:08.627Z        info    receivercreator@v0.76.3/observerhandler.go:101  starting receiver       {"kind": "receiver", "name": "receiver_creator", "data_type": "metrics", "name": "smartagent/nginx", "endpoint": "10.244.2.234:80", "endpoint_id": "k8s_observer/03e4a7f1-79c0-436b-95c8-922ea0a4f325/(80)"}

まとめ

receiver_creatorは初見だとちょっと分かりにくいかもしれませんが、定義を一ヶ所で管理できるのでとても便利だと思います。

Discussion