如何获取宿主机上容器中的jvm数据
How to get the jvm data in the container on the host
有这样的需要检测容器中的jvm代码是否被恶意修改。我google一些相关问题,我们可以通过Java Instrumentation动态监控jvm。但是第一步失败了,无法获取到容器中的jvm。如果是host jvm就ok了
例如
Test.java
import com.sun.tools.attach.AttachNotSupportedException;
import com.sun.tools.attach.VirtualMachine;
import com.sun.tools.attach.VirtualMachineDescriptor;
import java.io.IOException;
import java.util.List;
public class Main {
public static void main(String[] args) throws IOException, AttachNotSupportedException {
List<VirtualMachineDescriptor> list = VirtualMachine.list();
for (VirtualMachineDescriptor virtualMachineDescriptor : list) {
System.out.println("virtualMachineDescriptor = " + virtualMachineDescriptor);
}
}
}
我在后台启动了一个springboot项目。
javac 和 运行 它。
➜ java javac Main.java
➜ java java Main
virtualMachineDescriptor = sun.tools.attach.BsdAttachProvider@7a81197d: 20819 springboot.jar
virtualMachineDescriptor = sun.tools.attach.BsdAttachProvider@7a81197d: 21492 Main
virtualMachineDescriptor = sun.tools.attach.BsdAttachProvider@7a81197d: 41035
有效。我打算在容器中实现同样的效果
这是我的开发环境
OS: Ubuntu 18.04
JDK: openjdk8
docker:
Client: Docker Engine - Community
Version: 20.10.6
API version: 1.41
Go version: go1.13.15
Git commit: 370c289
Built: Fri Apr 9 22:46:01 2021
OS/Arch: linux/amd64
Context: default
Experimental: true
Server: Docker Engine - Community
Engine:
Version: 20.10.6
API version: 1.41 (minimum version 1.12)
Go version: go1.13.15
Git commit: 8728dd2
Built: Fri Apr 9 22:44:13 2021
OS/Arch: linux/amd64
Experimental: false
containerd:
Version: 1.4.4
GitCommit: 05f951a3781f4f2c1911b05e61c160e9c30eaa8e
runc:
Version: 1.0.0-rc93
GitCommit: 12644e614e25b05da6fd08a38ffa0cfe1903fdec
docker-init:
Version: 0.19.0
GitCommit: de40ad0
- 在后台启动一个网络容器
docker run -d -p 8080:8080 springboot_demo
(springboot_demo那个镜像是我自己建的)
FROM openjdk:8
COPY springboot.jar app.jar
EXPOSE 8080
ENTRYPOINT ["java","-jar","/app.jar"]
docker top container_id
我得到容器 pid 24820
javacode
import com.sun.tools.attach.AttachNotSupportedException;
import com.sun.tools.attach.VirtualMachine;
import com.sun.tools.attach.VirtualMachineDescriptor;
import java.io.IOException;
import java.util.List;
public class Main {
public static void main(String[] args) throws IOException, AttachNotSupportedException {
¦ VirtualMachine vm = VirtualMachine.attach("24820");
¦ System.out.println(vm);
}
}
javac Main.java && java Main
我遇到了这些错误。
Exception in thread "main" com.sun.tools.attach.AttachNotSupportedException: Unable to open socket file: target process not responding or HotSpot VM not loaded
at sun.tools.attach.LinuxVirtualMachine.<init>(LinuxVirtualMachine.java:106)
at sun.tools.attach.LinuxAttachProvider.attachVirtualMachine(LinuxAttachProvider.java:63)
at com.sun.tools.attach.VirtualMachine.attach(VirtualMachine.java:208)
at Main.main(Main.java:17)
是否可以在同一台机器上从外部获取容器中的jvm数据?
JDK 8 不支持命名空间,因此无法附加到不同挂载命名空间(即容器)中的 JVM 进程。
Attach API 已修复,可以与 JDK 10 中的容器一起使用。
同时有 jattach 项目解决了这个问题。
jattach
允许连接到容器中的任何 HotSpot JVM(包括 JDK 8 甚至更早的 JDKs),即使主机上没有安装 JDK(这是一个很小的纯 C 语言程序)。您可以使用 jattach
代替 Java 附加 API 以执行任何操作:
- 加载Java代理;
- 获取线程转储和堆转储;
- 调用
jcmd
命令等。
有这样的需要检测容器中的jvm代码是否被恶意修改。我google一些相关问题,我们可以通过Java Instrumentation动态监控jvm。但是第一步失败了,无法获取到容器中的jvm。如果是host jvm就ok了
例如
Test.java
import com.sun.tools.attach.AttachNotSupportedException;
import com.sun.tools.attach.VirtualMachine;
import com.sun.tools.attach.VirtualMachineDescriptor;
import java.io.IOException;
import java.util.List;
public class Main {
public static void main(String[] args) throws IOException, AttachNotSupportedException {
List<VirtualMachineDescriptor> list = VirtualMachine.list();
for (VirtualMachineDescriptor virtualMachineDescriptor : list) {
System.out.println("virtualMachineDescriptor = " + virtualMachineDescriptor);
}
}
}
我在后台启动了一个springboot项目。 javac 和 运行 它。
➜ java javac Main.java
➜ java java Main
virtualMachineDescriptor = sun.tools.attach.BsdAttachProvider@7a81197d: 20819 springboot.jar
virtualMachineDescriptor = sun.tools.attach.BsdAttachProvider@7a81197d: 21492 Main
virtualMachineDescriptor = sun.tools.attach.BsdAttachProvider@7a81197d: 41035
有效。我打算在容器中实现同样的效果
这是我的开发环境
OS: Ubuntu 18.04
JDK: openjdk8
docker:
Client: Docker Engine - Community
Version: 20.10.6
API version: 1.41
Go version: go1.13.15
Git commit: 370c289
Built: Fri Apr 9 22:46:01 2021
OS/Arch: linux/amd64
Context: default
Experimental: true
Server: Docker Engine - Community
Engine:
Version: 20.10.6
API version: 1.41 (minimum version 1.12)
Go version: go1.13.15
Git commit: 8728dd2
Built: Fri Apr 9 22:44:13 2021
OS/Arch: linux/amd64
Experimental: false
containerd:
Version: 1.4.4
GitCommit: 05f951a3781f4f2c1911b05e61c160e9c30eaa8e
runc:
Version: 1.0.0-rc93
GitCommit: 12644e614e25b05da6fd08a38ffa0cfe1903fdec
docker-init:
Version: 0.19.0
GitCommit: de40ad0
- 在后台启动一个网络容器
docker run -d -p 8080:8080 springboot_demo
(springboot_demo那个镜像是我自己建的)
FROM openjdk:8
COPY springboot.jar app.jar
EXPOSE 8080
ENTRYPOINT ["java","-jar","/app.jar"]
docker top container_id
我得到容器 pid 24820javacode
import com.sun.tools.attach.AttachNotSupportedException;
import com.sun.tools.attach.VirtualMachine;
import com.sun.tools.attach.VirtualMachineDescriptor;
import java.io.IOException;
import java.util.List;
public class Main {
public static void main(String[] args) throws IOException, AttachNotSupportedException {
¦ VirtualMachine vm = VirtualMachine.attach("24820");
¦ System.out.println(vm);
}
}
javac Main.java && java Main
我遇到了这些错误。
Exception in thread "main" com.sun.tools.attach.AttachNotSupportedException: Unable to open socket file: target process not responding or HotSpot VM not loaded
at sun.tools.attach.LinuxVirtualMachine.<init>(LinuxVirtualMachine.java:106)
at sun.tools.attach.LinuxAttachProvider.attachVirtualMachine(LinuxAttachProvider.java:63)
at com.sun.tools.attach.VirtualMachine.attach(VirtualMachine.java:208)
at Main.main(Main.java:17)
是否可以在同一台机器上从外部获取容器中的jvm数据?
JDK 8 不支持命名空间,因此无法附加到不同挂载命名空间(即容器)中的 JVM 进程。
Attach API 已修复,可以与 JDK 10 中的容器一起使用。
同时有 jattach 项目解决了这个问题。
jattach
允许连接到容器中的任何 HotSpot JVM(包括 JDK 8 甚至更早的 JDKs),即使主机上没有安装 JDK(这是一个很小的纯 C 语言程序)。您可以使用 jattach
代替 Java 附加 API 以执行任何操作:
- 加载Java代理;
- 获取线程转储和堆转储;
- 调用
jcmd
命令等。