Opentelemetry collector 在 kubernetes 中的介紹,包含 opentelemetry 的運作基礎

介紹 opentelmetry 的基礎概念,像是 collector 中的 receivers, processors, exports, service.pipeline 的參數設定,然後進入 k8s 的 opentelemetry,兩種版本的差異,及最後的安裝與 demo

Kiwi lee
15 min readJun 7, 2024

關於 opentelemetry 的最基礎知識

  • opentelemetry 不會像 prometheues, jaeger, loki 擔任 metrics/log/trace 的資料儲存後端
  • opentelemetry 專注在生成 (generate)、收集 (collect)、管理 (manage)、輸出 (export)。(我自己會覺得跟 fluentbit 很像)
  • 支持各種 third-party 元件的收集 (ex. prometheus),元件的輸出 (ex. tempo, jaeger, loki)
  • 生成與收集的項目包含:metrics, trace, log
  • 收集的 opentelemetry 元件:opentelemetry collector
  • 生成的 opentelemetry 元件:opentelemetry instrument

最核心的元件 — opentelemetry collector

負責收集處理輸出監控相關的數據

  • Receivers: 接收監控數據
receivers:
# Data sources: logs
fluentforward:
endpoint: 0.0.0.0:8006

# Data sources: traces, metrics, logs
otlp:
protocols:
grpc:
endpoint: 0.0.0.0:4317
http:
endpoint: 0.0.0.0:4318

# Data sources: metrics
prometheus:
config:
scrape_configs:
- job_name: otel-collector
scrape_interval: 5s
static_configs:
- targets: [localhost:8888]
  • Processors: 監控數據的處理 & 監控過程中的控管
processors:
# Data sources: traces
attributes:
actions:
- key: environment
value: production
action: insert
- key: db.statement
action: delete
- key: email
action: hash

# Data sources: traces, metrics, logs
batch:

# Data sources: metrics
filter:
metrics:
include:
match_type: regexp
metric_names:
- prefix/.*
- prefix_.*

# Data sources: traces, metrics, logs
memory_limiter:
check_interval: 5s
limit_mib: 4000
spike_limit_mib: 500

# Data sources: traces
resource:
attributes:
- key: cloud.zone
value: zone-1
action: upsert
- key: k8s.cluster.name
from_attribute: k8s-cluster
action: insert
- key: redundant-attribute
action: delete

# Data sources: traces
probabilistic_sampler:
hash_seed: 22
sampling_percentage: 15

# Data sources: traces
span:
name:
to_attributes:
rules:
- ^\/api\/v1\/document\/(?P<documentId>.*)\/update$
from_attributes: [db.svc, operation]
separator: '::'

Opentelemetry 推薦要加的 processor

  1. memory_limiter: 加入 memory 限制器,避免監控數據把 opentelemetry collector 給塞爆。超過 soft_limit 會開始拒絕 metrics (receivers 需實作 error retry 機制),而超過 hard_limit 則會開始進行 garbage collection
  2. Any sampling or initial filtering processors
  3. Any processor relying on sending source from Context (e.g. k8sattributes)
  4. batch: 藉由批次累積後的上傳,可以減低負擔。可調整的項目像是 send_batch_size (最大的 batch)、 timeout (無論大小,批次的發送時間)
  5. Any other processors
  • Exporters: 輸出處理完後的監控數據
exporters:
# Data sources: traces, metrics, logs
file:
path: ./filename.json

# Data sources: traces
otlp/jaeger:
endpoint: jaeger-server:4317
tls:
cert_file: cert.pem
key_file: cert-key.pem

# Data sources: traces, metrics, logs
kafka:
protocol_version: 2.0.0

# Data sources: traces, metrics, logs
# NOTE: Prior to v0.86.0 use `logging` instead of `debug`
debug:
verbosity: detailed

# Data sources: traces, metrics, logs
otlp:
endpoint: otelcol2:4317
tls:
cert_file: cert.pem
key_file: cert-key.pem

# Data sources: traces, metrics
otlphttp:
endpoint: https://otlp.example.com:4318
tls:
insecure: true

# Data sources: metrics
prometheus:
endpoint: 0.0.0.0:8889
namespace: default

# Data sources: metrics
prometheusremotewrite:
endpoint: http://prometheus.example.com:9411/api/prom/push
# When using the official Prometheus (running via Docker)
# endpoint: 'http://prometheus:9090/api/v1/write', add:
# tls:
# insecure: true

可以輸出給 prometheus, tempo, jaeger, 另一座的 opentelemetry, kafka 等等的。

須注意 exporter 中的 otlp 是 GRPC,若是要傳送 HTTP,需要用 otlphttp

  • Services.pipeline: 定義 trace, metrics, log 的處理流程,裡面填入的元件必須在上面的 receivers, processors, exporters 定義才能正確使用

所以完整的 opentelemetry collector 範例如下:

receivers:
otlp:
protocols:
grpc:
endpoint: 0.0.0.0:4317
http:
endpoint: 0.0.0.0:4318

processors:
batch:

exporters:
otlp:
endpoint: otelcol:4317

extensions:
health_check:
pprof:
zpages:

service:
extensions: [health_check, pprof, zpages]
pipelines:
traces:
receivers: [otlp]
processors: [batch]
exporters: [otlp]
metrics:
receivers: [otlp]
processors: [batch]
exporters: [otlp]
logs:
receivers: [otlp]
processors: [batch]
exporters: [otlp]

