ターゲットアロケーター

OpenTelemetryオペレーター上でターゲットアロケーターのサービスディスカバリーを有効にしていて、ターゲットアロケーターがスクレイプ対象の検出に失敗した場合に、何が起きているのかを理解し、通常の動作を復元するためにいくつかのトラブルシューティング手順を実行できます。

トラブルシューティング手順

すべてのリソースをKubernetesにデプロイしましたか?

最初のステップとして、関連するすべてのリソースがKubernetesクラスターにデプロイされていることを確認してください。

メトリクスは実際にスクレイプされていますか?

すべてのリソースをKubernetesにデプロイしたら、ターゲットアロケーターが ServiceMonitorまたはPodMonitorからスクレイプ対象を検出していることを確認してください。

次のような ServiceMonitor の定義があるとします。

apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
  name: sm-example
  namespace: opentelemetry
  labels:
    app.kubernetes.io/name: py-prometheus-app
    release: prometheus
spec:
  selector:
    matchLabels:
      app: my-app
  namespaceSelector:
    matchNames:
      - opentelemetry
  endpoints:
    - port: prom
      path: /metrics
    - port: py-client-port
      interval: 15s
    - port: py-server-port

これは Service の定義です。

apiVersion: v1
kind: Service
metadata:
  name: py-prometheus-app
  namespace: opentelemetry
  labels:
    app: my-app
    app.kubernetes.io/name: py-prometheus-app
spec:
  selector:
    app: my-app
    app.kubernetes.io/name: py-prometheus-app
  ports:
    - name: prom
      port: 8080

これは OpenTelemetryCollector の定義です。

apiVersion: opentelemetry.io/v1beta1
kind: OpenTelemetryCollector
metadata:
  name: otelcol
  namespace: opentelemetry
spec:
  mode: statefulset
  targetAllocator:
    enabled: true
    serviceAccount: opentelemetry-targetallocator-sa
    prometheusCR:
      enabled: true
      podMonitorSelector: {}
      serviceMonitorSelector: {}
  config:
    receivers:
      otlp:
        protocols:
          grpc: {}
          http: {}
      prometheus:
        config:
          scrape_configs:
            - job_name: 'otel-collector'
              scrape_interval: 10s
              static_configs:
                - targets: ['0.0.0.0:8888']

    processors:
      batch: {}

    exporters:
      debug:
        verbosity: detailed

    service:
      pipelines:
        traces:
          receivers: [otlp]
          processors: [batch]
          exporters: [debug]
        metrics:
          receivers: [otlp, prometheus]
          processors: []
          exporters: [debug]
        logs:
          receivers: [otlp]
          processors: [batch]
          exporters: [debug]

まず、Kubernetesで port-forward を設定し、ターゲットアロケーターのサービスを公開できるようにします。

kubectl port-forward svc/otelcol-targetallocator -n opentelemetry 8080:80

otelcol-targetallocatorOpenTelemetryCollector CRの metadata.name の値と -targetallocator サフィックスを連結したもので、opentelemetryOpenTelemetryCollector CRがデプロイされている名前空間です。

次に、ターゲットアロケーターに登録されているジョブのリストを取得します。

curl localhost:8080/jobs | jq

サンプル出力は次のようになります。

{
  "serviceMonitor/opentelemetry/sm-example/1": {
    "_link": "/jobs/serviceMonitor%2Fopentelemetry%2Fsm-example%2F1/targets"
  },
  "serviceMonitor/opentelemetry/sm-example/2": {
    "_link": "/jobs/serviceMonitor%2Fopentelemetry%2Fsm-example%2F2/targets"
  },
  "otel-collector": {
    "_link": "/jobs/otel-collector/targets"
  },
  "serviceMonitor/opentelemetry/sm-example/0": {
    "_link": "/jobs/serviceMonitor%2Fopentelemetry%2Fsm-example%2F0/targets"
  },
  "podMonitor/opentelemetry/pm-example/0": {
    "_link": "/jobs/podMonitor%2Fopentelemetry%2Fpm-example%2F0/targets"
  }
}

