k8s微服務接入SkyWalking,三分鐘教你怎麼玩!

前面我給大家分享了關於分佈式鏈路追蹤的基本原理和SkyWalking的k8s部署玩法,如果還沒來得及看的朋友可以看我上篇文章。

今天要給大家分享是我們日常工作中最常見的一種場景,那就是部署在k8s環境下的Java微服務,要接入SkyWalking的具體玩法,通過這個過程咱們可以更深入的理解SkyWalking進行數據採集的邏輯,也能更深刻地從運維角度理解日常工作中所寫的Java微服務被無侵入的方式接入分佈式鏈路追蹤系統的過程!

廢話不多說,接下來就讓我們開啓乾貨模式吧!

Java微服務接入SkyWalking的方式

在上篇文章關於SkyWalking基本原理的內容中有講過,SkyWalking的數據採集主要是通過業務探針(Agent)來實現的,針對不同的編程語言SkyWalking提供了對應的Agent實現。Java微服務接入SkyWalking可以使用“SkyWalking Java Agent”來上報監控數據。

這就需要Java微服務在部署啓動的過程中需要獲取"SkyWalking Java Agent"探針包,並在啓動參數中通過“--javaagent:xxx”進行參數指定。而具體的集成方式大致有以下三種:

  • 使用官方提供的基礎鏡像;

  • 將agent包構建到已存在的基礎鏡像中;

  • 通過sidecar 模式掛載agent;

其中前兩種方式主要是通過在構建Docker鏡像的過程中將Agent依賴打包集成到Java服務的Docker鏡像中,而sidecar模式則是利用k8s的相關特性來實現在容器啓動時掛載Agent相關依賴。

如果微服務是直接部署在Kubernetes集羣,那麼採用sidecar模式來使用SkyWalking Agent會更加方便,因爲這種方式不需要修改原來的基礎鏡像,也不需要重新構建新的服務鏡像,而是會以sidecar模式,通過共享的volume將agent所需的相關文件直接掛載到已經存在的服務鏡像中。

構建SkyWalking Agent鏡像

在開始以sidecar方式,將一個用Spring Cloud框架編寫的Java微服務接入SkyWalking之前,我們需要構建SkyWalking Java Agent的公共鏡像,具體步驟如下:

1)、下載SkyWalking官方發行包,並解壓到指定目錄

#下載skywalking-8.3.0 for es7版本的發佈包,與部署的skywalking後端版本一致
$ wget https://mirror.bit.edu.cn/apache/skywalking/8.3.0/apache-skywalking-apm-es7-8.3.0.tar.gz

#將下載的發佈包解壓到當前目錄
$ tar -zxvf apache-skywalking-apm-es7-8.3.0.tar.gz

2)、構建skywalking-agentsidecar鏡像並push至hub私有鏡像倉庫

在前面步驟中解壓的skywalking發行包的同級目錄編寫Dockerfile文件,具體內容如下:

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的發行鏡像,這樣可以確保構建出來的sidecar鏡像保持最小。

完成Docker文件編寫後,執行鏡像構建命令:

#執行鏡像構建命令
$ 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

爲了驗證構建的鏡像是否成功,可以通過命令查看本地構建的鏡像,命令如下:

#查看本地鏡像信息
$ docker images
REPOSITORY                                                   TAG                   IMAGE ID            CREATED             SIZE
springcloud-action/skywalking-agent-sidecar                           8.3.0                 7e73ddba48bb        2 minutes ago       32.2MB
...

3)、將打包的鏡像推送到harbor鏡像倉庫

爲了便於後續微服務直接使用已經構建好的SkyWalking Agent SideCar鏡像,我們可以將其push至私有Harbor鏡像倉庫中。具體命令如下:

#登錄鏡像倉庫,輸入用戶名密碼(admin/Harbor12345)
$ docker login http://10.211.55.2:8080
Username: admin
Password: 
Login Succeeded

這裏的Harbor私有鏡像倉庫一般公司都會自己搭建,接下來我們對構建的鏡像打tag並上傳,具體如下:

#這裏將原先構建的鏡像安裝{鏡像倉庫地址}/項目名稱/鏡像名稱的方式打tag
$ docker tag springcloud-action/skywalking-agent-sidecar:8.3.0 10.211.55.2:8080/springcloud-action/skywalking-agent-sidecar

之後可以具體查看已經打過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
...

接下來我們將打過tag的鏡像推送至私有Harbor倉庫,具體操作如下:

#將鏡像推送到Harbor私有鏡像倉庫
$ 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

完成後可以進入harbor倉庫進行查看,如下圖所示:

SideCar模式接入SkyWalking服務

上面我們通過手工構建的方式構建了SkyWalking Java Agent的公共Docker鏡像,並將其Push到了我們的私有Harbor鏡像倉庫,接下來我們將演示如何通過編寫Kubernetes服務發佈文件,來將Java服務發佈到K8s集羣的過程中自動以SideCar的形式集成Agent、並接入SkyWalking服務。

這個過程纔是作爲一個Java程序員最關心的步驟。在開始下面步驟前,你應該通過IDEA構建一個Spring Boot微服務工程,具體構建的過程就不掩飾了,但重點是你這個Spring Boot工程應該支持構建Docker鏡像,以Maven爲例,需要在pom.xml文件中添加打包插件,具體如下:

<!--添加將Java應用打包爲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>
            <!--提供參數向Dockerfile傳遞-->
            <JAR_FILE>target/${project.build.finalName}.jar</JAR_FILE>
        </buildArgs>
    </configuration>
