作者:Matthew Lucas
追踪你现有的java应用程序,而不需要修改一行代码
自从我第一次摆弄Istio - 一个运行在K8s上的智能服务网格 - 我就被它的自动注入功能吸引住了。轻弹开关,Istio就会分散在你现有的部署中,为你提供梦幻般的服务网格能力,而无需修改、重新打包或以任何方式重新部署你现有的应用程序。
稍微解释一下这个过程,Istio使用了Kubernetes的一个特性,名为“Mutating Admission Webhooks”。这些比听起来要简单得多。在部署资源时,K8s将向所有活跃的webhook发送正在执行的操作的YAML表示。这些服务可以根据需要编辑部署 — 添加卷、调整环境变量、检查参数等等。
https://kubernetes.io/docs/reference/access-authn-authz/admission-controllers/#mutatingadmissionwebhook
为什么在乎?- 因为OpenTracing,这就是原因!
OpenTracing是什么?
OpenTracing是一个为分布式追踪启用可复用的、开放源码的、厂商中立的工具的倡议。事实上,OpenTracing本身正在成为一个更大的项目OpenTelemetry的一部分,但那是另一个事情了。
追踪是什么?单个追踪表示请求跳过应用程序中的服务后留下的足迹。它为你提供关于任何HTTP请求、数据库调用或你可能设置的其他范围的详细信息。它可以作为一种有用的工具来理解你流量的形状,并发现/调试跨一套微服务的任何瓶颈。
这与webhook有什么关系?首先,连接追踪是需要进行少量的开发。除非你在你的平台上测试所有的应用程序,价值是有限的,而如果你有10+微服务,这种努力可以很快增加。如果你能在大量投入之前试一下,就像你用Istio做的那样轻按一下开关,那不是很好吗?
本文的其余部分只解释了这个特性 — 至少对于Java应用程序是这样 — 以及它是如何结合在一起的。
特殊代理
在opentracing-contrib项目中发现的宝藏有一个Java特殊代理。通过使用-javaagent JVM标记将其插入到我们的应用程序中,我们可以完全启用跨任何常用第三方库的追踪,而无需更改任何代码或重新构建项目。测仪库的列表非常全面 - Jersey、Cassandra驱动程序、MongoDB驱动程序等等。
https://github.com/opentracing-contrib/java-specialagent
https://github.com/opentracing-contrib/java-specialagent#44-instrumentation-plugin
这里我们要做的是在部署时使用webhook、init容器和调整环境变量的组合来自动插入代理。
自动追踪webhook
完整的源代码在这里,但简单来说,webhook将:
https://github.com/lucas-matt/auto-tracing-webhook/blob/master/webhook.py
部署这一切
首先,确保Jaeger在你的默认命名空间中运行 - 可以简单执行:
kubectl apply -f https://raw.githubusercontent.com/jaegertracing/jaeger-kubernetes/master/all-in-one/jaeger-all-in-one-template.yml
接下来是webhook本身。它的源代码在这里:webhook.yaml。
https://raw.githubusercontent.com/lucas-matt/auto-tracing-webhook/master/webhook.yml
kubectl apply -f webhook.yml
最后,确保你标记了目标命名空间,以便webhook在内部的任何部署中都能被激活。
kubectl label namespace default autotrace=enabled
到目前为止,我们已经完成了。
尝试
让我们快速浏览一下解决方案。我们需要演示跨多个服务的请求,以显示追踪工作良好,端到端。
Deployment.yml创建了一个服务链A、B和C。A调用B,B调用C,C调用上游的world clock API。默认情况下,每个服务都是完全不受追踪的Spring Boot应用程序。
https://raw.githubusercontent.com/lucas-matt/pass-the-buck/master/deployment.yml
http://worldclockapi.com/api/json/gmt/now
每个服务都使用autotrace: enabled标签进行标记,以便我们的webhook知道在部署时将插装注入到应用程序中。
spec:
replicas: 1
selector:
matchLabels:
app: service-a
template:
metadata:
name: service-a
labels:
app: service-a
autotrace: enabled
在端口转发service-a之后,剩下的就是发出请求。
到目前为止一切顺利 - 我们得到了时间 - 但主要的问题是,它被追踪了吗?是时候检查Jaeger了:
成功!我们可以看到请求是如何沿着每个服务移动到web上的。
结论
这当前状态不是我在生产环境中使用的的解决方案 - 首先,未调优的应用程序启动性能被降级,代理扫描classpath以寻找它可以插入自己的完整库集 - 但这仍然是一个有趣的实验。
如果你对OpenTracing感兴趣,或者对如何创建你自己的Kubernetes webhook感兴趣,请看看源码库中的一些例子: