本文主要介绍了 k8s 环境里面在不修改应用镜像的前提下,如何给 java 应用快速添加 skywalking agent 采集器,以及其中所涉及到的技术原理。k8s 应用接入 skywalking 是基于已有的 k8s 环境、待接入应用以及 skywalking 后端服务进行接入的。如果这些都已经准备好了,可以直接跳过 前置准备,从 快速接入 开始。如果还没有这些环境,至少需要准备一个干净的 k8s 环境,再按照 前置准备 中的步骤部署好前置的资源环境。
在接入 skywalking 之前,首选需要一个 skywalking 的后端服务/集群,用于收集采集到的监控数据,并对其进行聚合、存储以及展示。
如果还没有部署 skywaking 后端服务的,可以使用下面的 helm chart 部署一套 skywalking 后端服务。
## 克隆 helm chart
git clone --branch 1.0 git@e.coding.net:treezh/demo03/coffeemaker-helm.git
## 生成 helm chart
cd ./coffeemaker-helm
helm dep ./
## 确保当前 kubeconfig 配置正确情况下,执行下面指令进行部署
helm upgrade --install coffeemaker ./ --set coffee.enable=false --set skywalking.enabled=true --set jaeger.enabled=false
Skywalking 需要从应用中采集链路数据并进行上报,然而应用本身不包含这些代码逻辑,这些逻辑通过 javaagent 方式被写到了 skywalking-agent.jar
里面。并且使用 javaagent 的特性与 bytebuddy 字节码织入技术,让应用加载这些代码到相应的位置。
所以我们需要一个镜像,把 skywalking-agent.jar
搬运到目标应用里面,并且让目标应用加载。
这个镜像只需要包含 skywalking-agent.jar
已经相应的依赖插件即可。可以自行制作,也可以官方提供 agent 镜像。这里以官方镜像的一个备份为例。
docker pull http://treezh-docker.pkg.coding.net/demo03/public/skywalking-java-agent:8.9.0-alpine
为了让应用加载 skywalking-agent.jar
, 需要对应用的 deployment 做一些修改。所以需要准备待接入应用的 manifest。如果已经有待接入的应用,则可以通过 kubectl get deployment (deploymentName) -o yaml > app.yaml
获取对应的 manifest。如果还没有,则可以使用本文准备好的 helmchart 生成对应的 manifest。
## 克隆 helm chart
git clone --branch 1.0 git@e.coding.net:treezh/demo03/coffeemaker-helm.git
## 生成 helm chart
cd ./coffeemaker-helm
## 生成 mainifest
helm template --set coffee.enabled=true --set skywalking.enabled=false --set jaeger.enabled=false ./ > coffee-maker.yaml
部署 coffee-maker 应用
## 部署
helm dep ./
helm upgrade --install coffeemaker ./ --set coffee.enabled=true --set skywalking.enabled=false --set jaeger.enabled=false
这里以 coffee-maker 的 coffee-machine 应用为例子,快速接入 Skywalking 步骤如下
1. 找到 coffee-machine 的 manifest 中的 deployment 内容(非关键信息省略):
# Source: coffee-maker/templates/coffee-material.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: coffee-material
spec:
template:
spec:
containers:
- name: coffee-material
image: "treezh-docker.pkg.coding.net/demo03/public/coffee-material:8bc05202416f680c2a3a7179703be94ad806a099"
imagePullPolicy: IfNotPresent
env:
- name: LOGGING_LEVEL_ROOT
value: "INFO"
...
...
...
2. 添加 initContainer :
# Source: coffee-maker/templates/coffee-material.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: coffee-material
spec:
template:
spec:
initContainers:
- name: skywalking-agent
image: "treezh-docker.pkg.coding.net/demo03/public/skywalking-java-agent:8.9.0-alpine"
containers:
- name: coffee-material
image: "treezh-docker.pkg.coding.net/demo03/public/coffee-material:8bc05202416f680c2a3a7179703be94ad806a099"
imagePullPolicy: IfNotPresent
env:
- name: LOGGING_LEVEL_ROOT
value: "INFO"
...
...
...
3. 添加 initContainer 与目标 container 共享目录:
# Source: coffee-maker/templates/coffee-material.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: coffee-material
spec:
template:
spec:
volumes:
- name: skywalking-agent
emptyDir: { }
initContainers:
- name: skywalking-agent
image: "treezh-docker.pkg.coding.net/demo03/public/skywalking-java-agent:8.9.0-alpine"
volumeMounts:
- name: skywalking-agent
mountPath: /agent
containers:
- name: coffee-material
image: "treezh-docker.pkg.coding.net/demo03/public/coffee-material:8bc05202416f680c2a3a7179703be94ad806a099"
imagePullPolicy: IfNotPresent
env:
- name: LOGGING_LEVEL_ROOT
value: "INFO"
...
volumeMounts:
- name: skywalking-agent
mountPath: /skywalking
...
...
4. 把需要加载的文件从跟 initContainer 拷贝到共享文件夹
# Source: coffee-maker/templates/coffee-material.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: coffee-material
spec:
template:
spec:
volumes:
- name: skywalking-agent
emptyDir: { }
initContainers:
- name: skywalking-agent
image: "treezh-docker.pkg.coding.net/demo03/public/skywalking-java-agent:8.9.0-alpine"
volumeMounts:
- name: skywalking-agent
mountPath: /agent
command: [ "/bin/sh" ]
args: [ "-c", "cp -R /skywalking/agent /agent/" ]
containers:
- name: coffee-material
image: "treezh-docker.pkg.coding.net/demo03/public/coffee-material:8bc05202416f680c2a3a7179703be94ad806a099"
imagePullPolicy: IfNotPresent
env:
- name: LOGGING_LEVEL_ROOT
value: "INFO"
...
volumeMounts:
- name: skywalking-agent
mountPath: /skywalking
...
...
5. 添加环境变量,指定从共享文件夹中加载 javaagent,并且设置应用名称,上报地址等信息
# Source: coffee-maker/templates/coffee-material.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: coffee-material
spec:
template:
spec:
volumes:
- name: skywalking-agent
emptyDir: { }
initContainers:
- name: skywalking-agent
image: "treezh-docker.pkg.coding.net/demo03/public/skywalking-java-agent:8.9.0-alpine"
volumeMounts:
- name: skywalking-agent
mountPath: /agent
command: [ "/bin/sh" ]
args: [ "-c", "cp -R /skywalking/agent /agent/" ]
containers:
- name: coffee-material
image: "treezh-docker.pkg.coding.net/demo03/public/coffee-material:8bc05202416f680c2a3a7179703be94ad806a099"
imagePullPolicy: IfNotPresent
env:
- name: LOGGING_LEVEL_ROOT
value: "INFO"
- name: JAVA_TOOL_OPTIONS
value: "-javaagent:/skywalking/agent/skywalking-agent.jar"
- name: SW_AGENT_NAME
value: "coffee-material"
- name: SW_AGENT_COLLECTOR_BACKEND_SERVICES
value: "oap:11800"
...
volumeMounts:
- name: skywalking-agent
mountPath: /skywalking
...
...
6. 完成配置,重新部署该服务。
使用如下指令重新部署:
kubectl apply -f coffee-maker.yaml
看到有 Picked up JAVA_TOOL_OPTIONS: ...
一行信息,就说明 skywalking agent 已经加载成功了。
+ java -server -Djava.awt.headless=true -XX:-OmitStackTraceInFastThrow -Djava.security.egd=file:/dev/./urandom -jar /app/coffee-machine.jar
Picked up JAVA_TOOL_OPTIONS: -javaagent:/skywalking/agent/skywalking-agent.jar
DEBUG 2022-05-15 18:47:00:001 main AgentPackagePath : The beacon class location is jar:file:/skywalking/agent/skywalking-agent.jar!/org/apache/skywalking/apm/agent/core/boot/AgentPackagePath.class.
...
...
如果想要确认是否已经加载了自己想要的包,以及链路信息是否正常上报等更多信息,则可以更改 Skywalking agent 的日志输出级别和输出方式来查看更多的信息。
- name: SW_LOGGING_LEVEL
value: "DEBUG"
- name: SW_LOGGING_OUTPUT
value: "CONSOLE"
要 k8s 环境里面在不修改应用镜像的前提下,给 java 应用加载到 skywalking agent 主要有两个问题需要解决。
第一个问题是如何在不修改应用镜像的前提下,把 javaagent.jar
(指 skywalking-agent.jar
) 放到应用容器可访问的路径里面。这个问题常见的解法就是添加一个与目标 container
有共享目录的 initContainer
, 让这个新加的 initContainer
携带文件并拷贝文件到共享目录。
第二个问题是如何在不修改应用镜像前提下加载 javaagent.jar
。有的人可能会想到通过修改目标容器的 command
和 args
,往里面添加 -javaagent:/skywalking/agent/javaagent.jar
参数实现加载。这种方法要求知道目标容器的 java 路径和启动文件路径,而且容易覆盖掉原有的 java 启动参数。
解决第二个问题的另外一种办法,就是利用 JVM 支持的 JAVA_TOOL_OPTIONS
,参考 JDK-4971166。该环境变量支持从环境变量读取 java 启动参数。但是实际支持情况也要看具体的 jdk 发行版与所在环境么。如在 oracle jdk
中,出于安全考虑,在一些操作系统中此环境变量默认是禁用的,参考 The JAVA_TOOL_OPTIONS Environment Variable。
利用 JVM 的 JAVA_TOOL_OPTIONS
特性,可以在对应用镜像 0 知识的情况下让应用实现对 javaagent.jar
的加载。也就使得这个操作可以完全由 operator 代替手工操作,实现全自动的 agent 注入。其实本文所讲述的实现,正是 skywalking-swck
和 opentelemetry-operator
支持全自动织入 agent 的实现原理。随着这些 operator
的成熟与普及,链路追踪的接入门槛降大大降低,实现真正意义上的链路追踪全流程的开箱即用。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。