docker化应用接入skywalking Agent
本文柯苏远写于2024年3月21日15点50分
1. SkyWalking 架构简介
2. 背景
服务容器化的过程中想要引入sw来监控整个系统的信息。
目前运维同学已经在开发环境上搭建好了oap以及存储层和sw-ui层。
我们需要将探针层和应用层接入整个sw架构。
3. 问题 & 解决思路
3.1 问题描述
在我们应用中接入探针层主要是在jar的启动命令上指定agent的jar包以及oap地址,格式如下:
bash
# skywalking agent jar包路径
-javaagent:/sw/skywalking-agent/skywalking-agent.jar
# 服务名称
-Dskywalking.agent.service_name=provider
# sw-oap地址
-Dskywalking.collector.backend_service=127.0.0.1:11800
这里涉及两个变动点:
-javaagent
指定的agent包路径。-Dskywalking.collector.backend_service
指定sw-oap服务地址。
由于现在服务容器化,这两个点都需要在dockerfile文件中体现,可是dockerfile文件又不支持这两个属性动态变化(我调研的结果是dockerfile里不支持写一些if之类逻辑的)。
由于整个部署是cicd的,所以dev、test、uat以及prod都是用这一个dockerfile,那么如何实现各个环境基于同一个dockerfile来满足上面说的两个变动点呢?
3.2 解决思路
- 将动的变成不动的。
-javaagent
- 将一定要动的抽取出来。
-Dskywalking.collector.backend_service
3.3 具体方案
探针的配置优先级:
- 启动命令上的。
config/agent.config
配置文件里的配置
根据这个优先级我们可以将-Dskywalking.collector.backend_service
从dockerfile文件里抽取出来放在 agent.config
里。
下面是对于 -javaagent
动变不动的具体方案:
3.3.1 复制一份agent文件到docker容器内
关键点:直接将探针copy一份到服务对应的容器里,然后在dockerfile里 -javaagent
指向容器里的探针地址。
缺点:
- 每个服务对应的容器里都有一份探针,冗余了很多份。
- 从宿主机往容器里拷贝agent的时候有一个docker构建上下文环境,被拷贝的文件只能在dockerfile所处的当前目录以及当前目录的子目录。不在这个范围的会报文件找不到,所以对于复制的路径不够灵活。
3.3.2 将一份agent文件分别挂载到多个docker容器内
关键点:将探针文件挂载在每个docker容器里,同一个服务器上的docker容器用同一份探针文件。
优点:
- 容器内没有冗余探针文件,共用一份,节省物理资源。
- 在挂载的时候不需要将探针放在当前dockerfile目录或者是子目录下,可以放置在服务器任意地址进行挂载操作,更加灵活。
4. 可行性实践
有两个服务:
consumer
、provider
,都注册在nacos
上。consumer
对外暴露了一个接口:/echo/{str}
整个调用链就是:
consumer
→provider
→mysql
4.1 复制到容器里的方式
- 首先将我们的两个jar包以及本地编写的两个dockerfile文件,以及我们要用到的sw-agent上传的dev服务器上,在服务器上的目录如下所示:
-
具体的
consumer-dockerfile
文件内容如下所示:bash# 使用官方提供的Spring Boot基础镜像 FROM openjdk:8-jdk-alpine # 设置工作目录为/app WORKDIR /app # 将当前目录内容复制到容器的/app内 COPY consumer.jar /app/consumer.jar # 拷贝宿主机的skywalking-agent/ 文件夹下的内容到容器的/skywalking-agent目录下 COPY skywalking-agent/ /skywalking-agent/ # 使用容器内在上一步复制进来的agent地址 ENV JAVA_OPTS="-javaagent:/skywalking-agent/skywalking-agent.jar -Dskywalking.agent.service_name=consumer" # 暴露容器的 8082 端口 EXPOSE 8082 # 设置容器启动时运行jar包 ENTRYPOINT ["sh", "-c", "java ${JAVA_OPTS} -jar /app/consumer.jar"]
-
将consumer-dockerfile文件打包成镜像
bashdocker build -f Consumer-Dockerfile -t consumer:1.0 .
-
运行镜像生成对应容器
bashdocker run -t -d -i -p 8082:8082 --name=consumer consumer:1.0
-
Provider是相同的操作
-
dockerfile
bashFROM openjdk:8-jdk-alpine # 设置工作目录为/app WORKDIR /app # 将当前目录内容复制到容器的/app内 COPY provider.jar /app/provider.jar # 拷贝宿主机的skywalking-agent/ 文件夹下的内容到容器的/skywalking-agent目录下 COPY skywalking-agent/ /skywalking-agent/ # 使用容器内的agent地址 ENV JAVA_OPTS="-javaagent:/skywalking-agent/skywalking-agent.jar -Dskywalking.agent.service_name=provider" # 暴露容器的 8081 端口 EXPOSE 8081 # 设置容器启动时运行jar包 ENTRYPOINT ["sh", "-c", "java ${JAVA_OPTS} -jar /app/provider.jar"]
-
构建镜像 & 运行容器
bashdocker build -f Provider-Dockerfile -t provider:1.0 . docker build -f Consumer-Dockerfile -t consumer:1.0 .
-
-
测试
- 暴露出来的接口是:
http://192.24.100.118:8082/echo/{str}
,{str}
是路径参数,循环调用100次,去sw-ui界面看看是否有对应的跟踪链路。
- 暴露出来的接口是:
复制方案的测试结论是可行的。
4.2 挂载到容器里的方式
去调研了下dockerfile的语法,发现在dockerfile里是不可以直接进行挂载的,只能指定卷,挂载操作要在镜像起容器的时候才可以。
-
首先服务还是上面两个jar包,只不过这次不是copy探针了,而是挂载,所以我们要对应修改dockerfile文件,分别注释掉copy指令,更改容器暴露端口,以及启动时候在命令行指定端口。
复制了一份到另外一个目录,然后进行了修改dockerfile,目录详情。
-
Consumer-dockerfile & Provider-dockerfile
bash# 使用官方提供的Spring Boot基础镜像 FROM openjdk:8-jdk-alpine # 设置工作目录为/app WORKDIR /app # 将当前目录内容复制到容器的/app内 COPY consumer.jar /app/consumer.jar # 拷贝宿主机的skywalking-agent/ 文件夹下的内容到容器的/skywalking-agent目录下 # COPY skywalking-agent/ /skywalking-agent/ # 使用容器内挂载agent的地址 ENV JAVA_OPTS="-javaagent:/skywalking-agent/skywalking-agent.jar -Dskywalking.agent.service_name=consumer" # 暴露容器的 8083 端口 EXPOSE 8083 # 设置容器启动时运行jar包 ENTRYPOINT ["sh", "-c", "java ${JAVA_OPTS} -jar /app/consumer.jar --server.port=8083"]
bashFROM openjdk:8-jdk-alpine # 设置工作目录为/app WORKDIR /app # 将当前目录内容复制到容器的/app内 COPY provider.jar /app/provider.jar # 拷贝宿主机的skywalking-agent/ 文件夹下的内容到容器的/skywalking-agent目录下 # COPY skywalking-agent/ /skywalking-agent/ # 使用容器内的agent地址 ENV JAVA_OPTS="-javaagent:/skywalking-agent/skywalking-agent.jar -Dskywalking.agent.service_name=provider" # 暴露容器的 8084 端口 EXPOSE 8084 # 设置容器启动时运行jar包 ENTRYPOINT ["sh", "-c", "java ${JAVA_OPTS} -jar /app/provider.jar --server.port=8084"]
-
构建并运行 consumer & provider
这里的 -v 是挂载 宿主机目录到容器里的参数
bashdocker build -f Consumer-Dockerfile -t consumer:2.0 . docker run -t -d -i -p 8083:8083 -v /sw/mount/skywalking-agent:/skywalking-agent --name=consumer2 consumer:2.0 docker build -f Provider-Dockerfile -t provider:2.0 . docker run -t -d -i -p 8084:8084 -v /sw/mount/skywalking-agent:/skywalking-agent --name=provider2 provider:2.0
-
测试
- 暴露出来的接口是:
http://192.24.100.118:8083/echo/{str}
,{str}
是路径参数,循环调用100次,去sw-ui界面看看是否有对应的跟踪链路。
- 暴露出来的接口是:
挂载方案的测试结论是可行的。
5. 总结
关于如何将探针和我们的应用接入sw架构,主要是两种方式:
- 将探针复制到应用容器内。
- 将探针挂载到应用容器内。
推荐使用第二种