serviceMonitor/opentelemetry/sm-example/0 は、ServiceMonitor が取得した Service ポートのひとつを表しています。

  • opentelemetryServiceMonitor リソースが存在する名前空間です。
  • sm-exampleServiceMonitor の名前です。
  • 0 は、ServiceMonitorService の間で一致するポートエンドポイントのひとつです。

同様に、PodMonitorcurl の出力で podMonitor/opentelemetry/pm-example/0 として表示されます。

これは、スクレイプ構成の検出が機能していることを示す朗報です!

これは、(otel-collector という名前の)OpenTelemetryCollector リソースの spec.config.receivers.prometheusReceiver でセルフスクレイプが有効になっているためです。

prometheus:
  config:
    scrape_configs:
      - job_name: 'otel-collector'
        scrape_interval: 10s
        static_configs:
          - targets: ['0.0.0.0:8888']

上記の _link の出力値に対して curl を実行して、serviceMonitor/opentelemetry/sm-example/0 の詳細を確認し、どのスクレイプ対象が取得されているかを確認できます。

curl localhost:8080/jobs/serviceMonitor%2Fopentelemetry%2Fsm-example%2F0/targets | jq

サンプル出力

{
  "otelcol-collector-0": {
    "_link": "/jobs/serviceMonitor%2Fopentelemetry%2Fsm-example%2F0/targets?collector_id=otelcol-collector-0",
    "targets": [
      {
        "targets": ["10.244.0.11:8080"],
        "labels": {
          "__meta_kubernetes_endpointslice_port_name": "prom",
          "__meta_kubernetes_pod_labelpresent_app_kubernetes_io_name": "true",
          "__meta_kubernetes_endpointslice_port_protocol": "TCP",
          "__meta_kubernetes_endpointslice_address_target_name": "py-prometheus-app-575cfdd46-nfttj",
          "__meta_kubernetes_endpointslice_annotation_endpoints_kubernetes_io_last_change_trigger_time": "2024-06-21T20:01:37Z",
          "__meta_kubernetes_endpointslice_labelpresent_app_kubernetes_io_name": "true",
          "__meta_kubernetes_pod_name": "py-prometheus-app-575cfdd46-nfttj",
          "__meta_kubernetes_pod_controller_name": "py-prometheus-app-575cfdd46",
          "__meta_kubernetes_pod_label_app_kubernetes_io_name": "py-prometheus-app",
          "__meta_kubernetes_endpointslice_address_target_kind": "Pod",
          "__meta_kubernetes_pod_node_name": "otel-target-allocator-talk-control-plane",
          "__meta_kubernetes_pod_labelpresent_pod_template_hash": "true",
          "__meta_kubernetes_endpointslice_label_kubernetes_io_service_name": "py-prometheus-app",
          "__meta_kubernetes_endpointslice_annotationpresent_endpoints_kubernetes_io_last_change_trigger_time": "true",
          "__meta_kubernetes_service_name": "py-prometheus-app",
          "__meta_kubernetes_pod_ready": "true",
          "__meta_kubernetes_pod_labelpresent_app": "true",
          "__meta_kubernetes_pod_controller_kind": "ReplicaSet",
          "__meta_kubernetes_endpointslice_labelpresent_app": "true",
          "__meta_kubernetes_pod_container_image": "otel-target-allocator-talk:0.1.0-py-prometheus-app",
          "__address__": "10.244.0.11:8080",
          "__meta_kubernetes_service_label_app_kubernetes_io_name": "py-prometheus-app",
          "__meta_kubernetes_pod_uid": "495d47ee-9a0e-49df-9b41-fe9e6f70090b",
          "__meta_kubernetes_endpointslice_port": "8080",
          "__meta_kubernetes_endpointslice_label_endpointslice_kubernetes_io_managed_by": "endpointslice-controller.k8s.io",
          "__meta_kubernetes_endpointslice_label_app": "my-app",
          "__meta_kubernetes_service_labelpresent_app_kubernetes_io_name": "true",
          "__meta_kubernetes_pod_host_ip": "172.24.0.2",
          "__meta_kubernetes_namespace": "opentelemetry",
          "__meta_kubernetes_endpointslice_endpoint_conditions_serving": "true",
          "__meta_kubernetes_endpointslice_labelpresent_kubernetes_io_service_name": "true",
          "__meta_kubernetes_endpointslice_endpoint_conditions_ready": "true",
          "__meta_kubernetes_service_annotation_kubectl_kubernetes_io_last_applied_configuration": "{\"apiVersion\":\"v1\",\"kind\":\"Service\",\"metadata\":{\"annotations\":{},\"labels\":{\"app\":\"my-app\",\"app.kubernetes.io/name\":\"py-prometheus-app\"},\"name\":\"py-prometheus-app\",\"namespace\":\"opentelemetry\"},\"spec\":{\"ports\":[{\"name\":\"prom\",\"port\":8080}],\"selector\":{\"app\":\"my-app\",\"app.kubernetes.io/name\":\"py-prometheus-app\"}}}\n",
          "__meta_kubernetes_endpointslice_endpoint_conditions_terminating": "false",
          "__meta_kubernetes_pod_container_port_protocol": "TCP",
          "__meta_kubernetes_pod_phase": "Running",
          "__meta_kubernetes_pod_container_name": "my-app",
          "__meta_kubernetes_pod_container_port_name": "prom",
          "__meta_kubernetes_pod_ip": "10.244.0.11",
          "__meta_kubernetes_service_annotationpresent_kubectl_kubernetes_io_last_applied_configuration": "true",
          "__meta_kubernetes_service_labelpresent_app": "true",
          "__meta_kubernetes_endpointslice_address_type": "IPv4",
          "__meta_kubernetes_service_label_app": "my-app",
          "__meta_kubernetes_pod_label_app": "my-app",
          "__meta_kubernetes_pod_container_port_number": "8080",
          "__meta_kubernetes_endpointslice_name": "py-prometheus-app-bwbvn",
          "__meta_kubernetes_pod_label_pod_template_hash": "575cfdd46",
          "__meta_kubernetes_endpointslice_endpoint_node_name": "otel-target-allocator-talk-control-plane",
          "__meta_kubernetes_endpointslice_labelpresent_endpointslice_kubernetes_io_managed_by": "true",
          "__meta_kubernetes_endpointslice_label_app_kubernetes_io_name": "py-prometheus-app"
        }
      }
    ]
  }
}

