iT邦幫忙

2026 iThome 鐵人賽

DAY 11
0
IT Operation

寫完微服務然後呢?走向平台工程的黃金路徑系列 第 11 篇

Day 11 - 部署與設定 OpenTelemetry Collector

  • 分享至 

  • xImage
  •  

今天我們試著部署一個 OpenTelemetry Collector Gateway。服務只需要將 Metrics、Logs 和 Traces 傳到同一個 OTLP endpoint;Collector 再統一補上平台欄位、移除指定的敏感 attribute、批次處理,並依訊號轉送。Metrics 由 Prometheus scrape,Logs 送往 Loki,Traces 送往 Tempo;debug exporter 同時保留,方便在受控測試環境檢查 Collector 實際收到什麼。

Gateway 接收服務送來的 OTLP

Collector 常見的部署方式有三種:

模式 Kubernetes 部署方式 適合處理的資料
Agent 每個 Node 一個 DaemonSet container log、Node 資訊等靠近主機的資料
Gateway 集中的 Deployment application 主動傳送的 OTLP 資料
Hybrid Agent 將資料再送往 Gateway Node 資料與 application telemetry 都需要集中處理的環境

Todo 系統的服務會主動傳送 OTLP,因此先使用 Gateway。這組設定部署一個 Deployment,並透過 Service 提供 OTLP/gRPC 的 4317 port 和 OTLP/HTTP 的 4318 port。

BFF 與 todo-api 經 OTLP 將三種 telemetry 送入 OpenTelemetry Collector,依序經過 receiver 與 processors 後分流至 debug exporter、Prometheus、Loki 和 Tempo

Service 只負責把資料送到 Collector Pod;資料進入 Collector 後,會依 service.pipelines 中列出的順序經過 receiver、processor 和 exporter。設定檔裡宣告 processor 還不夠,必須放進 pipeline 才會執行。

建立 Namespace 和 Collector 設定

先建立一個獨立的 Namespace:

apiVersion: v1
kind: Namespace
metadata:
  name: observability

接著建立 otel-collector-config.yaml。OTLP receiver 同時開啟 gRPC 和 HTTP;三種訊號各有一條 pipeline,處理順序相同。

apiVersion: v1
kind: ConfigMap
metadata:
  name: otel-collector-config
  namespace: observability
data:
  config.yaml: |
    extensions:
      health_check:
        endpoint: 0.0.0.0:13133

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

    processors:
      memory_limiter:
        check_interval: 1s
        limit_mib: 192
        spike_limit_mib: 64
      resource/platform:
        attributes:
          - key: platform.name
            value: todo-platform
            action: upsert
      attributes/remove-sensitive:
        actions:
          - key: enduser.id
            action: delete
          - key: authorization
            action: delete
          - key: http.request.header.authorization
            action: delete
      batch:
        timeout: 5s
        send_batch_size: 1024

    exporters:
      debug:
        verbosity: detailed
      prometheus:
        endpoint: 0.0.0.0:8889
        resource_to_telemetry_conversion:
          enabled: true
      otlphttp/tempo:
        endpoint: http://tempo.observability.svc:4318
      otlphttp/loki:
        endpoint: http://loki.observability.svc:3100/otlp

    service:
      extensions: [health_check]
      pipelines:
        traces:
          receivers: [otlp]
          processors: [memory_limiter, resource/platform, attributes/remove-sensitive, batch]
          exporters: [debug, otlphttp/tempo]
        metrics:
          receivers: [otlp]
          processors: [memory_limiter, resource/platform, attributes/remove-sensitive, batch]
          exporters: [debug, prometheus]
        logs:
          receivers: [otlp]
          processors: [memory_limiter, resource/platform, attributes/remove-sensitive, batch]
          exporters: [debug, otlphttp/loki]

memory_limiter 依 Collector 的可用記憶體限制接收量,避免大量 telemetry 讓 Pod 因記憶體不足而重啟。resource/platform 將 platform.name=todo-platform 加到每筆資料的 resource attributes。attributes/remove-sensitive 在資料交給 exporter 前移除列出的欄位,batch 則把已處理的資料合併後送出。三條 pipeline 的 processor 順序相同,但 traces、metrics 和 logs 的 exporter 不同。

Prometheus exporter 會在 :8889 提供 metrics endpoint;Prometheus 對它進行 scrape。Logs 和 Traces 則由 Collector 以 OTLP/HTTP 主動送給 Loki 與 Tempo。otlphttp/loki 的 endpoint 以 /otlp 為基底,logs pipeline 會將路徑補為 /v1/logs,實際送往 http://loki.observability.svc:3100/otlp/v1/logs。因此 Loki 必須使用支援原生 OTLP logs 的版本與設定。debug exporter 只用來看處理過的內容,不能取代可以保存與查詢資料的 backend。

