Day05 我們佈署了 Stable 跟 Canary 兩個版本,每個版本的監控數據要能分開看,也要能放在一起比。
最直覺的做法是在 Spring Boot 代碼裡自己加埋點,但每次要監控新的東西,都得回頭改代碼、重新測試、重新部署,維護成本高,也容易漏埋。
所以今天的做法是:不改代碼,用 OTel Java Agent 讓兩個版本各自產生監控數據,並且用同一個服務名稱、只靠版本標籤區分。

先簡單講一點 Java 編譯邏輯:
.java)編譯後會變成位元組碼(bytecode),也就是 .class 檔裡的指令。1. java.lang.instrument 是什麼
2. -javaagent 與 premain
-javaagent:<jar 路徑>,JVM 就知道要載入這個 agent。premain(agent 的進場點)main
premain 跑在前面,agent 有機會在 Spring Boot、Tomcat 等 class 被載入之前,先登記「這些 class 進來時通知我」。3. OTel Agent 插入了什麼
4. 攔截的位置
/api/hello。5. 為什麼說「零侵入」
JAVA_TOOL_OPTIONS 拿掉重啟,程式就回到原樣。RestTemplate 而不是 RestClient,就是因為前者在官方支援清單裡有明確條目。在 Day05 兩份 Deployment 的 container 裡,各自加上環境變數。
Stable(demo-app-v1.yaml):
env:
- name: JAVA_TOOL_OPTIONS
value: "-javaagent:/workspace/opentelemetry-javaagent.jar"
- name: OTEL_SERVICE_NAME
value: "demo-app"
- name: OTEL_RESOURCE_ATTRIBUTES
value: "service.version=v1,deployment.environment=production"
Canary(demo-app-v2-canary.yaml):
env:
- name: JAVA_TOOL_OPTIONS
value: "-javaagent:/workspace/opentelemetry-javaagent.jar"
- name: OTEL_SERVICE_NAME
value: "demo-app"
- name: OTEL_RESOURCE_ATTRIBUTES
value: "service.version=v2-canary,deployment.environment=production"
兩份幾乎一模一樣,唯一的差異就是 OTEL_RESOURCE_ATTRIBUTES 裡的 service.version。
OTEL_SERVICE_NAME 兩邊都設成同一個 demo-app,是為了讓之後 Prometheus/Tempo 能用 service.version(v1 vs v2-canary)這個維度,在「同一個服務」底下比較兩個版本的延遲跟錯誤率。如果兩邊 service.name 不一樣,追蹤系統會把它們當成兩個完全無關的服務,沒辦法放在同一張圖上比較。opentelemetry-javaagent.jar)是 demo-app 的 Dockerfile 在 build image 時下載的(鎖定版本 v2.29.0),放在 image 的 /workspace/ 路徑。Deployment 只需要透過 JAVA_TOOL_OPTIONS 宣告路徑去載入它,Pod 啟動後 Agent 就跟著啟動。JAVA_TOOL_OPTIONS 是 JVM 啟動時會讀取的環境變數,放進去的 -javaagent:... 效果等同於直接寫在啟動指令上(官方 Getting started 兩種寫法都有列)。用環境變數的好處是不用改 image 裡的啟動指令,由 Deployment 決定要不要啟用 Agent。-javaagent 與 JAVA_TOOL_OPTIONS 兩種啟用寫法premain 的呼叫時機