在 Kubernetes 中远程调试 Java 应用程序
“在我机器上运行正常 ¯_(ツ)_/¯”——老一辈开发者经常在日常生活中使用这句话。如今,有了 Docker 和 Kubernetes 这样的平台,这类问题就能迎刃而解。
但别高兴得太早:有时你的应用程序并不会像在本地实现和测试的那样运行。经验丰富的开发人员在这种情况下会启用调试器,但在 Kubernetes 集群上操作起来就那么容易吗?答案是肯定的,我们将在本文中详细演示如何操作!
为了简单起见,本文将使用 IntelliJ 开发环境,但这不应该是一个很大的限制——其他开发环境也提供类似的功能。
概念
其基本思路是在 Kubernetes Pod(运行 Java 应用的 Pod)的某个端口上启用调试功能。该端口必须由 Pod 暴露出来。
之后,必须使用端口转发将本地端口转发到 Pod 的开放调试端口。最后,必须在开发环境中使用转发的本地端口启动 JVM 远程调试。下图展示了 Kubernetes 集群中远程调试的结构:
步骤 0:在 IntelliJ 中设置 JVM 远程调试
第一步是在 IntelliJ 中设置远程调试。为此,请打开以下配置窗口Run Configurations:
Run Configuration点击左上角的加号图标,然后Remote JVM Debug从列表中选择,即可创建新项目。- 然后你可以给配置项起任何你喜欢的名字。
- 标准配置通常无需调整。如果您的应用程序其他地方也使用了默认端口 5005,则可以在配置中进行更改。
- 现在复制命令行参数,下一步会用到它们。
- 最后,保存配置,因为以后会用到。
步骤 1:在远程 JVM 中启用调试
我们通常将应用程序打包成 Docker 镜像,并使用如下的 Dockerfile 构建这些镜像:
FROM eclipse-temurin:17-alpine
ARG ARTIFACT
COPY $ARTIFACT app.jar
ENTRYPOINT ["sh", "-c", "java $JAVA_OPTS -jar /app.jar"]
$JAVA_OPTS重要的是 ` <variable>` 中的变量ENTRYPOINT。我们使用它来插入之前复制的命令行参数。我们通过调整 Kubernetes 中的部署资源来实现这一点。使用 `<variable>`kubectl get deployments可以显示部署列表,使用 ` kubectl edit deployment <DEPLOYMENT_NAME><variable>` 可以按如下方式调整部署:
spec:
containers:
- ...
env:
- name: JAVA_OPTS
value: <COPIED_JAVA_OPTS>
ports:
- name: remotedebugging
containerPort: <PORT>
protocol: TCP
...
- 替换
<COPIED_JAVA_OPTS>为从 IntelliJ 复制的命令行参数。 - 替换
<PORT>为您用于调试的端口,在本例中为5005。
完成上述步骤后,您可以关闭编辑器,Kubernetes 将为您启动一个新的部署。您可以使用命令进行检查kubectl get pods。应该已经创建了一个新的 Pod。下一步非常重要:请复制 Pod 的名称!
步骤二:端口转发
Pod 重启后,必须将 Pod 的调试端口转发到本地计算机。可以使用以下命令完成此操作:kubectl port-forward <POD_NAME> <LOCAL_PORT>:<POD_PORT>
<POD_NAME>这是你在上一步中应该复制的 pod 的名称。<LOCAL_PORT>必须替换为本地用于转发的端口,以及开发环境连接进行调试的端口。<POD_PORT>这是你在上一步部署配置中打开的端口。
步骤 3:祝您调试愉快!
最后,必须启动步骤 0 中创建的调试配置,并应显示以下消息:Listening for transport dt_socket at address: 5005🎉
现在你可以设置断点并查找一些错误了!
资源
Michael Weidmann 为 devlix 博客撰稿,网址为https://www.devlix.de/blog。
本文最初发表于此处(德语):https://www.devlix.de/remote-debugging-von-java-apps-in-kubernetes/