部署 Collector 與 Service

以下 manifest 將設定檔掛載到 Collector container,並提供 OTLP 的兩個 port。health check 僅供 Kubernetes probe 使用,不對其他 Pod 建立 Service port。

apiVersion: apps/v1
kind: Deployment
metadata:
  name: otel-collector
  namespace: observability
spec:
  replicas: 1
  selector:
    matchLabels:
      app: otel-collector
  template:
    metadata:
      labels:
        app: otel-collector
    spec:
      securityContext:
        runAsNonRoot: true
        seccompProfile:
          type: RuntimeDefault
      containers:
        - name: otel-collector
          image: otel/opentelemetry-collector:0.161.0
          args:
            - --config=/conf/config.yaml
          ports:
            - name: otlp-grpc
              containerPort: 4317
            - name: otlp-http
              containerPort: 4318
            - name: health
              containerPort: 13133
            - name: prometheus
              containerPort: 8889
          resources:
            requests:
              cpu: 100m
              memory: 128Mi
            limits:
              cpu: 500m
              memory: 256Mi
          readinessProbe:
            httpGet:
              path: /
              port: health
          livenessProbe:
            httpGet:
              path: /
              port: health
            initialDelaySeconds: 10
          securityContext:
            allowPrivilegeEscalation: false
            capabilities:
              drop:
                - ALL
            readOnlyRootFilesystem: true
            runAsUser: 10001
            runAsGroup: 10001
          volumeMounts:
            - name: config
              mountPath: /conf
              readOnly: true
      volumes:
        - name: config
          configMap:
            name: otel-collector-config
---
apiVersion: v1
kind: Service
metadata:
  name: otel-collector
  namespace: observability
spec:
  selector:
    app: otel-collector
  ports:
    - name: otlp-grpc
      port: 4317
      targetPort: otlp-grpc
    - name: otlp-http
      port: 4318
      targetPort: otlp-http
    - name: prometheus
      port: 8889
      targetPort: prometheus

部署時依序套用三份檔案:

kubectl apply -f namespace.yaml
kubectl apply -f otel-collector-config.yaml
kubectl apply -f otel-collector.yaml

kubectl rollout status deployment/otel-collector -n observability
kubectl get deployment,service -n observability

叢集內的 application 可使用下列 endpoint:

otel-collector.observability.svc:4317
http://otel-collector.observability.svc:4318
otel-collector.observability.svc:8889

送入測試 Trace 並檢查處理結果

先確認健康檢查 endpoint:

kubectl port-forward deployment/otel-collector 13133:13133 -n observability
curl --fail http://127.0.0.1:13133/

接著安裝官方的 telemetrygen,並將一筆 Trace 送到 Collector。若命令在叢集外執行,開啟另一個終端機轉送 gRPC port:

kubectl port-forward service/otel-collector 4317:4317 -n observability
go install github.com/open-telemetry/opentelemetry-collector-contrib/cmd/telemetrygen@latest
$(go env GOPATH)/bin/telemetrygen traces \
  --otlp-insecure \
  --otlp-endpoint 127.0.0.1:4317 \
  --service todo-api \
  --traces 1

查看 Collector log:

kubectl logs deployment/otel-collector -n observability

debug exporter 的輸出應包含 service.name: todo-api 和 platform.name: todo-platform。若 application 或測試工具送入 enduser.id、authorization 或 http.request.header.authorization,輸出不應包含這些 attribute。確認這些內容後,再從 Prometheus、Loki 和 Tempo 查詢同一批資料,才能證明 exporter 連到的是可用 backend,而不是只有資料進到 Collector。

debug exporter 的輸出本身也可能包含 telemetry 內容,因此只適合在受控的開發環境使用。真正的服務仍不應把 password、token、email、Authorization header 或 Todo 內容寫入 telemetry。

下一篇:讓 Trace 跨服務串起來

Collector 已能接收與處理 telemetry,但 BFF 和 todo-api 還需要正確傳遞 traceparent,才能讓 backend 將兩個服務的 span 視為同一筆請求。下一篇會從這個 HTTP context propagation 開始,建立跨服務的 Trace。


上一篇
Day 10 - OpenTelemetry 的資料格式與元件
下一篇
Day 12 - 用 Distributed Tracing 找出微服務的瓶頸
系列文
寫完微服務然後呢?走向平台工程的黃金路徑 共 15 篇
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言