后面我给大家分享了对于分布式链路追踪的基本原理和 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 相干文章,学习材料都会在外面更新,整顿的材料也会放在外面。
感觉写的还不错的就点个赞,加个关注呗!点关注,不迷路,继续更新!!!