📘

Istio のトレース情報を OpenTelemetry Protocol を使って転送する

2024/09/03に公開1

Istio にいつの間にか OpenTelemetry Protocol でトレースを転送する機能が搭載されていのでシュッとできるかなと思ったけど色々手順があったのでブログで紹介したいと思います。

データの転送先は New Relic に転送を実施しています。

参考情報

本記事を構成する上で参考にさせて頂いた記事やスライドを紹介します。

https://istio.io/latest/docs/tasks/observability/distributed-tracing/opentelemetry/
https://techblog.goinc.jp/entry/2024/05/17/153729
https://speakerdeck.com/k6s4i53rx/opentelemetry-in-service-mesh
https://zenn.dev/ryoyoshii/articles/e87bc69d616ee1

環境情報

以下の環境で検証しています

EKS 1.30
Istio 1.22.3

Bookinfo Application がデプロイされている前提で進めているので Bookinfo Application までの準備をすませてから取り組んでください。

既にIstio環境を時前で持っている場合はそちらを利用して頂いても大丈夫です。

OpenTelemetry Collector の準備

OpenTelemetry Collector(otel collector) の準備をします。

最低限の設定をしているので必要に応じて設定を変更して下さい。

# otel.yaml

apiVersion: v1
kind: Service
metadata:
  name: opentelemetrycollector
  namespace: observability
spec:
  type: ClusterIP
  ports:
    - name: grpc-otlp # Default endpoint for OpenTelemetry receiver.
      port: 4317
      protocol: TCP
      targetPort: 4317
    - name: http-otlp # HTTP endpoint for OpenTelemetry receiver.
      port: 4318
      protocol: TCP
      targetPort: 4318
    - name: health
      port: 13133
      protocol: TCP
      targetPort: 13133
  selector:
    app.kubernetes.io/name: opentelemetrycollector
---
apiVersion: v1
kind: ConfigMap
metadata:
  name: otel-conf
  namespace: observability
data:
  otel-collector-conf.yaml: |
    receivers:
      zipkin:
      otlp:
        protocols:
          grpc:
            endpoint: 0.0.0.0:4317
          http:
            endpoint: 0.0.0.0:4318
            
    processors:
      batch:

    exporters:
      otlp:
        endpoint: "https://otlp.nr-data.net:4317" #https://docs.newrelic.com/docs/opentelemetry/best-practices/opentelemetry-otlp/
        headers:
          api-key: "<newrelic license key>"

    extensions:
      health_check:
        
    service:
      extensions:
        - health_check
      telemetry:
        logs:
          level: "DEBUG"
      pipelines:
        traces:
          receivers: [otlp]
          processors: [batch]
          exporters: [otlp]
        metrics:
          receivers: [otlp]
          processors: [batch]
          exporters: [otlp]
        logs:
          receivers: [otlp]
          processors: [batch]
          exporters: [otlp]
---
apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: opentelemetrycollector
  namespace: observability
spec:
  selector:
    matchLabels:
      app.kubernetes.io/name: opentelemetrycollector
  template:
    metadata:
      labels:
        app.kubernetes.io/name: opentelemetrycollector
    spec:
      containers:
        - name: otel-collector
          args:
            - --config=/conf/otel-collector-conf.yaml
          image: otel/opentelemetry-collector-contrib:0.107.0
          ports:
            - containerPort: 4317
              protocol: TCP
              name: grpc-otlp
            - containerPort: 4318
              protocol: TCP
              name: http-otlp
            - containerPort: 13133
              protocol: TCP
              name: health
          volumeMounts:
            - mountPath: /conf
              name: otel-conf
          resources:
            limits:
              cpu: "2"
              memory: 4Gi
            requests:
              cpu: 200m
              memory: 400Mi
      volumes:
        - configMap:
            name: otel-conf
            items:
              - key: otel-collector-conf.yaml
                path: otel-collector-conf.yaml
          name: otel-conf

クラスタに反映します

kubectl apply -f otel.yaml

IstioOperator の編集

IstioOperator でトレーシングを有効にします。

