侧边栏壁纸
博主头像
运维日记-记录IT运维经验博主等级

行动起来,活在当下

  • 累计撰写 66 篇文章
  • 累计创建 7 个标签
  • 累计收到 0 条评论

目 录CONTENT

文章目录

alpine容器无法启动arthas

xlong
2024-03-24 / 0 评论 / 0 点赞 / 2 阅读 / 5576 字 / 正在检测是否收录...

alpine容器无法启动arthas

最近在容器环境中,发现在 Java 进程是 1 号进程的情况下,无法使用 [arthas]。

提示 AttachNotSupportedException: Unable to get pid of LinuxThreads manager thread。具体操作和报错如下:

bash-4.4# java -jar arthas-boot.jar

Picked up JAVA_TOOL_OPTIONS: -Xms256m -Xmx256m

[INFO] JAVA_HOME: /usr/lib/jvm/java-1.8-openjdk/jre

[INFO] arthas-boot version: 3.6.7

[INFO] JAVA_TOOL_OPTIONS: -Xms256m -Xmx256m

[INFO] Found existing java process, please choose one and input the serial number of the process, eg : 1. Then hit ENTER.

* [1]: 1 /usr/cpp/ccreate-new-procurement-cloud-annex-1.0-SNAPSHOT.jar

1

[INFO] arthas home: /root/.arthas/lib/3.6.7/arthas

[INFO] Try to attach process 1

Picked up JAVA_TOOL_OPTIONS: 

[ERROR] Start arthas failed, exception stack trace: 

com.sun.tools.attach.AttachNotSupportedException: Unable to get pid of LinuxThreads manager thread

	at sun.tools.attach.LinuxVirtualMachine.<init>(LinuxVirtualMachine.java:86)

	at sun.tools.attach.LinuxAttachProvider.attachVirtualMachine(LinuxAttachProvider.java:78)

	at com.sun.tools.attach.VirtualMachine.attach(VirtualMachine.java:250)

	at com.taobao.arthas.core.Arthas.attachAgent(Arthas.java:102)

	at com.taobao.arthas.core.Arthas.<init>(Arthas.java:27)

	at com.taobao.arthas.core.Arthas.main(Arthas.java:161)

[INFO] Attach process 1 success.

[INFO] arthas-client connect 127.0.0.1 3658

Connect to telnet server error: 127.0.0.1 3658

java.net.ConnectException: Connection refused (Connection refused)

	at java.net.PlainSocketImpl.socketConnect(Native Method)

	at java.net.AbstractPlainSocketImpl.doConnect(AbstractPlainSocketImpl.java:350)

	at java.net.AbstractPlainSocketImpl.connectToAddress(AbstractPlainSocketImpl.java:206)

	at java.net.AbstractPlainSocketImpl.connect(AbstractPlainSocketImpl.java:188)

	at java.net.SocksSocketImpl.connect(SocksSocketImpl.java:392)

	at java.net.Socket.connect(Socket.java:589)

	at org.apache.commons.net.SocketClient.connect(SocketClient.java:188)

	at org.apache.commons.net.SocketClient.connect(SocketClient.java:209)

	at com.taobao.arthas.client.TelnetConsole.process(TelnetConsole.java:306)

	at com.taobao.arthas.client.TelnetConsole.main(TelnetConsole.java:166)

	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)

	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)

	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)

	at java.lang.reflect.Method.invoke(Method.java:498)

	at com.taobao.arthas.boot.Bootstrap.main(Bootstrap.java:629)

正常的 attach 流程是什么样子的?

如下是在排查问题中,梳理出来的 jvm Attach 流程:

1. 查找 /tmp/.java_pid${pid} 这个 unix socket,如果存在则检查权限,然后建立连接。

2. 如果不存在则先创建 /proc/${pid}/cwd/.attach_pid${pid},开始通知 jvm 线程。

3. 首先判断是不是 LinuxThread如果是 LinuxThread则找到 LinuxThreadsManager,然后给其所有子进程发送 SIGQUIT.

4. 如果不是 LinuxThread,则直接给目标进程发送 SIGQUIT。

5. 目标进程收到信号后,创建 Attach Listener,监听 /tmp/.java_pid${pid}。

6. 开始正常的 socket 通信,根据通信的具体内容,可以是 dumpThread(jstack),也可以是加载 JavaAgent,比如上面提到的 arthas。

解决方法一: shell 模拟

pid=1 ;\

touch /proc/${pid}/cwd/.attach_pid${pid} && \

  kill -SIGQUIT ${pid} && \

  sleep 2 &&

  ls /proc/${pid}/root/tmp/.java_pid${pid}

# 接下来就可以正常 java -jar arthas-boot.jar 挂arthas了

通过上面的操作后,Attach Listener 已经启动并且监听了路径,第二次 attach 就直接可以连接了;就可以按照正常的方式使用 arthas 了。

其中有一点需要注意,**一定需要提前创建 .attach_pid${pid} 文件,不然 jvm 会将这个信号交给默认的 sigaction 处理,对于 pid 1 来说,会导致容器退出!**

解决方法二: 设置启动参数

注:这种方式需要调整启动参数或者环境变量,需要重启应用/容器,可能会丢失业务现场。

Jvm 支持设置 -XX:+StartAttachListener,这样就能在启动 Jvm 的时候,自动启动 Attach Listener 线程并监听,也可以正常使用 arthas。

对于容器环境下,更加容易的做法是给容器添加环境变量 JAVA_TOOL_OPTIONS=-XX:+StartAttachListener,这样不用修改启动脚本也能达到效果。

解决方法三:上游优先,修改镜像

注:这种方式需要修改镜像。

OpenJDK 8 官方没有修复这个问题,所以如果直接使用 openjdk:8-jdk-alpine,是避免不了这个问题的。Docker 镜像仓库也有人讨论这个问题[6]。

OpenJDK 11 就已经解决了这个问题了(见源码[7]),不再对古旧的 LinuxThread 模型做判断,这样 arthas 也能工作。

不过 Alpine 官方仓库中的 OpenJDK 8 已经通过自己打 patch 的方式,修复了这个问题:

https://gitlab.alpinelinux.org/alpine/aports/-/issues/13032

作为比较知名的 JDK 发行版,也在 eclipse-temurin:8-jdk-alpine 中修复了这个问题,可以直接使用这个镜像。相关讨论见:https://github.com/adoptium/jdk8u/pull/8

参考: https://blog.csdn.net/yunqiinsight/article/details/129080195

0

评论区