上記の出力の _link フィールドのクエリパラメータ collector_id は、これらのターゲットが otelcol-collector-0 (OpenTelemetryCollector リソースのために作成された StatefulSet の名前) に関連することを示しています。

ターゲットアロケーターは有効ですか?Prometheusのサービスディスカバリーは有効ですか?

上記の curl コマンドで期待される ServiceMonitorPodMonitor のリストが表示されない場合、それらの値を設定する機能が有効になっているかを確認する必要があります。

留意すべきことは、OpenTelemetryCollector CRに targetAllocator セクションを含めたからといって、それが有効になるわけではないということです。 ターゲットアロケーターは明示的に有効化する必要があります。 さらに、Prometheusのサービスディスカバリーを使用する場合は、明示的に有効化する必要があります。

  • spec.targetAllocator.enabledtrue に設定する
  • spec.targetAllocator.prometheusCR.enabledtrue に設定する

OpenTelemetryCollector リソースは次のようになります。

apiVersion: opentelemetry.io/v1beta1
kind: OpenTelemetryCollector
metadata:
  name: otelcol
  namespace: opentelemetry
spec:
  mode: statefulset
  targetAllocator:
    enabled: true
    serviceAccount: opentelemetry-targetallocator-sa
    prometheusCR:
      enabled: true

完全な OpenTelemetryCollector リソース定義については"メトリクスは実際にスクレイプされていますか?"を参照してください。

ServiceMonitor (または PodMonitor) のセレクターを設定しましたか?

ServiceMonitorのセレクターを設定した場合、ターゲットアロケーターはserviceMonitorSelectorの値と一致する metadata.label を持つ ServiceMonitor のみを探すことになります。

次の例のように、ターゲットアロケーターにserviceMonitorSelectorを設定したとします。

