Dockerfile集成SkyWalking APM避坑指南)
最近給一個(gè) Java 服務(wù)做容器化改造正好趕上要給系統(tǒng)接 SkyWalking 做鏈路追蹤就想在 Dockerfile 里直接把 agent 打進(jìn)鏡像省得每次發(fā)布還要單獨(dú)掛目錄、搞版本同步。第一版寫得很順以為加個(gè)-javaagent就完事了結(jié)果鏡像能起、業(yè)務(wù)也正常SkyWalking 后端卻怎么都查不到這個(gè)服務(wù)折騰了大半天才定位到問題。從頭到尾踩了三個(gè)坑基礎(chǔ)鏡像里/tmp目錄不可寫、agent 版本和 OAP 后端版本不對(duì)齊、上報(bào)地址把 gRPC 端口和 HTTP 端口搞混了。這篇文章就是想把 Dockerfile 配置 SkyWalking 的完整思路、可以直接抄的代碼模板和排查方法整理出來(lái)給正在做微服務(wù)容器化改造、想在鏡像里內(nèi)置 APM agent 的 Java 開發(fā)和運(yùn)維同學(xué)做個(gè)參考。不管你是剛接觸容器化的新手還是已經(jīng)在生產(chǎn)環(huán)境摸爬滾打過的老手按照這里的思路走一遍能少踩不少坑。1. 先把方案選型想明白為什么要把 agent 直接做進(jìn)鏡像里1.1 從 APM 的接入方式聊起SkyWalking 是一個(gè)開源的 APM 系統(tǒng)核心價(jià)值是鏈路追蹤、服務(wù)拓?fù)洹⑿阅芷饰龊透婢?。Java 服務(wù)接入 SkyWalking 幾乎不需要改業(yè)務(wù)代碼只要在 JVM 啟動(dòng)時(shí)掛一個(gè)-javaagent參數(shù)指向 skywalking-agent.jar字節(jié)碼增強(qiáng)就能自動(dòng)完成埋點(diǎn)采集。這個(gè)模式很像快遞驛站給包裹裝追蹤標(biāo)簽包裹本身不用改樣驛站按尺寸給每個(gè)包裹貼一張單子快遞系統(tǒng)就能全程看到它到了哪一站、停了多久、在哪一站異常了。業(yè)務(wù)代碼就是包裹agent 就是那張標(biāo)簽JVM 啟動(dòng)參數(shù)就是貼標(biāo)簽的動(dòng)作。既然接入方式這么簡(jiǎn)單那問題就是agent 這個(gè)標(biāo)簽放在哪里常見的做法有三類我在實(shí)際項(xiàng)目里都試過各有各的坑。1.2 三種常見接入方案對(duì)比第一種也是最推薦的做法就是在 Dockerfile 構(gòu)建階段就把 agent 打進(jìn)鏡像run 起來(lái)的時(shí)候啟動(dòng)腳本自動(dòng)帶上-javaagent。交付的鏡像是自包含的開發(fā)測(cè)試環(huán)境和生產(chǎn)環(huán)境拿到的產(chǎn)物完全一致不會(huì)出現(xiàn)本地能看鏈路、測(cè)試環(huán)境看不了的問題。第二種是用 K8s 的 Volume 把 agent 目錄掛載進(jìn)容器鏡像保持干凈不裝任何 agent 相關(guān)的東西。聽起來(lái)挺優(yōu)雅但實(shí)際維護(hù)起來(lái)很痛苦每一個(gè)節(jié)點(diǎn)都要準(zhǔn)備一份 agent 二進(jìn)制升級(jí) agent 版本的時(shí)候所有節(jié)點(diǎn)的文件都要跟著換稍有不慎就是新舊版本混用。要是碰到那種直接跑 Docker 的虛擬機(jī)環(huán)境你還得單獨(dú)去每臺(tái)機(jī)器上準(zhǔn)備目錄鏡像本身反而失去了可移植性。第三種是通過 Maven 插件或 JIB 等工具在構(gòu)建鏡像的時(shí)候把 agent 塞進(jìn)去適合已經(jīng)統(tǒng)一了 CI 構(gòu)建流程的團(tuán)隊(duì)。但這個(gè)方案對(duì)現(xiàn)有構(gòu)建鏈路侵入比較大而且出了問題不好排查不是所見即所得。三者的取舍我用一張表總結(jié)一下方便你根據(jù)團(tuán)隊(duì)情況選擇對(duì)比維度Dockerfile 內(nèi)置Volume 掛載構(gòu)建插件注入鏡像自包含是否是版本一致性高低高部署復(fù)雜度低中高中排障直觀性高低中適合場(chǎng)景多數(shù)微服務(wù)團(tuán)隊(duì)多租戶共享節(jié)點(diǎn)已有強(qiáng) CI 體系我個(gè)人的建議很簡(jiǎn)單只要你的服務(wù)是走容器化交付就優(yōu)先把 agent 做進(jìn)鏡像。體積多幾十兆完全無(wú)所謂換來(lái)的是部署和排查的確定性這筆賬怎么算都劃算。1.3 先把版本對(duì)應(yīng)關(guān)系定下來(lái)再動(dòng)手寫選方案之前有一件事必須提前確認(rèn)agent 版本和 OAP 服務(wù)端版本要匹配。SkyWalking 的 Java Agent 和 OAP 之間的通信協(xié)議是分版本的跨大版本連基本都會(huì)出問題。比如 8.x 的 agent 去連 9.x 的 OAP很常見的情況是 agent 啟動(dòng)日志看著正常但數(shù)據(jù)就是注冊(cè)不上去UI 里服務(wù)列表永遠(yuǎn)空白。正確做法是先看你們線上 OAP 是什么版本再去下載對(duì)應(yīng)版本的 java-agent 包。這里給一個(gè)簡(jiǎn)單的版本對(duì)應(yīng)規(guī)律8.x 的 OAP 配 8.x 的 agent9.x 的 OAP 配 9.x 的 agent不要在同一個(gè)大版本里混用不同小版本比如 8.16.0 的 agent 配 8.9.0 的 OAP雖然大部分情況能用但有些新上報(bào)的指標(biāo)在老版本 OAP 上解析不了會(huì)直接影響展示。另外還要注意 JDK 版本。SkyWalking 8.x 的 agent 支持 JDK 8 到 179.x 在此基礎(chǔ)上覆蓋更廣。如果你的服務(wù)還在 JDK 7 或者更老的版本上就得考慮上歷史版本的 agent 了這一點(diǎn)在做 MES 這類傳統(tǒng)制造系統(tǒng)兼容性評(píng)估時(shí)尤其重要后面第 5 節(jié)我會(huì)專門展開說。2. Dockerfile 核心配置細(xì)節(jié)每個(gè)關(guān)鍵點(diǎn)都藏著一個(gè)坑2.1 基礎(chǔ)鏡像怎么選不是隨便拉個(gè) JDK 鏡像就完事基礎(chǔ)鏡像是 Dockerfile 的地基很多人習(xí)慣直接用openjdk:8-jdk-alpine圖它體積小。但如果你要在里面跑 SkyWalking agent這個(gè)選擇可能會(huì)讓你在深更半夜排查的時(shí)候懷疑人生。Alpine 系統(tǒng)用的是 musl libc不是標(biāo)準(zhǔn)的 glibc。SkyWalking agent 內(nèi)部依賴的很多組件在 glibc 環(huán)境下測(cè)試最充分放到 musl 環(huán)境中偶爾會(huì)出現(xiàn)文件鎖、socket 通信異常、線程調(diào)度異常這類莫名其妙的問題。agent 加載本身不報(bào)錯(cuò)但采集數(shù)據(jù)就是不穩(wěn)定。我記得有一次在一個(gè) Alpine 鏡像里部署服務(wù)能正常跑SkyWalking 的 UI 上拓?fù)鋱D卻時(shí)有時(shí)無(wú)后來(lái)把基礎(chǔ)鏡像從 Alpine 換成 Ubuntu 底層的 temurin問題就再?zèng)]出現(xiàn)過。如果你想少在半夜被叫醒生產(chǎn)環(huán)境基礎(chǔ)鏡像建議直接用 Eclipse Temurin它維護(hù)規(guī)范、CVE 修復(fù)及時(shí)底層是 Ubuntuglibc 環(huán)境穩(wěn)妥。根據(jù)你的 JDK 版本選對(duì)應(yīng)的 tag 就行。如果項(xiàng)目還在用 Java 8就eclipse-temurin:8-jreJava 11 就eclipse-temurin:11-jreJava 17 就eclipse-temurin:17-jre。是選 JRE 還是 JDK多數(shù)情況 JRE 就夠用了但如果后續(xù)要自己擴(kuò)展 agent 插件或者做一些深入的字節(jié)碼調(diào)試選 JDK 會(huì)更省事。時(shí)區(qū)配置也要在基礎(chǔ)鏡像階段解決。容器默認(rèn)是 UTC 時(shí)間如果你的服務(wù)是面向國(guó)內(nèi)用戶的日志和監(jiān)控?cái)?shù)據(jù)的時(shí)間戳?xí)?8 個(gè)小時(shí)排查問題時(shí)很難受。我一般會(huì)在 Dockerfile 里加一行ENV TZAsia/Shanghai RUN ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime這樣容器內(nèi)執(zhí)行的 Java 進(jìn)程、agent 寫的日志時(shí)間都是東八區(qū)不用再對(duì)著時(shí)間戳做減法。2.2 agent 下載與多階段構(gòu)建不要在生產(chǎn)鏡像里留一堆構(gòu)建工具下載 SkyWalking agent 有一個(gè)現(xiàn)實(shí)問題公網(wǎng)下載速度受網(wǎng)絡(luò)環(huán)境影響大直接在 Dockerfile 里用ADD https://...拉取每次構(gòu)建都可能因?yàn)榫W(wǎng)絡(luò)波動(dòng)失敗。更穩(wěn)妥的做法是把 agent 包先下載到公司內(nèi)部的制品庫(kù)比如 Nexus 或 ArtifactoryDockerfile 里從內(nèi)網(wǎng)地址拉取構(gòu)建穩(wěn)定性和速度都會(huì)有保障。拿到 tar.gz 包之后解壓出來(lái)是一個(gè)skywalking-agent目錄里面包含了skywalking-agent.jar、plugins/、config/、logs/等子目錄。需要注意plugins/目錄里的插件不能隨便刪它是 SkyWalking 能采集各種中間件鏈路的底氣logs/目錄是運(yùn)行時(shí)寫日志用的鏡像里要有對(duì)應(yīng)的可寫權(quán)限。一個(gè)典型的下載寫法是這樣FROM alpine:3.18 AS skywalking-download RUN apk add --no-cache ca-certificates tar ARG SW_AGENT_VERSION8.16.0 ADD https://archive.apache.org/dist/skywalking/java-agent/${SW_AGENT_VERSION}/apache-skywalking-java-agent-${SW_AGENT_VERSION}.tgz /tmp/agent.tgz RUN tar -zxf /tmp/agent.tgz -C /opt用多階段構(gòu)建是這里的關(guān)鍵思路。第一階段只負(fù)責(zé)下載和解壓第二階段 COPY 的時(shí)候只把解壓好的目錄復(fù)制過去最終運(yùn)行鏡像里不會(huì)殘留 curl、tar、apk 這類構(gòu)建工具和包管理緩存鏡像更小、更安全CVE 面也更小。2.3 環(huán)境變量與啟動(dòng)參數(shù)注入讓你少踩兩個(gè)隱形坑SkyWalking agent 支持用環(huán)境變量覆蓋配置文件里的參數(shù)這比在 Dockerfile 里硬編碼-Dskywalking.xxx要靈活得多。最常用的兩個(gè)環(huán)境變量是SW_AGENT_NAME服務(wù)名和SW_AGENT_COLLECTOR_BACKEND_SERVICESOAP 后端地址。如果你在 Dockerfile 里寫ENV SW_AGENT_NAMEmes-service \ SW_AGENT_COLLECTOR_BACKEND_SERVICESskywalking-oap:11800那么在部署到 K8s 的時(shí)候只要在 Deployment 的 env 里覆蓋同名變量就能做到不重新構(gòu)建鏡像就調(diào)整服務(wù)名或后端地址。這樣一套鏡像可以部署多個(gè)環(huán)境非常實(shí)用。這里有一個(gè)特別容易踩的坑OAP 的 gRPC 端口默認(rèn)是 11800UI 查詢端口是 12800而很多新手會(huì)把collector.backend_service配成http://xxx:12800或者干脆寫成 8080結(jié)果 agent 一直連不上后端。注意這里不需要寫http://前綴直接寫host:11800就行agent 走的是 gRPC 協(xié)議不是你瀏覽器訪問 UI 的那個(gè)端口。啟動(dòng)參數(shù)方面有兩種注入方式一是用JAVA_TOOL_OPTIONS環(huán)境變量JVM 會(huì)自動(dòng)讀取但每次啟動(dòng)都會(huì)打印一行Picked up JAVA_TOOL_OPTIONS比較污染日志二是用JAVA_OPTS環(huán)境變量配合自定義入口腳本拼接靈活性和可控性都更好。我在生產(chǎn)環(huán)境更喜歡后者因?yàn)榭梢栽谀_本里做各種判斷和預(yù)處理而且不會(huì)被 JVM 自動(dòng)拾取的機(jī)制干擾。3. 完整實(shí)操?gòu)牧銓懸粋€(gè)能上生產(chǎn)環(huán)境的 Dockerfile3.1 直接可用的 Dockerfile 模板下面這個(gè) Dockerfile 是我在多個(gè)項(xiàng)目里反復(fù)用過的模板改一改業(yè)務(wù) jar 名和版本號(hào)就能用。它同時(shí)處理了時(shí)區(qū)、agent 版本鎖定、非 root 用戶、多階段構(gòu)建這幾個(gè)要點(diǎn)# 階段一只負(fù)責(zé)準(zhǔn)備 SkyWalking Agent FROM alpine:3.18 AS skywalking-download RUN apk add --no-cache ca-certificates tar ARG SW_AGENT_VERSION8.16.0 ADD https://archive.apache.org/dist/skywalking/java-agent/${SW_AGENT_VERSION}/apache-skywalking-java-agent-${SW_AGENT_VERSION}.tgz /tmp/agent.tgz RUN tar -zxf /tmp/agent.tgz -C /opt # 階段二業(yè)務(wù)運(yùn)行鏡像 FROM eclipse-temurin:8-jre ENV TZAsia/Shanghai \ SW_AGENT_NAMEmes-service \ SW_AGENT_COLLECTOR_BACKEND_SERVICESskywalking-oap:11800 RUN ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime \ mkdir -p /app/logs /opt/skywalking-agent/logs \ useradd -r -s /sbin/nologin appuser WORKDIR /app COPY --fromskywalking-download /opt/skywalking-agent /opt/skywalking-agent COPY app.jar /app/app.jar COPY entrypoint.sh /app/entrypoint.sh RUN chmod x /app/entrypoint.sh chown -R appuser:appuser /app /opt/skywalking-agent USER appuser EXPOSE 8080 ENTRYPOINT [/app/entrypoint.sh]這個(gè)模板里有幾個(gè)細(xì)節(jié)值得你注意。第一我單獨(dú)創(chuàng)建了/opt/skywalking-agent/logs目錄并且把整個(gè) agent 目錄的屬主改成了非 root 用戶否則 agent 運(yùn)行時(shí)寫不了日志啟動(dòng)日志里會(huì)刷一堆Permission denied但業(yè)務(wù)進(jìn)程本身不報(bào)錯(cuò)極易漏判。第二agent 的 jar 包是通過 COPY 從第一階段拿來(lái)的運(yùn)行鏡像里沒有任何包管理器鏡像很干凈。第三我用的是非 root 用戶appuser來(lái)跑業(yè)務(wù)這是容器安全的基本要求能夠避免容器內(nèi)進(jìn)程以 root 權(quán)限被攻破后直接操作宿主機(jī)。3.2 entrypoint.sh 啟動(dòng)腳本agent 加載的正確姿勢(shì)Dockerfile 里的 ENTRYPOINT 指向的腳本負(fù)責(zé)在容器啟動(dòng)時(shí)把-javaagent拼進(jìn) JVM 啟動(dòng)命令。最簡(jiǎn)版本長(zhǎng)這樣#!/bin/sh set -e AGENT_PATH/opt/skywalking-agent/skywalking-agent.jar if [ ! -f ${AGENT_PATH} ]; then echo [ERROR] SkyWalking agent not found at ${AGENT_PATH} exit 1 fi JAVA_OPTS${JAVA_OPTS} -javaagent:${AGENT_PATH} exec java ${JAVA_OPTS} -jar /app/app.jar $這個(gè)腳本做了三件事校驗(yàn) agent 文件存在、把外部傳入的JAVA_OPTS和-javaagent拼接起來(lái)、用exec啟動(dòng) Java 進(jìn)程。注意最后一行用了exec這個(gè)不是可有可無(wú)的細(xì)節(jié)。用exec之后Java 進(jìn)程會(huì)直接替換掉 shell 進(jìn)程容器的 1 號(hào)進(jìn)程就是 Java 進(jìn)程本身這樣容器收到 SIGTERM 信號(hào)時(shí)Java 進(jìn)程能直接響應(yīng)配合 JVM 的優(yōu)雅停機(jī)機(jī)制完成收尾。如果不用execshell 會(huì)成為 1 號(hào)進(jìn)程信號(hào)先打到 shell 上程序退出行為會(huì)變得不可控。SkyWalking agent 本身的配置在上面的 Dockerfile 里已經(jīng)通過環(huán)境變量指定了。如果你需要在腳本里做一些個(gè)性化處理比如動(dòng)態(tài)設(shè)置服務(wù)名、按環(huán)境切換 OAP 地址也完全可以在這個(gè)腳本里加邏輯自由度比JAVA_TOOL_OPTIONS大得多。3.3 構(gòu)建、運(yùn)行與驗(yàn)證怎么確認(rèn) agent 真的起了作用鏡像文件準(zhǔn)備齊了接下來(lái)就是構(gòu)建和驗(yàn)證。構(gòu)建命令很簡(jiǎn)單docker build -t my-mes-service:1.0.0 .跑起來(lái)的時(shí)候可以手動(dòng)覆蓋環(huán)境變量來(lái)模擬不同環(huán)境docker run -d --name mes-service \ -e SW_AGENT_NAMEmes-service-test \ -e SW_AGENT_COLLECTOR_BACKEND_SERVICES192.168.10.20:11800 \ -p 8080:8080 \ my-mes-service:1.0.0這里覆蓋了 Dockerfile 里默認(rèn)的SW_AGENT_NAME和 OAP 地址模擬的是測(cè)試環(huán)境連接不同的后端。這樣你就能理解為什么我前面強(qiáng)烈推薦用環(huán)境變量而不是寫死參數(shù)部署的靈活性就體現(xiàn)在這里。啟動(dòng)之后第一步是看 agent 自己的日志docker exec -it mes-service tail -f /opt/skywalking-agent/logs/skywalking-agent.log如果 agent 加載正常這個(gè)日志里會(huì)有啟動(dòng)信息并且會(huì)顯示 OAP 地址。如果連不上后端日志里會(huì)有明顯的連接異?;蛑卦囆畔?。第二步是打開 SkyWalking UI在服務(wù)列表里找mes-service-test能看到就說明注冊(cè)成功了。第三步是主動(dòng)打幾條請(qǐng)求過去過一兩分鐘到 Traces 頁(yè)面看有沒有鏈路數(shù)據(jù)。這里有個(gè)經(jīng)驗(yàn)鏈路數(shù)據(jù)通常要等請(qǐng)求發(fā)生之后才上報(bào)不是服務(wù)一注冊(cè)就立刻有 trace。很多新手啟動(dòng)完發(fā)現(xiàn) UI 里沒數(shù)據(jù)就以為失敗了其實(shí)只要服務(wù)列表里有你注冊(cè)的服務(wù)名就已經(jīng)成功了一大半剩下的只是等流量進(jìn)來(lái)。4. 生產(chǎn)環(huán)境常見坑與排查實(shí)錄4.1 服務(wù)老是不上報(bào)按這個(gè)順序排查我接手過好幾個(gè)團(tuán)隊(duì)的容器化排查發(fā)現(xiàn)大家遇到的問題高度相似。服務(wù)不上報(bào)數(shù)據(jù)時(shí)不要一個(gè)一個(gè)按鈕亂點(diǎn)按下面的順序來(lái)先查 agent 能不能啟動(dòng)???opt/skywalking-agent/logs/下的日志如果這個(gè)文件壓根不存在說明 agent 連寫日志的權(quán)限都沒有或者啟動(dòng)參數(shù)根本就沒帶上去。二查 agent 日志里有沒有異常堆棧最常見的兩個(gè)錯(cuò)誤agent 版本與 OAP 不兼容、找不到collector.backend_service配置。三查網(wǎng)絡(luò)連通性。agent 和 OAP 之間走 gRPC端口默認(rèn) 11800很多微服務(wù)集群的網(wǎng)絡(luò)策略只放開了 HTTP 端口gRPC 端口是通的但防火墻沒放行也會(huì)導(dǎo)致連接超時(shí)。在容器里執(zhí)行nc -zv skywalking-oap 11800驗(yàn)證一下是最直接的。我遇到過最隱蔽的一個(gè)問題K8s 集群里 agent 和 OAP 之間網(wǎng)絡(luò)沒問題但 agent 日志里反復(fù)出現(xiàn)Channel ... is not active最后查出來(lái)是 OAP 的 Pod 有多個(gè)副本其中一個(gè)副本所在的節(jié)點(diǎn)內(nèi)存壓力太大OAP 一直在 GC導(dǎo)致某些 gRPC 連接建立后又被重置。這種情況就不是 Dockerfile 能解決的了得從后端資源規(guī)劃去找原因。4.2 時(shí)區(qū)、臨時(shí)目錄、協(xié)議端口三個(gè)看起來(lái)不像問題的問題第一個(gè)是時(shí)區(qū)。容器默認(rèn) UTC如果 Dockerfile 里沒有設(shè)置TZAsia/Shanghaiagent 日志時(shí)間會(huì)比北京時(shí)間慢 8 小時(shí)你看到這個(gè)時(shí)間點(diǎn)沒有數(shù)據(jù)其實(shí)只是時(shí)間標(biāo)簽錯(cuò)位。更麻煩的是 OAP 服務(wù)端如果沒有統(tǒng)一時(shí)區(qū)配置UI 上展示的曲線按小時(shí)錯(cuò)位排查半天發(fā)現(xiàn)是時(shí)區(qū)問題很浪費(fèi)精力。第二個(gè)是/tmp目錄權(quán)限?,F(xiàn)在安全掃描和運(yùn)行策略普遍要求容器以非 root 用戶啟動(dòng)但很多精簡(jiǎn)鏡像的/tmp目錄默認(rèn)權(quán)限是drwxrwxrwt非 root 用戶按理說也能寫。問題常出在那些在加固鏡像上又加了一層只讀根文件系統(tǒng)策略的環(huán)境里agent 初始化時(shí)需要寫臨時(shí)文件寫不進(jìn)去就直接崩潰或者靜默降級(jí)。解決方法是提前建一個(gè)應(yīng)用可寫的目錄并且通過 JVM 參數(shù)指向它JAVA_OPTS${JAVA_OPTS} -Djava.io.tmpdir/app/tmp第三個(gè)是協(xié)議端口。collector.backend_service一定要寫 OAP 的 gRPC 端口默認(rèn)是 11800。UI 的訪問端口是 8080OAP 的 HTTP 查詢端口是 12800這三個(gè)端口各有各的用途但它們之間是獨(dú)立的。配成什么http://127.0.0.1:8080之類agent 自然連不上。每次遇到服務(wù)看不到的問題我都會(huì)第一時(shí)間去檢查這個(gè)變量。4.3 常見問題速查表為了方便你排查時(shí)對(duì)照我把高頻問題整理成了速查表癥狀常見原因處理建議agent 啟動(dòng)日志為空或不存在目錄不可寫、-javaagent未生效檢查鏡像權(quán)限、確認(rèn) entrypoint 是否執(zhí)行啟動(dòng)日志提示 agent jar 無(wú)法加載COPY 路徑不對(duì)或 jar 損壞檢查 Dockerfile 中 COPY 前后路徑服務(wù)列表看不到新服務(wù)agent 與 OAP 版本不兼容兩端統(tǒng)一到同一大版本8.x/9.x服務(wù)能看到但 Track 沒有數(shù)據(jù)請(qǐng)求流量未經(jīng)過 agent 埋點(diǎn)確認(rèn)啟動(dòng)命令確實(shí)帶上了-javaagentOAP 日志顯示連接被重置網(wǎng)絡(luò)策略限制 gRPC 端口放行 11800檢查集群網(wǎng)絡(luò)策略UI 時(shí)間曲線整體偏移時(shí)區(qū)配置不一致統(tǒng)一設(shè)置TZAsia/Shanghaiagent 日志有 gRPC 連接異常backend_service 端口錯(cuò)誤改為host:11800不要寫 HTTP這個(gè)表我實(shí)際用下來(lái)很有效基本覆蓋了 80% 的接入問題。如果你的問題不在表里記住一個(gè)核心思路任何 APM 接入問題永遠(yuǎn)都是從 agent 日志門口第一塊磚開始查不要跳過去猜。5. 延伸SkyWalking 能部署到 MES 制造系統(tǒng)上嗎5.1 先給結(jié)論能而且非常適合很多做制造業(yè)數(shù)字化的人會(huì)問MES 制造執(zhí)行系統(tǒng)能不能上 SkyWalking。這個(gè)問題需要分兩層看第一層MES 系統(tǒng)只要跑在 JVM 上就能掛 agent 接 SkyWalking和它是不是制造系統(tǒng)沒有本質(zhì)區(qū)別第二層MES 系統(tǒng)通常部署在工廠內(nèi)網(wǎng)網(wǎng)絡(luò)環(huán)境比較封閉后端組件需要跟著內(nèi)網(wǎng)策略一起規(guī)劃。我經(jīng)手的 MES 項(xiàng)目里技術(shù)?;径际?Java Spring Boot MySQL服務(wù)數(shù)量一般在二三十個(gè)以內(nèi)。這種體量接入 SkyWalking 后的收益非常直觀工單流轉(zhuǎn)慢、設(shè)備數(shù)采延遲、過站事務(wù)卡頓這類問題之前排查要翻半天日志有了鏈路追蹤以后一眼就能看到是哪一次遠(yuǎn)程調(diào)用耗時(shí)最長(zhǎng)、哪一個(gè) SQL 出現(xiàn)了慢查詢。有一點(diǎn)需要特別提醒MES 行業(yè)里至今還有不少系統(tǒng)跑在 JDK 7 甚至更老的版本上。SkyWalking 從 8.x 開始對(duì) JDK 版本有硬性要求JDK 7 的項(xiàng)目只能考慮更早的 agent 版本但這又意味著功能不完整、維護(hù)成本高。所以接到 MES 接入需求時(shí)先做的應(yīng)該是摸清線上 JDK 版本這決定了你能不能用上現(xiàn)代版本的 SkyWalking。5.2 部署形態(tài)與資源規(guī)劃建議MES 系統(tǒng)的部署環(huán)境常見有單機(jī) Docker Compose 和 K8s 集群兩種。中小型 MES 如果只有十幾二十個(gè)服務(wù)部署單機(jī)模式完全夠用OAP 一個(gè)進(jìn)程、UI 一個(gè)進(jìn)程存儲(chǔ)直接用 MySQL 庫(kù)注意提前初始化 SkyWalking 所需的表結(jié)構(gòu)即可。這個(gè)形態(tài)三臺(tái) 8C16G 的機(jī)器可以跑得很舒適。規(guī)模大一些、或者對(duì)服務(wù)可靠性要求高的 MES 集群建議走 K8s 部署 OAP 集群存儲(chǔ)換 Elasticsearch。這里要給一個(gè)明確建議trace 數(shù)據(jù)量上來(lái)之后MySQL 做存儲(chǔ)會(huì)逐漸吃緊ES 的寫入和查詢效率明顯更好。初期數(shù)據(jù)量小的時(shí)候可以用 MySQL 省運(yùn)維成本一旦服務(wù)數(shù)量超過四五十個(gè)、核心鏈路的 trace 量每天幾百萬(wàn)上千萬(wàn)條就要考慮遷移到 ES 了。agent 對(duì)業(yè)務(wù)性能的影響方面以我的實(shí)測(cè)經(jīng)驗(yàn)來(lái)看常規(guī) Web 接口的損耗大概在 5% 到 10%大部分場(chǎng)景可以接受。但 MES 系統(tǒng)里有不少高頻采集服務(wù)每秒鐘要處理上千條設(shè)備數(shù)據(jù)這類服務(wù)上 agent 之前最好先做一輪壓測(cè)對(duì)比可以在 Dockerfile 層面通過環(huán)境變量控制SW_AGENT_SAMPLING_RATE把采樣率調(diào)整到更低區(qū)間比如 1%在業(yè)務(wù)影響和監(jiān)控力度之間找平衡。接入節(jié)奏上我強(qiáng)烈建議先在測(cè)試環(huán)境跑通整個(gè)鏈路再挑一兩個(gè)非核心服務(wù)觀察兩三天確認(rèn)穩(wěn)定后逐步推廣。這樣既能保證監(jiān)控真正服務(wù)生產(chǎn)也不會(huì)因?yàn)橐淮渭みM(jìn)改造把制造系統(tǒng)的穩(wěn)定性搞出問題。我做 MES 項(xiàng)目的感受是SkyWalking 這套東西本身技術(shù)門檻不高真正決定體驗(yàn)的往往是在 Dockerfile 里那些細(xì)節(jié)agent 放進(jìn)鏡像、版本鎖對(duì)、環(huán)境變量分清、端口和權(quán)限都處理干凈。你把這些基礎(chǔ)設(shè)施搭好了后面接任何服務(wù)都只是復(fù)制模板改個(gè)名的事。