背景
OpenTelemetry 探針
OpenTelemetry(簡稱 Otel芳室,最新的版本是 1.27) 是一個用于觀察性的開源項目,提供了一套工具糙箍、APIs 和 SDKs渤愁,用于收集、處理和導(dǎo)出遙測數(shù)據(jù)(如指標(biāo)深夯、日志和追蹤信息)抖格。應(yīng)用程序遙測數(shù)據(jù)(如追蹤、指標(biāo)和日志)的收集是通過探針來完成的咕晋,探針通常以庫的形式集成到應(yīng)用程序中雹拄,自動捕獲重要信息協(xié)助監(jiān)控和調(diào)試。OpenTelemetry 探針支持市面上大多數(shù)的編程語言掌呜,探針的安裝(通常被稱為插樁滓玖,Instrumentation)分為手動和自動兩種方式。
- 手動插樁:指開發(fā)者直接在其應(yīng)用程序代碼中顯式地添加遙測數(shù)據(jù)收集的代碼质蕉,需要手動完成 SDK 初始化势篡、插入追蹤點、添加上下文信息等一系列操作模暗。
- 自動插樁:利用 OpenTelemetry 提供的庫自動捕獲應(yīng)用程序的遙測數(shù)據(jù)禁悠,無需或只需很少的代碼更改。比如兑宇,Java 通過
javaagent
實現(xiàn)探針的自動安裝碍侦。
二者各有優(yōu)劣:手動插樁適用于需要高度定制和精確控制遙測數(shù)據(jù)收集的場景;自動插樁適合快速啟動和簡化集成,特別是在使用標(biāo)準(zhǔn)框架和庫的應(yīng)用程序中瓷产。
OpenTelemetry Operator 介紹
OpenTelemetry Operator 是一個為了簡化 OpenTelemetry 組件在 Kubernetes 環(huán)境中的部署和管理而設(shè)計的 Kubernetes Operator站玄。
OpenTelemetry Operator 通過 CRD(OpenTelemetryCollector、Instrumentation濒旦、OpAMPBridge) 實現(xiàn)在 Kubernetes 集群中自動部署和管理 OpenTelemetry Collector株旷;在工作負(fù)載中自動安裝 OpenTelemetry 探針。
今天我們就將體驗如何使用 OpenTelemetry Operator 自動安裝探針疤估,實現(xiàn)鏈路跟蹤灾常。
演示
架構(gòu)
這是演示的架構(gòu),Otel 提供了 多種語言的 instrumentation SDK铃拇,這篇文章中我們將使用 Java 和 Go 兩種語言的應(yīng)用钞瀑。這兩種語言會使用全自動和半自動的注入安裝:
- Java 全自動注入安裝,Otel Operator 通過使用 init container 引入 sdk 慷荔,并通過
JAVA_TOOL_OPTIONS
來指定javaagent
來插樁雕什。這里將使用pinakispecial/spring-boot-rest
鏡像來運行一個簡單的 Spring Boot REST 服務(wù)。 - Go 半自動注入安裝显晶,為什么是半自動贷岸?Go 的全自動是通過 eBPF 的方式實現(xiàn)的:在 Pod 注入獨立的容器,加載 BPF 程序磷雇。但是 eBPF 的實現(xiàn)對內(nèi)核要求十分苛刻 5.4 - 5.14偿警。這里演示半自動的方式:手動引入 Go instrumentation SDK,自動注入配置唯笙。
Jaeger
為了便于演示這里使用 jaegertracing/all-in-one
鏡像來部署 Jaeger螟蒸,這個鏡像包含了 Jaeger 收集器、內(nèi)存存儲崩掘、查詢服務(wù)和 UI 等組件七嫌,非常適合開發(fā)和測試使用。
通過環(huán)境變量 COLLECTOR_OTLP_ENABLED
啟動對 OTLP(OpenTelemetry Protocol) 的支持苞慢。
kubectl apply -f - <<EOF
apiVersion: apps/v1
kind: Deployment
metadata:
name: jaeger
spec:
replicas: 1
selector:
matchLabels:
app: jaeger
template:
metadata:
labels:
app: jaeger
spec:
containers:
- name: jaeger
image: jaegertracing/all-in-one:latest
env:
- name: COLLECTOR_OTLP_ENABLED
value: "true"
ports:
- containerPort: 16686
- containerPort: 14268
---
apiVersion: v1
kind: Service
metadata:
name: jaeger
spec:
selector:
app: jaeger
type: ClusterIP
ports:
- name: ui
port: 16686
targetPort: 16686
- name: collector
port: 14268
targetPort: 14268
- name: http
protocol: TCP
port: 4318
targetPort: 4318
- name: grpc
protocol: TCP
port: 4317
targetPort: 4317
EOF
安裝 cert-manager
Otel Operator 依賴 cert-manager 進(jìn)行證書的管理诵原,安裝 operator 之前需要安裝 cert-manager。
kubectl apply -f https://github.com/cert-manager/cert-manager/releases/download/v1.13.2/cert-manager.yaml
安裝 OpenTelemetry Operator
執(zhí)行下面命令安裝 Otel Operator
kubectl apply -f https://github.com/open-telemetry/opentelemetry-operator/releases/latest/download/opentelemetry-operator.yaml
配置 OpenTelemetry Collector
通過創(chuàng)建 CR OpenTelemetryCollector 來配置 Otel 的采集器挽放,這里我們配置了:
-
otel
接收器:支持 grpc(端口4317
)和 http(端口4318
) -
memory_limiter
和batch
處理器绍赛,但是為了方便快速查看數(shù)據(jù),這兩個并沒有啟用辑畦,僅作展示用惹资。 -
debug
和otlp/jaeger
的輸出器,分別用于在標(biāo)準(zhǔn)輸出中打印信息和使用 otlp 協(xié)議輸出到 Jaeger航闺。 -
pipeline
服務(wù),用于配置跟蹤數(shù)據(jù)的處理流程:接收、處理和輸出潦刃。
kubectl apply -f - <<EOF
apiVersion: opentelemetry.io/v1alpha1
kind: OpenTelemetryCollector
metadata:
name: otel
spec:
config: |
receivers:
otlp:
protocols:
grpc:
http:
processors:
memory_limiter:
check_interval: 1s
limit_percentage: 75
spike_limit_percentage: 15
batch:
send_batch_size: 10000
timeout: 10s
exporters:
debug:
otlp/jaeger:
endpoint: "jaeger.default:4317"
tls:
insecure: true
service:
pipelines:
traces:
receivers: [otlp]
processors: []
exporters: [debug,otlp/jaeger]
EOF
創(chuàng)建 CR OpenTelemetryCollector 后侮措,Otel Operator 會創(chuàng)建一個 deployment 和 多個 service。
kubectl get deployment,service -l app.kubernetes.io/component=opentelemetry-collector
NAME READY UP-TO-DATE AVAILABLE AGE
deployment.apps/otel-collector 1/1 1 1 12h
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/otel-collector ClusterIP 10.43.152.81 <none> 4317/TCP,4318/TCP,8889/TCP,9411/TCP 12h
service/otel-collector-headless ClusterIP None <none> 4317/TCP,4318/TCP,8889/TCP,9411/TCP 12h
service/otel-collector-monitoring ClusterIP 10.43.115.103 <none> 8888/TCP 12h
Collector 部署的四種部署模型 Deployment乖杠、DaemonSet分扎、StatefulSet、Sidecar胧洒,默認(rèn)為 Deployment畏吓。
配置 Instrumentation
Instrumentation 是 Otel Operator 的另一個 CRD,用于自動安裝 Otel 探針和配置:
-
propagators
用于配置跟蹤信息在上下文的傳遞方式卫漫。 -
sampler
采樣器 -
env
和[language].env
添加到容器的環(huán)境變量
更多配置說明菲饼,請參考 Instrumentation API 文檔。
kubectl apply -f - <<EOF
apiVersion: opentelemetry.io/v1alpha1
kind: Instrumentation
metadata:
name: instrumentation-sample
spec:
propagators:
- tracecontext
- baggage
- b3
sampler:
type: parentbased_traceidratio
argument: "1"
env:
- name: OTEL_EXPORTER_OTLP_ENDPOINT
value: otel-collector.default:4318
java:
env:
- name: OTEL_EXPORTER_OTLP_ENDPOINT
value: http://otel-collector.default:4317
EOF
Java 示例應(yīng)用
為 Pod 添加注解 instrumentation.opentelemetry.io/inject-java: "true"
通知 Otel Operator 該應(yīng)用的類型以便注入正確的探針列赎。
kubectl apply -f - <<EOF
apiVersion: apps/v1
kind: Deployment
metadata:
name: java-sample
spec:
replicas: 1
selector:
matchLabels:
app: java-sample
template:
metadata:
labels:
app: java-sample
annotations:
instrumentation.opentelemetry.io/inject-java: "true"
spec:
containers:
- name: java-sample
image: pinakispecial/spring-boot-rest
ports:
- containerPort: 8080
EOF
可以看到 Otel Operator 向 Pod 中注入了一個 otel 的初始化容器宏悦。
以及在 java 容器中注入了一系列的環(huán)境變量進(jìn)行配置。
Go 示例應(yīng)用
前面提到 Go 語言的自動注入演示使用半自動的方式包吝,與本文的標(biāo)題不符饼煞,屬于嵌入式的。我寫了一個 簡單的 Go 應(yīng)用诗越,使用手動的方式來安裝 Otel 探針砖瞧,有興趣的可以查看源碼。
kubectl apply -f https://raw.githubusercontent.com/addozhang/http-sample/main/manifests/service-v1.yaml
查看 Pod 同樣可以看到通過環(huán)境變量的方式注入的 Otel 配置嚷狞。
測試
pod_name="$(kubectl get pod -n default -l app=service-a -o jsonpath='{.items[0].metadata.name}')"
kubectl port-forward $pod_name 8080:8080 &
curl localhost:8080
service-a(version: v1, ip: 10.42.0.68, hostname: service-a-5bf98748f5-l9pjw) -> service-b(version: v1, ip: 10.42.0.70, hostname: service-b-676c56fb98-rjbwv) -> service-c(version: v1, ip: 10.42.0.69, hostname: service-c-79985dc75d-bh68k)
發(fā)送請求后块促,打開 Jaeger UI。
jaeger_pod="$(kubectl get pod -l app=jaeger -o jsonpath='{.items[0].metadata.name}')"
kubectl port-forward $jaeger_pod 16686:16686 &
Bingo!
訪問 Jaeger UI 就可以看到這個訪問的鏈路信息了感耙。