#operator.yaml
apiVersion: install.istio.io/v1alpha1
kind: IstioOperator
spec:
  profile: demo
  meshConfig:
    accessLogFile: /dev/stdout
    enableTracing: true
    extensionProviders:
      - name: otel-tracing
        opentelemetry:
          port: 4317
          service: opentelemetrycollector.observability.svc.cluster.local
          resource_detectors:
            environment: {}
    defaultProviders:
      tracing:
        - otel-tracing

extentionsProvider で opentelemetry を設定することによって OpenTelemetry 形式でのトレーシングを利用することができます。

筆者はistioctlで管理をしていたのでistioctlで変更を反映させます。

istioctl install -f operator.yaml -y

resource_detectors が設定されていないというようなエラーが出ますが特に気にしなくても大丈夫ですが設定をしたい場合は ProxyConfig を設定してください。

一例です

apiVersion: networking.istio.io/v1beta1
kind: ProxyConfig
metadata:
  name: istio-proxyconfig
  namespace: istio-system
spec:
  concurrency: 0
  environmentVariables:
    OTEL_RESOURCE_ATTRIBUTES: "service.name=istio-proxy"

Telemetry API の設定

実際に IstioOperator で設定した内容を Telemetry APIを利用して有効化させます。

randomSamplingPercentage でサンプリングレートを変更ができるのでお好みの数値に変更して下さい。

# telemetry.yaml
apiVersion: telemetry.istio.io/v1
kind: Telemetry
metadata:
  name: otel-demo
spec:
  tracing:
    - providers:
        - name: otel-tracing
      randomSamplingPercentage: 100

反映させます

kubectl apply -f telemetry.yaml

ここまでくると準備は完了なので istio-proxy を ingect させているPod群を再起動させましょう。何回かリクエストをさせて New Relic 側の画面でトレースが流れてきているか確認します。(黒塗り箇所はLB名がそのまま出てしまっているので隠しています。)

トレースが流れていることが確認できました。
Spanでいうところの ingress などとついている箇所が istio-proxy が生成した Span になっています。

内容としては以上になりますがカスタマイズなどで色々なことができそうなのでまた時間があればやってみたいと思います。

ハマったところ

実はこの作業をしている時に istio-proxy から otel collector に対して接続ができなくなっていて何故だろうと調べていたのですがなかなかエラーログがでず otel collector にもそれらしいエラーログがでていなかったので1行ずつ調べている時にこのようなログがでていました。

info	localhostgate/featuregate.go:63	The default endpoints for all servers in components have changed to use localhost instead of 0.0.0.0. Disable the feature gate to temporarily revert to the previous default.

最初は見逃していたのですがこれが原因でログで調べたら1発で偉大な先人の知見があったので解決することが出来ました。

https://zenn.dev/ryoyoshii/articles/e87bc69d616ee1

Discussion

joejoe

Otel Collector 経由しなくても直接 New Relic に送る方法があったので追記で、otlp endpoint が用意されていれば他のツールでもできると思います。

公式ドキュメントの実装を参考にしました
https://istio.io/latest/docs/reference/config/istio.mesh.v1alpha1/#MeshConfig-ExtensionProvider-OpenTelemetryTracingProvider

extensionProvider の設定を http を利用するように変更

- name: otel-tracing
  opentelemetry:
    port: 443
    service: otlp.nr-data.net
    http:
     path: "/v1/traces"
     timeout: 5s #任意で
     headers:
      - name: "api-key"
        value: "<newrelic license key>"

ServiceEntry と DestinationRule を追加

apiVersion: networking.istio.io/v1alpha3
kind: ServiceEntry
metadata:
  name: newrelic-otlp
spec:
  hosts:
    - otlp.nr-data.net
  ports:
    - number: 443
      name: https
      protocol: HTTPS
  resolution: DNS
  location: MESH_EXTERNAL
---
apiVersion: networking.istio.io/v1alpha3
kind: DestinationRule
metadata:
  name: newrelic-otlp
spec:
  host: otlp.nr-data.net
  trafficPolicy:
    portLevelSettings:
      - port:
          number: 443
        tls:
          mode: SIMPLE