apiVersion: opentelemetry.io/v1beta1
kind: OpenTelemetryCollector
metadata:
  name: otelcol
  namespace: opentelemetry
spec:
  mode: statefulset
  targetAllocator:
    enabled: true
    serviceAccount: opentelemetry-targetallocator-sa
    prometheusCR:
      enabled: true
      serviceMonitorSelector:
        matchLabels:
          app: my-app

app: my-appspec.targetAllocator.prometheusCR.serviceMonitorSelector.matchLabels の値を設定することで、ServiceMonitor リソースの metadata.labels にも同じ値が必要になります。

apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
  name: sm-example
  labels:
    app: my-app
    release: prometheus
spec:

完全な ServiceMonitor リソース定義については"メトリクスは実際にスクレイプされていますか?"を参照してください。

この場合、 OpenTelemetryCollector リソースの prometheusCR.serviceMonitorSelector.matchLabels は、前の例にあったように app: my-app ラベルを持つ ServiceMonitor のみを探します。

ServiceMonitor リソースにそのラベルがない場合、ターゲットアロケーターはその ServiceMonitor からスクレイプ対象を検出できません。

serviceMonitorSelector および/または podMonitorSelector の構成を完全に省略しましたか?

“ServiceMonitor (または PodMonitor) のセレクターを設定しましたか?”で述べたように、serviceMonitorSelectorpodMonitorSelector に一致しない値が設定されている場合、ターゲットアロケーターはそれぞれの ServiceMonitorPodMonitor からスクレイプ対象を検出できなくなります。

同様に、OpenTelemetryCollector CRのv1beta1では、この構成を完全に省略すると、ターゲットアロケーターは ServiceMonitorPodMonitor からスクレイプ対象を検出できなくなります。

OpenTelemetryCollectorv1beta1 では、serviceMonitorSelectorpodMonitorSelector を使用する予定がない場合でも、次のように含める必要があります。

prometheusCR:
  enabled: true
  podMonitorSelector: {}
  serviceMonitorSelector: {}

この構成は、すべての PodMonitor および ServiceMonitor リソースに一致することを意味します。 完全なOpenTelemetryCollectorの定義については、“メトリクスは実際にスクレイプされていますか? “を参照してください。

ServiceMonitorとService(または PodMonitor と Pod)のラベル、名前空間、ポートは一致していますか?

ServiceMonitor は、次の条件に一致するKubernetesの Serviceを取得するように構成されています。

  • ラベル
  • 名前空間 (optional)
  • ポート (エンドポイント)

次のような ServiceMonitor があるとします。

apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
  name: sm-example
  labels:
    app: my-app
    release: prometheus
spec:
  selector:
    matchLabels:
      app: my-app
  namespaceSelector:
    matchNames:
      - opentelemetry
  endpoints:
    - port: prom
      path: /metrics
    - port: py-client-port
      interval: 15s
    - port: py-server-port

前述の ServiceMonitor は、次の条件に一致するサービスを探しています。

  • ラベルが app: my-app
  • opentelemetry という名前空間に存在する
  • prompy-client-portまたは py-server-port という名前のポート

たとえば、次の Service リソースは前述の条件に一致するため、ServiceMonitor によって取得されます。

apiVersion: v1
kind: Service
metadata:
  name: py-prometheus-app
  namespace: opentelemetry
  labels:
    app: my-app
    app.kubernetes.io/name: py-prometheus-app
spec:
  selector:
    app: my-app
    app.kubernetes.io/name: py-prometheus-app
  ports:
    - name: prom
      port: 8080

次の Service リソースは、ServiceMonitorprompy-client-portまたは py-server-port という名前のポートを探していますが、このサービスのポートは bleh という名前であるため取得されません。

apiVersion: v1
kind: Service
metadata:
  name: py-prometheus-app
  namespace: opentelemetry
  labels:
    app: my-app
    app.kubernetes.io/name: py-prometheus-app
spec:
  selector:
    app: my-app
    app.kubernetes.io/name: py-prometheus-app
  ports:
    - name: bleh
      port: 8080