</plugin>

其中<configuration>標籤中指定的Dockerfile文件內容如下:

FROM openjdk:8u191-jre-alpine3.9
ENTRYPOINT ["/usr/bin/java", "-jar", "/app.jar"]
ARG JAR_FILE
ADD ${JAR_FILE} /app.jar
EXPOSE 8080

這就是一個簡單的鏡像構建文件,如果不採用sidecar方式,那麼就需要在服務鏡像構建文件中添加SkyWalking Agent的相關集成,但這裏我們是sidecar方式,所以服務鏡像構建文件就不用那麼複雜了!

此外<configuration>標籤中關於鏡像倉庫地址、應用名稱的動態參數在pom.xml文件中的定義如下(把玩時以自己實際環境爲準):

<properties>
    <!--定義Docker鏡像倉庫地址-->
    <docker.repository>10.211.55.2:8080</docker.repository>
    <!--定義項目名稱作爲鏡像名稱生成的組成部分-->
    <app.name>chapter10-monitor-demo</app.name>
</properties>

接下來具體講述接入步驟:

1)、將Java微服務工程打包成Docker鏡像並Push到Harbor鏡像倉庫

# Maven項目構建,會自動根據pom.xml中的相關插件配置進行docker鏡像構建
$ mvn clean install -X

查看本地新構建的鏡像信息,具體如下:

$ 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
...

將微服務鏡像push到Harbor鏡像倉庫:

$ 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)、微服務Kubernetes發佈文件集成SkyWalking Agent實現埋點

到這裏你並沒有發現爲了將Java服務接入SkyWalking,你需要在Java微服務本身做任何動作,而接下來在k8s部署文件中的將演示,爲什麼要將這種方式稱之爲SideCar。

其主要原理是通過Kubernetes的初始化容器initContainers來實現的,initContainers是一種專用容器,可以在應用容器啓動之前運行,可以用於完成應用啓動前的必要初始化工作。具體的Kubernetes部署文件(deploy-skywalking.yml)內容如下:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: chapter10-monitor-demo
spec:
  selector:
    matchLabels:
      app: chapter10-monitor-demo
  replicas: 1
  #設置滾動升級策略
  #Kubernetes在等待設置的時間後纔開始進行升級,例如5秒
  minReadySeconds: 5
  strategy:
    type: RollingUpdate
    rollingUpdate:
      #升級過程中最多可以比原先設置多出的Pod數量
      maxSurge: 1
      #升級過程中Deployment控制器最多可以刪除多少箇舊Pod,主要用於提供緩衝時間
      maxUnavailable: 1
  template:
    metadata:
      labels:
        app: chapter10-monitor-demo
    spec:
      #構建初始化鏡像(通過初始化鏡像的方式集成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:
            #這裏通過JAVA_TOOL_OPTIONS,而不是JAVA_OPTS可以實現不通過將agent命令加入到java應用jvm參數而實現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發佈文件,以微服務“chapter10-devops-demo”爲例,主要是通過共享volume的方式掛載agent。其中initContainers通過skywalking-agent卷掛載了skywalking-agent-sidecar鏡像中的/skywalking/agent,並將上面構建好的鏡像中的agent目錄cp到了/skywalking/agent目錄,完成之後微服務容器啓動時也掛載了skywalking-agent卷,並將其掛載到容器的/usr/skywalking/agent目錄,這樣就完成了共享過程。

這裏有一個有意思的點,Java服務通過Agent接入SkyWalking一般情況下還需要在啓動命令中加入JVM參數,例如:“-javaagent:/usr/skywalking/agent/skywalking-agent.jar”。這就需要我們在定義Java程序鏡像打包的Dockerfile文件中通過“ENTRYPOINT”加入相關參數,例如:

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文件中額外設置SkyWalking Agent相關的JVM參數,所以你可能沒注意到,在上述k8s部署文件中我所使用的是“JAVA_TOOL_OPTIONS”這個參數,而不是最常見的“JAVA_OPTS”。這個點很多人都不知道,如果你耐心看到這裏,恭喜你Get了一個新技能!至於二者的區別,感興趣的朋友可以搜索下!

4)、部署啓動微服務,並驗證其是否已經正常接入SkyWalking監控

接下來我們進入部署文件所在目錄,執行發佈命令如下:

$ kubectl apply -f deploy-skywalking.yml
deployment.apps/chapter10-monitor-demo created
service/chapter10-monitor-demo created

之後查看相關Pod是否運行成功:

$ kubectl get pods
NAME                                     READY   STATUS    RESTARTS   AGE
chapter10-monitor-demo-5767d54f5-vfqqf   1/1     Running   0          96m

運行成功了!此時可以訪問下服務的測試接口,多刷幾次,之後通過SkyWalking UI查看是否有監控數據,如下圖所示:

如上圖所示,在訪問微服務測試接口後可以看到SpringCloud微服務已經通過Agent像SkyWalking上報了APM監控數據!

後記

本文實驗步驟比較多,也許你很難一次性看完,但是真正的技術都是要練的,所以有空的時候搭建環境後玩一玩是理解文章內容的關鍵!

寫在最後

歡迎大家關注我的公衆號【風平浪靜如碼】,海量Java相關文章,學習資料都會在裏面更新,整理的資料也會放在裏面。

覺得寫的還不錯的就點個贊,加個關注唄!點關注,不迷路,持續更新!!!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章