前面我給大家分享了關(guān)于分布式鏈路追蹤的基本原理和SkyWalking的k8s部署玩法七芭,如果還沒(méi)來(lái)得及看的朋友可以看我上篇文章片习。
今天要給大家分享是我們?nèi)粘9ぷ髦凶畛R?jiàn)的一種場(chǎng)景,那就是部署在k8s環(huán)境下的Java微服務(wù)枪眉,要接入SkyWalking的具體玩法捺檬,通過(guò)這個(gè)過(guò)程咱們可以更深入的理解SkyWalking進(jìn)行數(shù)據(jù)采集的邏輯,也能更深刻地從運(yùn)維角度理解日常工作中所寫的Java微服務(wù)被無(wú)侵入的方式接入分布式鏈路追蹤系統(tǒng)的過(guò)程贸铜!
廢話不多說(shuō)堡纬,接下來(lái)就讓我們開啟干貨模式吧!
Java微服務(wù)接入SkyWalking的方式
在上篇文章關(guān)于SkyWalking基本原理的內(nèi)容中有講過(guò)蒿秦,SkyWalking的數(shù)據(jù)采集主要是通過(guò)業(yè)務(wù)探針(Agent)來(lái)實(shí)現(xiàn)的烤镐,針對(duì)不同的編程語(yǔ)言SkyWalking提供了對(duì)應(yīng)的Agent實(shí)現(xiàn)。Java微服務(wù)接入SkyWalking可以使用“SkyWalking Java Agent”來(lái)上報(bào)監(jiān)控?cái)?shù)據(jù)渤早。
這就需要Java微服務(wù)在部署啟動(dòng)的過(guò)程中需要獲取"SkyWalking Java Agent"探針包,并在啟動(dòng)參數(shù)中通過(guò)“--javaagent:xxx”進(jìn)行參數(shù)指定瘫俊。而具體的集成方式大致有以下三種:
使用官方提供的基礎(chǔ)鏡像鹊杖;
將agent包構(gòu)建到已存在的基礎(chǔ)鏡像中;
通過(guò)sidecar 模式掛載agent扛芽;
其中前兩種方式主要是通過(guò)在構(gòu)建Docker鏡像的過(guò)程中將Agent依賴打包集成到Java服務(wù)的Docker鏡像中骂蓖,而sidecar模式則是利用k8s的相關(guān)特性來(lái)實(shí)現(xiàn)在容器啟動(dòng)時(shí)掛載Agent相關(guān)依賴。
如果微服務(wù)是直接部署在Kubernetes集群川尖,那么采用sidecar模式來(lái)使用SkyWalking Agent會(huì)更加方便登下,因?yàn)檫@種方式不需要修改原來(lái)的基礎(chǔ)鏡像,也不需要重新構(gòu)建新的服務(wù)鏡像叮喳,而是會(huì)以sidecar模式被芳,通過(guò)共享的volume將agent所需的相關(guān)文件直接掛載到已經(jīng)存在的服務(wù)鏡像中。
構(gòu)建SkyWalking Agent鏡像
在開始以sidecar方式馍悟,將一個(gè)用Spring Cloud框架編寫的Java微服務(wù)接入SkyWalking之前畔濒,我們需要構(gòu)建SkyWalking Java Agent的公共鏡像,具體步驟如下:
1)锣咒、下載SkyWalking官方發(fā)行包侵状,并解壓到指定目錄
#下載skywalking-8.3.0 for es7版本的發(fā)布包赞弥,與部署的skywalking后端版本一致
$ wget https://mirror.bit.edu.cn/apache/skywalking/8.3.0/apache-skywalking-apm-es7-8.3.0.tar.gz
#將下載的發(fā)布包解壓到當(dāng)前目錄
$ tar -zxvf apache-skywalking-apm-es7-8.3.0.tar.gz
2)、構(gòu)建skywalking-agentsidecar鏡像并push至hub私有鏡像倉(cāng)庫(kù)
在前面步驟中解壓的skywalking發(fā)行包的同級(jí)目錄編寫Dockerfile文件趣兄,具體內(nèi)容如下:
FROM busybox:latest
ENV LANG=C.UTF-8
RUN set -eux && mkdir -p /usr/skywalking/agent
add apache-skywalking-apm-bin-es7/agent /usr/skywalking/agent
WORKDIR
在上述Dockefile文件中使用是的bosybox鏡像绽左,而不是SkyWalking的發(fā)行鏡像,這樣可以確保構(gòu)建出來(lái)的sidecar鏡像保持最小艇潭。
完成Docker文件編寫后拼窥,執(zhí)行鏡像構(gòu)建命令:
#執(zhí)行鏡像構(gòu)建命令
$ docker build . -t springcloud-action/skywalking-agent-sidecar:8.3.0
Sending build context to Docker daemon 556.5MB
Step 1/5 : FROM busybox:latest
latest: Pulling from library/busybox
d60bca25ef07: Pull complete
Digest: sha256:49dae530fd5fee674a6b0d3da89a380fc93746095e7eca0f1b70188a95fd5d71
Status: Downloaded newer image for busybox:latest
---> a77dce18d0ec
Step 2/5 : ENV LANG=C.UTF-8
---> Running in e95b4c25ebf3
Removing intermediate container e95b4c25ebf3
---> 83f22bccb6f3
Step 3/5 : RUN set -eux && mkdir -p /usr/skywalking/agent
---> Running in 49c2eac2b6ab
+ mkdir -p /usr/skywalking/agent
Removing intermediate container 49c2eac2b6ab
---> 89cf3ce8238e
Step 4/5 : add apache-skywalking-apm-bin/agent /usr/skywalking/agent
---> 91fe5f06948f
Step 5/5 : WORKDIR /
---> Running in 6a64553f1870
Removing intermediate container 6a64553f1870
---> 7e73ddba48bb
Successfully built 7e73ddba48bb
Successfully tagged springcloud-action/skywalking-agent-sidecar:8.3.0
為了驗(yàn)證構(gòu)建的鏡像是否成功,可以通過(guò)命令查看本地構(gòu)建的鏡像暴区,命令如下:
#查看本地鏡像信息
$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
springcloud-action/skywalking-agent-sidecar 8.3.0 7e73ddba48bb 2 minutes ago 32.2MB
...
3)闯团、將打包的鏡像推送到harbor鏡像倉(cāng)庫(kù)
為了便于后續(xù)微服務(wù)直接使用已經(jīng)構(gòu)建好的SkyWalking Agent SideCar鏡像,我們可以將其push至私有Harbor鏡像倉(cāng)庫(kù)中仙粱。具體命令如下:
#登錄鏡像倉(cāng)庫(kù)房交,輸入用戶名密碼(admin/Harbor12345)
$ docker login http://10.211.55.2:8080
Username: admin
Password:
Login Succeeded
這里的Harbor私有鏡像倉(cāng)庫(kù)一般公司都會(huì)自己搭建,接下來(lái)我們對(duì)構(gòu)建的鏡像打tag并上傳伐割,具體如下:
#這里將原先構(gòu)建的鏡像安裝{鏡像倉(cāng)庫(kù)地址}/項(xiàng)目名稱/鏡像名稱的方式打tag
$ docker tag springcloud-action/skywalking-agent-sidecar:8.3.0 10.211.55.2:8080/springcloud-action/skywalking-agent-sidecar
之后可以具體查看已經(jīng)打過(guò)tag鏡像信息候味,命令如下:
$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
springcloud-action/skywalking-agent-sidecar 8.3.0 e21040c57e42 2 weeks ago 32.2MB
10.211.55.2:8080/springcloud-action/skywalking-agent-sidecar latest e21040c57e42 2 weeks ago 32.2MB
...
接下來(lái)我們將打過(guò)tag的鏡像推送至私有Harbor倉(cāng)庫(kù),具體操作如下:
#將鏡像推送到Harbor私有鏡像倉(cāng)庫(kù)
$ docker push 10.211.55.2:8080/springcloud-action/skywalking-agent-sidecar
The push refers to repository [10.211.55.2:8080/springcloud-action/skywalking-agent-sidecar]
e80d641c3ed9: Layer already exists
11fe582bd430: Layer already exists
1dad141bdb55: Layer already exists
latest: digest: sha256:b495c18c3ae35f563ad4db91c3db66f245e6038be0ced635d16d0e3d3f3bcb80 size: 946
完成后可以進(jìn)入harbor倉(cāng)庫(kù)進(jìn)行查看隔心,如下圖所示:
SideCar模式接入SkyWalking服務(wù)
上面我們通過(guò)手工構(gòu)建的方式構(gòu)建了SkyWalking Java Agent的公共Docker鏡像白群,并將其Push到了我們的私有Harbor鏡像倉(cāng)庫(kù),接下來(lái)我們將演示如何通過(guò)編寫Kubernetes服務(wù)發(fā)布文件硬霍,來(lái)將Java服務(wù)發(fā)布到K8s集群的過(guò)程中自動(dòng)以SideCar的形式集成Agent帜慢、并接入SkyWalking服務(wù)。
而這個(gè)過(guò)程才是作為一個(gè)Java程序員最關(guān)心的步驟唯卖。在開始下面步驟前粱玲,你應(yīng)該通過(guò)IDEA構(gòu)建一個(gè)Spring Boot微服務(wù)工程,具體構(gòu)建的過(guò)程就不掩飾了拜轨,但重點(diǎn)是你這個(gè)Spring Boot工程應(yīng)該支持構(gòu)建Docker鏡像抽减,以Maven為例,需要在pom.xml文件中添加打包插件橄碾,具體如下:
<!--添加將Java應(yīng)用打包為Docker Image的Maven插件-->
<plugin>
<groupId>com.spotify</groupId>
<artifactId>dockerfile-maven-plugin</artifactId>
<version>1.4.13</version>
<executions>
<execution>
<id>build-image</id>
<phase>package</phase>
<goals>
<goal>build</goal>
</goals>
</execution>
</executions>
<configuration>
<!--指定Dockerfile文件位置-->
<dockerfile>docker/Dockerfile</dockerfile>
<repository>${docker.repository}/springcloud-action/${app.name}</repository>
<!--<tag>${project.version}</tag>-->
<buildArgs>
<!--提供參數(shù)向Dockerfile傳遞-->
<JAR_FILE>target/${project.build.finalName}.jar</JAR_FILE>
</buildArgs>
</configuration>
</plugin>
其中<configuration>標(biāo)簽中指定的Dockerfile文件內(nèi)容如下:
FROM openjdk:8u191-jre-alpine3.9
ENTRYPOINT ["/usr/bin/java", "-jar", "/app.jar"]
ARG JAR_FILE
ADD ${JAR_FILE} /app.jar
EXPOSE 8080
這就是一個(gè)簡(jiǎn)單的鏡像構(gòu)建文件卵沉,如果不采用sidecar方式,那么就需要在服務(wù)鏡像構(gòu)建文件中添加SkyWalking Agent的相關(guān)集成法牲,但這里我們是sidecar方式史汗,所以服務(wù)鏡像構(gòu)建文件就不用那么復(fù)雜了!
此外<configuration>標(biāo)簽中關(guān)于鏡像倉(cāng)庫(kù)地址拒垃、應(yīng)用名稱的動(dòng)態(tài)參數(shù)在pom.xml文件中的定義如下(把玩時(shí)以自己實(shí)際環(huán)境為準(zhǔn)):
<properties>
<!--定義Docker鏡像倉(cāng)庫(kù)地址-->
<docker.repository>10.211.55.2:8080</docker.repository>
<!--定義項(xiàng)目名稱作為鏡像名稱生成的組成部分-->
<app.name>chapter10-monitor-demo</app.name>
</properties>
接下來(lái)具體講述接入步驟:
1)淹办、將Java微服務(wù)工程打包成Docker鏡像并Push到Harbor鏡像倉(cāng)庫(kù)
# Maven項(xiàng)目構(gòu)建,會(huì)自動(dòng)根據(jù)pom.xml中的相關(guān)插件配置進(jìn)行docker鏡像構(gòu)建
$ mvn clean install -X
查看本地新構(gòu)建的鏡像信息恶复,具體如下:
$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
10.211.55.2:8080/springcloud-action/chapter10-monitor-demo latest 3ae132cdfeb7 12 seconds ago 121MB
10.211.55.2:8080/springcloud-action/skywalking-agent-sidecar latest e21040c57e42 2 weeks ago 32.2MB
springcloud-action/skywalking-agent-sidecar 8.3.0 e21040c57e42 2 weeks ago 32.2MB
...
將微服務(wù)鏡像push到Harbor鏡像倉(cāng)庫(kù):
$ docker push 10.211.55.2:8080/springcloud-action/chapter10-monitor-demo
The push refers to repository [10.211.55.2:8080/springcloud-action/chapter10-monitor-demo]
5f3427edfc10: Pushed
925523484e00: Layer already exists
344fb4b275b7: Layer already exists
bcf2f368fe23: Layer already exists
latest: digest: sha256:b424180c56b28a9a7704a1f6476f4247fad12cc27721c21fce32149a8f344dee size: 1159
3)怜森、微服務(wù)Kubernetes發(fā)布文件集成SkyWalking Agent實(shí)現(xiàn)埋點(diǎn)
到這里你并沒(méi)有發(fā)現(xiàn)為了將Java服務(wù)接入SkyWalking速挑,你需要在Java微服務(wù)本身做任何動(dòng)作,而接下來(lái)在k8s部署文件中的將演示副硅,為什么要將這種方式稱之為SideCar姥宝。
其主要原理是通過(guò)Kubernetes的初始化容器initContainers來(lái)實(shí)現(xiàn)的,initContainers是一種專用容器恐疲,可以在應(yīng)用容器啟動(dòng)之前運(yùn)行腊满,可以用于完成應(yīng)用啟動(dòng)前的必要初始化工作。具體的Kubernetes部署文件(deploy-skywalking.yml)內(nèi)容如下:
apiVersion: apps/v1
kind: Deployment
metadata:
name: chapter10-monitor-demo
spec:
selector:
matchLabels:
app: chapter10-monitor-demo
replicas: 1
#設(shè)置滾動(dòng)升級(jí)策略
#Kubernetes在等待設(shè)置的時(shí)間后才開始進(jìn)行升級(jí)培己,例如5秒
minReadySeconds: 5
strategy:
type: RollingUpdate
rollingUpdate:
#升級(jí)過(guò)程中最多可以比原先設(shè)置多出的Pod數(shù)量
maxSurge: 1
#升級(jí)過(guò)程中Deployment控制器最多可以刪除多少個(gè)舊Pod碳蛋,主要用于提供緩沖時(shí)間
maxUnavailable: 1
template:
metadata:
labels:
app: chapter10-monitor-demo
spec:
#構(gòu)建初始化鏡像(通過(guò)初始化鏡像的方式集成SkyWalking Agent)
initContainers:
- image: 10.211.55.2:8080/springcloud-action/skywalking-agent-sidecar:latest
name: sw-agent-sidecar
imagePullPolicy: IfNotPresent
command: ["sh"]
args:
[
"-c",
"mkdir -p /skywalking/agent && cp -r /usr/skywalking/agent/* /skywalking/agent",
]
volumeMounts:
- mountPath: /skywalking/agent
name: sw-agent
containers:
- name: chapter10-devops-demo
image: 10.211.55.2:8080/springcloud-action/chapter10-monitor-demo:latest
env:
#這里通過(guò)JAVA_TOOL_OPTIONS,而不是JAVA_OPTS可以實(shí)現(xiàn)不通過(guò)將agent命令加入到j(luò)ava應(yīng)用jvm參數(shù)而實(shí)現(xiàn)agent的集成
- name: JAVA_TOOL_OPTIONS
value: -javaagent:/usr/skywalking/agent/skywalking-agent.jar
- name: SW_AGENT_NAME
value: chapter10-devops-demo
- name: SW_AGENT_COLLECTOR_BACKEND_SERVICES
# FQDN: servicename.namespacename.svc.cluster.local
value: oap.skywalking:11800
- name: SERVER_PORT
value: "8080"
- name: SPRING_PROFILES_ACTIVE
value: test
volumeMounts:
- mountPath: /usr/skywalking/agent
name: sw-agent
volumes:
- name: sw-agent
emptyDir: {}
---
apiVersion: v1
kind: Service
metadata:
name: chapter10-monitor-demo
labels:
svc: chapter10-monitor-demo
spec:
selector:
app: chapter10-monitor-demo
ports:
- name: http
port: 8080
nodePort: 30001
type: NodePort
以上是掛載sidecar的k8s發(fā)布文件省咨,以微服務(wù)“chapter10-devops-demo”為例肃弟,主要是通過(guò)共享volume的方式掛載agent。其中initContainers通過(guò)skywalking-agent卷掛載了skywalking-agent-sidecar鏡像中的/skywalking/agent零蓉,并將上面構(gòu)建好的鏡像中的agent目錄cp到了/skywalking/agent目錄笤受,完成之后微服務(wù)容器啟動(dòng)時(shí)也掛載了skywalking-agent卷,并將其掛載到容器的/usr/skywalking/agent目錄敌蜂,這樣就完成了共享過(guò)程箩兽。
這里有一個(gè)有意思的點(diǎn),Java服務(wù)通過(guò)Agent接入SkyWalking一般情況下還需要在啟動(dòng)命令中加入JVM參數(shù)章喉,例如:“-javaagent:/usr/skywalking/agent/skywalking-agent.jar”汗贫。這就需要我們?cè)诙xJava程序鏡像打包的Dockerfile文件中通過(guò)“ENTRYPOINT”加入相關(guān)參數(shù),例如:
ENTRYPOINT [ "sh", "-c", "java ${JAVA_OPTS} -javaagent:/app/agent/skywalking-agent.jar -Dskywalking.collector.backend_service=${SW_AGENT_COLLECTOR_BACKEND_SERVICES} -Dskywalking.agent.service_name=${SW_AGENT_NAME} -Dskywalking.agent.instance_name=${HOSTNAME} -Djava.security.egd=file:/dev/./urandom -jar /app/app.jar $PROFILE"
但這種方式需要在Dockerfile文件中額外設(shè)置SkyWalking Agent相關(guān)的JVM參數(shù)秸脱,所以你可能沒(méi)注意到落包,在上述k8s部署文件中我所使用的是“JAVA_TOOL_OPTIONS”這個(gè)參數(shù),而不是最常見(jiàn)的“JAVA_OPTS”撞反。這個(gè)點(diǎn)很多人都不知道妥色,如果你耐心看到這里搪花,恭喜你Get了一個(gè)新技能遏片!至于二者的區(qū)別,感興趣的朋友可以搜索下撮竿!
4)吮便、部署啟動(dòng)微服務(wù),并驗(yàn)證其是否已經(jīng)正常接入SkyWalking監(jiān)控
接下來(lái)我們進(jìn)入部署文件所在目錄,執(zhí)行發(fā)布命令如下:
$ kubectl apply -f deploy-skywalking.yml
deployment.apps/chapter10-monitor-demo created
service/chapter10-monitor-demo created
之后查看相關(guān)Pod是否運(yùn)行成功:
$ kubectl get pods
NAME READY STATUS RESTARTS AGE
chapter10-monitor-demo-5767d54f5-vfqqf 1/1 Running 0 96m
運(yùn)行成功了幢踏!此時(shí)可以訪問(wèn)下服務(wù)的測(cè)試接口髓需,多刷幾次,之后通過(guò)SkyWalking UI查看是否有監(jiān)控?cái)?shù)據(jù)房蝉,如下圖所示:
如上圖所示僚匆,在訪問(wèn)微服務(wù)測(cè)試接口后可以看到SpringCloud微服務(wù)已經(jīng)通過(guò)Agent像SkyWalking上報(bào)了APM監(jiān)控?cái)?shù)據(jù)微渠!
后記
本文實(shí)驗(yàn)步驟比較多,也許你很難一次性看完咧擂,但是真正的技術(shù)都是要練的逞盆,所以有空的時(shí)候搭建環(huán)境后玩一玩是理解文章內(nèi)容的關(guān)鍵!
寫在最后
歡迎大家關(guān)注我的公眾號(hào)【風(fēng)平浪靜如碼】松申,海量Java相關(guān)文章云芦,學(xué)習(xí)資料都會(huì)在里面更新,整理的資料也會(huì)放在里面贸桶。
覺(jué)得寫的還不錯(cuò)的就點(diǎn)個(gè)贊舅逸,加個(gè)關(guān)注唄!點(diǎn)關(guān)注皇筛,不迷路琉历,持續(xù)更新!I枇善已!