🎄

OpenTelemetry Collector Builder (ocb) を使ってお好みの OTel Collector を作る

2022/12/20に公開

初めに

こんにちは!この記事は OpenTelemetry Advent Calendar 2022 の 20 日目です 🎄 !

みなさん OpenTelemetry してますか?
OpenTelemetry には、バックエンドにテレメトリを送信する際のプロキシとして作用する OpenTelemetry Collector(以下、OTel Collector) というコンポーネントがあります。
今回は OTel Collector を自分好みにカスタマイズして作れる(?)、OpenTelemetry Collector Builder(通称:ocb)について やってみた を書きます。
この記事を読むことで、OTel Collector の構成や設定方法が超ざっくり分かると思います。
ocbイメージ図
Custom OTel Collector 作成イメージ

OTel Collector について

OpenTelemetry ではモニタリングソリューションにテレメトリを送信する際に、OTel Collector を介してデータを集約し、エクスポートをするようなアーキテクチャを取ることができます。

OTel Collector 概要図

OTel Collector 自体は Receiver / Processor / Exporter から構成されています。(参考
以下に示す例の他にも数多の Receiver / Processor / Exporter が用意されており、リポジトリを徘徊してこんなことができる processor があるのか〜と物色するのはとても楽しいのでオススメです。

  • Receiver:テレメトリの受け口
    • 例: otlpreceiver, jaegerreceiver, prometheusreceiver, ・・・
  • Processor:受け取ったテレメトリの処理部
  • Exporter:テレメトリの送信口

OTel Collector には標準とコントリビューションの2つのディストリビューションがあり、以下のリポジトリでどのようなコンポーネントが含まれているかを確認することができます。

コントリビューション Distro. には、AWS, GCP, Splunk などのベンダ製のコンポーネントや、Status が development のコンポーネントもたくさん含まれ配布されていることが分かります。
コントリビューション Distro. は多くのコンポーネントを含んでいるため やってみた するにはうってつけなのですが、ことプロダクション環境においては以下の自明な理由より、
必要に応じたコンポーネントのみ内包し構成を制限することを推奨 されております。 ※ 出典

① reduce the size of the collector, reducing deployment times for the collector
デプロイ時間短縮のために、OTel Collector のサイズ縮小するため
② improve the security of the collector by reducing the available attack surface area
セキュリティ的な観点

そこで、OpenTelemetry Collector Builder(以下、ocb)の登場です。
ocb は OpenTelemetry Community が開発している OTel Collector のビルドツールで、どのコンポーネントで構成するかのレシピを書くだけで簡単に Custom OTel Collector を作ることができます!

Custom OTel Collector を作る

ocb を使った Custom OTel Collector を作るには以下のフローを辿ります。
公式ドキュメントに沿っていけば簡単にできます。

Step.1 ocb のインストール

GO111MODULE=on go install go.opentelemetry.io/collector/cmd/builder@latest
❯ builder version
ocb version dev

バイナリ版も配布されています。
https://github.com/open-telemetry/opentelemetry-collector/releases/

Step.2 OTel Collector のレシピ(Yaml) の作成

yaml ファイルに OTel Collector に組み込みたいコンポーネント(Receiver / Processor / Exporter) を記述していきます。今回は最もシンプルな構成として、otlpreceiverotlpexporter から構成される OTel Collector を作ってみます。

otelcol-recipe.yaml
receivers:
  - gomod: go.opentelemetry.io/collector/receiver/otlpreceiver v0.68.0
exporters:
  - gomod: go.opentelemetry.io/collector/exporter/otlpexporter v0.68.0

Step.3 ビルド

ocb を使ってビルドします。ビルドの際に、上記のレシピを指定して実行すると Custom OTel Collector の完成です 🥳 otelcol-custom というバイナリが生成されていることがわかります!

❯ builder --config=otelcol-recipe.yaml --output-path=./
Flag --output-path has been deprecated, use config distribution::output_path
2022-12-20T16:21:25.354+0900	INFO	internal/command.go:125	OpenTelemetry Collector Builder	{"version": "dev", "date": "unknown"}
2022-12-20T16:21:25.355+0900	INFO	internal/command.go:158	Using config file	{"path": "otelcol-recipe.yaml"}
2022-12-20T16:21:25.355+0900	INFO	builder/config.go:107	Using go	{"go-executable": "/usr/local/bin/go"}
2022-12-20T16:21:25.357+0900	INFO	builder/main.go:76	Sources created	{"path": "./"}
2022-12-20T16:21:54.742+0900	INFO	builder/main.go:118	Getting go modules
2022-12-20T16:21:57.499+0900	INFO	builder/main.go:87	Compiling
2022-12-20T16:23:12.856+0900	INFO	builder/main.go:99	Compiled	{"binary": ".//otelcol-custom"}ls -hlrt otelcol-custom
-rwxr-xr-x  1 zuck3rx  staff    21M 12 20 16:23 otelcol-custom

実際に Kubernetes 環境にデプロイしてみる

今回は Kubernetes 環境にデプロイをするため、OTel Collector を Docker イメージにビルドします。Dockerfile 内で ocb を使ってバイナリを作成し、実行する処理を書いてあげれば OK です。

dockerfile
# ocb を用いてビルド
FROM golang:1.18 as build
WORKDIR /app
COPY . .
RUN go install go.opentelemetry.io/collector/cmd/builder@latest
RUN builder --config=otelcol-recipe.yaml --name=otelcol-custom --output-path=.

# debian のベースイメージを用いて実行
FROM gcr.io/distroless/base-debian11
WORKDIR /app
COPY --from=build /app/otelcol-custom /app
EXPOSE 4317/tcp 4318/tcp

CMD ["/app/telcol-custom"]

あとは適当なイメージレジストリにあげ、以下のような K8s マニフェスト群を用意します。

k8sリソースのマニフェストファイル
otelcol-manifest.yaml
apiVersion: v1
kind: ServiceAccount
metadata:
  name: otel-collector-custom
---
apiVersion: v1
kind: Service
metadata:
  name: otel-collector-custom
  labels:
    app: opentelemetry-custom
    component: otel-collector-custom
spec:
  ports:
  - name: otlp-grpc # Default endpoint for OpenTelemetry gRPC receiver.
    port: 4317
    protocol: TCP
    targetPort: 4317
  - name: otlp-http
    port: 4318
    protocol: TCP
    targetPort: 4318
  selector:
    component: otel-collector-custom
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: otel-collector-custom
  labels:
    app: opentelemetry-custom
    component: otel-collector-custom
spec:
  selector:
    matchLabels:
      app: opentelemetry-custom
      component: otel-collector-custom
  minReadySeconds: 5
  progressDeadlineSeconds: 120
  replicas: 1
  template:
    metadata:
      labels:
        app: opentelemetry-custom
        component: otel-collector-custom
    spec:
      containers:
      - command:
          - "./otelcol-custom"
          - "--config=/conf/otelcol-config.yaml"
        image: <Path>
        name: otel-collector-custom
        resources:
          limits:
            cpu: 1
            memory: 2Gi
          requests:
            cpu: 200m
            memory: 400Mi
        ports:
        - containerPort: 4317 # default OTLP receiver
        - containerPort: 4318 # default OTLP receiver
        volumeMounts:
        - name: otel-collector-config-vol-custom
          mountPath: /conf
      serviceAccountName: otel-collector-custom
      volumes:
        - configMap:
            name: otel-config-custom
          name: otel-collector-config-vol-custom

OTel Collector でどのコンポーネントを使用するかの設定は、以下のような yaml を書いた上で、ConfigMap としてデプロイします。

otelcol-config.yaml
receivers:
  otlp:
    protocols:
      grpc:
        endpoint: "0.0.0.0:4318"
processors:
exporters:
  otlp:
    endpoint: jaeger-collector.observability.svc.cluster.local:55680
service:
  pipelines:
    traces:
      receivers: [otlp]
      exporters: [otlp]

Receiver は OTel Collector の otlp port を指定。Exporter はトレーシングバックエンドである Jaeger の otlp port を指定する簡単な設定を記述しています。
ConfigMap と Pod などのリソースをデプロイして、Custom OpenTelemetry Collector を無事にデプロイすることができました 🥳

Custom OTel Collector のデプロイ
# ConfigMap デプロイ
❯ k create configmap otel-config-custom \
--from-file=./otelcol-config.yaml --dry-run=client \
-o yaml | kubectl apply -f -

# OTel Collector デプロイ
❯ k apply -f otelcol-manifest.yaml

# デプロイできた〜
❯ k get po | grep otel-collector
otel-collector-custom-7f55d6bd48-xlstf     1/1     Running   0               16s

当たり前ですが、組み込んでいないコンポーネントを使おうとすると今回の Custom OTel Collector では otlp しか使えないよ!と怒られます。

jaeger exporter を使おうとした例
❯ ./otelcol-custom --config=./otelcol-config-no.yaml
Error: failed to get config: cannot unmarshal the configuration: 1 error(s) decoding:

* error decoding 'exporters': unknown type: "jaeger" for id: "jaeger" (valid values: [otlp])
2022/12/20 17:34:14 collector server run finished with error: failed to get config: cannot unmarshal the configuration: 1 error(s) decoding:

* error decoding 'exporters': unknown type: "jaeger" for id: "jaeger" (valid values: [otlp])
jaeger を設定した config
otelcol-config-no.yaml
receivers:
  otlp:
    protocols:
      grpc:
        endpoint: "0.0.0.0:4318"
processors:
exporters:
  otlp:
    endpoint: jaeger-collector.observability.svc.cluster.local:55680
  jaeger:
    endpoint: jaeger-collector.observability.svc.cluster.local:14250
    tls:
      insecure: true
service:
  pipelines:
    traces:
      receivers: [otlp]
      exporters: [jaeger]

最後に

今回は OpenTelemetry Collector Builder の記事でした。
使い方自体はとても簡単なので、こんなツールがあるんだーと知るキッカケになれたら幸いです。
ocb を使って自分好みの Custom OpenTelemetry Collector を作ってみてはいかがでしょうか!!

明日は @yusukesato06 さんの「OpenTelemetry Collector導入のPoCと今後に向けて」です。

宣伝

11月に開催された Cloud Native Days Tokyo 2022 で、OTel Collector の SpanMetricsProcessor を使ってアプリケーションから取得したメトリクスとトレースを相関させる。といったセッションを行いましたので、こちらも合わせてご覧いただけると嬉しいです 🙇‍!!
https://speakerdeck.com/k6s4i53rx/cndt2022-shi-jian-opentelemetry-to-oss-woshi-tuta-observability-ji-pan-nogou-zhu

Discussion