collector 負責處理監控數據。而 instrument 就是負責生成監控數據

生成監控數據 — opentelemetry instrument

  • 支援自動收集 (可以自動補抓內部套件的使用,ex. Python 可自動抓取到的 Python package 清單 LINK )
  • 支援自己埋監控點 (Manual instrumentation, Exporting data)
  • 目前支援的程式語言

上面大概是最基本的 opentelmetry 元件了 (๑•̀ㅂ•́)و✧
下面就來介紹 k8s 的 Opentelemery。

Kubernetes 中的 Opentelemetry

有兩種版本,分別是 opentelemetry collector 與 opentelemetry operator。

Opentelemetry Collector

可選擇 deployment, daemonset 模式,有一些預設的 receivers 可以選擇 (Important Components for Kubernetes | OpenTelemetry)。利用 configmap 來管理 opentelemetry collector 的設定。

Opentelemetry Operator

opentelemetry-helm-charts/charts/opentelemetry-operator at main · open-telemetry/opentelemetry-helm-charts (github.com)

基於 kubernetes 的 crd 所改裝的 opentelemetry,會由opentelemetry-operator 的 deployment 來 watch opentelemetry 的 CRD (collector, instrument) 產生,然後執行像是生成 opentelemetry collector 的 deployment,或是 mutate 有需要 instrument 的 pod,使其內部能發送監控數據。

Collector 的 CRD 可以選擇 deployment, daemonset, statefulset, sidecar 形式,可以同時有多個 collector 存在。

不過 image 版本上,我在使用 helm-chart 時 collector 預設是 v0.93.0 ,operator 則是 v0.92.1 ,但因為 CRD 管控實在太香,所以我後來是選擇安裝 Opentelemetry Operator 的模式。

安裝 Opentelemetry Operator

因為 opentelemetry operator 是依靠 k8s crd 來創建 collector 與 instrument,所以需要跟 api-server 註冊 webhook。

要建立能跟 api-server 的 webhook,則需要有 TLS certificates 的 server,而用 cert-manager 這個套件的話,是最簡單的手法 🤣

安裝 dependency — cert-manager

  1. 先安裝 crds
$ kubectl apply -f https://github.com/cert-manager/cert-manager/releases/download/v1.14.5/cert-manager.crds.yaml
在安裝本體

2. 安裝本體

$ helm install my-release --namespace cert-manager --version v1.14.5 jetstack/cert-manager

安裝 operator 本體

opentelemetry-helm-charts/charts/opentelemetry-operator at main · open-telemetry/opentelemetry-helm-charts (github.com)

$ helm install opentelemetry-operator open-telemetry/opentelemetry-operator \
--set "manager.collectorImage.repository=otel/opentelemetry-collector-k8s"

加入 crds — 使用 sidecar 模式

這邊 demo 會使用 jaeger 來做示範

首先先安裝 OpenTelemetryCollector 的 CRD

  • mode: sidecar
  • config.receivers: jaeger
  • config.exporters: debug
  • config.service.pipeline: jaeger -> debug
apiVersion: opentelemetry.io/v1alpha1
kind: OpenTelemetryCollector
metadata:
name: sidecar-for-my-app
spec:
mode: sidecar
config: |
receivers:
jaeger:
protocols:
thrift_compact:
processors:

exporters:
debug:

service:
pipelines:
traces:
receivers: [jaeger]
processors: []
exporters: [debug]

然後 pod 內的 annotations 加入 sidecar.opentelemetry.io/inject: “true”(如果是 deployment 類型的,也是需要加在 pod template 裡面)

apiVersion: v1
kind: Pod
metadata:
name: myapp
annotations:
sidecar.opentelemetry.io/inject: "true"
spec:
containers:
- name: myapp
image: jaegertracing/vertx-create-span:operator-e2e-tests
ports:
- containerPort: 8080
protocol: TCP

這樣產生出來的 pod,就會多一個 sidecar container 來做監控

啟動的 log

然後打該 pod 的 port 8080 curl $podIP:8080 ,其 otc-container 的即可看到對應的 trace 資訊

若是我們想看更完整的 debug 資訊,可參考 debugexporter,只要改變 exporter 的參數

exporter:
debug:
verbosity: detailed

這樣 log 就會把監控數據給印出來,如下圖

以上把 opentelemetry 的基礎使用介紹完了~~~

我自己是把 opentelemetry 當成監控數據的 proxy,接收來自各種來源的資訊 (receivers),做完處理後 (processors),再扔給對應的儲存空間 (exporters)。本身不會做資料的儲存。

因此 opentelemetry 有很多方便使用的 plugin 可以使用,就像 ansible 一樣,輕鬆的呼叫,而不用煩惱自己要去做串接,可以快速的收集。

再來也有不同的 mode,deployment, daemonset, sidecar 可以選擇,端看你對於監控數據的收集需求,選擇自己想要的模式,甚至可以用混合的。

但此外 opentelemetry 有一塊 instrument,也是很重要的核心,我自己覺得更是 opentelemetry 實用的地方,可以自動生成系統的監控數據,一樣可以減輕我們撰寫這些 trace 斷點的時間。下一篇應該會提到 opentelemetry 在 python 服務中,要如何安裝 auto-instrument。

--

--

Kiwi lee

Hi, I'm kiwi, Platform Engineer (SRE, DevOps). Python Engineer. Love art, books, longboard. https://kiwilee-blog.netlify.app/