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

Service 只負責把資料送到 Collector Pod;資料進入 Collector 後,會依 service.pipelines 中列出的順序經過 receiver、processor 和 exporter。設定檔裡宣告 processor 還不夠,必須放進 pipeline 才會執行。
先建立一個獨立的 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。
以下 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
先確認健康檢查 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。
Collector 已能接收與處理 telemetry,但 BFF 和 todo-api 還需要正確傳遞 traceparent,才能讓 backend 將兩個服務的 span 視為同一筆請求。下一篇會從這個 HTTP context propagation 開始,建立跨服務的 Trace。