Java 9 ProcessHandle API in Docker: PID 值和可见进程的差异
Java 9 ProcessHandle API in Docker: Difference in PID values and visible processes
在尝试新的 ProcessHandle
API in Java 9 on a simple "Dockerized" Java program, I found a difference in terms of behavior when it comes to retrieving process IDs of running processes. Specifically when calling the method ProcessHandle.pid()
时,在 Docker 上生成的 PID 与主机上显示的本机 ID 不同 ,尽管文档说方法 "returns the native process ID of the process"。此外,ProcessHandle.allProcesses()
.
的结果也有差异
为了演示,下面的程序执行以下操作:
- 打印当前进程的PID,
- 生成一个休眠几秒钟的子进程(以便有时间打印其信息),
- 最后打印所有可见进程。
public static void main(String[] args) {
System.out.println("### Current process info ###");
ProcessHandle currentProcess = ProcessHandle.current();
printInfo(currentProcess);
System.out.println();
// Fork a child process that lasts for a few seconds
spawnProcess("jshell --startup ./sleep.txt");
printAllVisibleProcesses();
}
private static void printAllVisibleProcesses() {
System.out.println("### Visible processes info ###");
ProcessHandle.allProcesses().forEach(ProcessHandleExamples::printInfo);
System.out.println();
}
private static void spawnProcess(String command) {
System.out.println("Spawning: " + command);
try {
Runtime.getRuntime().exec(command);
} catch (IOException e) {
e.printStackTrace();
}
}
private static void printInfo(ProcessHandle processHandle) {
ProcessHandle.Info processInfo = processHandle.info();
System.out.println("Process ID: " + processHandle.pid());
System.out.println("Process arguments: " + Arrays.toString(processInfo.arguments().orElse(new String[0])));
System.out.println("Process executable: " + processInfo.command().orElse(""));
System.out.println("Process command line: " + processInfo.commandLine().orElse(""));
System.out.println("Process start time: " + processInfo.startInstant().orElse(null));
System.out.println("Process total cputime accumulated: " + processInfo.totalCpuDuration().orElse(null));
System.out.println("Process user: " + processInfo.user().orElse(""));
}
当运行正常运行应用程序时(没有Docker),输出符合预期;它包括当前进程的本机 PID、它的子进程和许多其他可见进程。
### Current process info ###
Process ID: 7756
Process arguments: []
Process executable: D:\Dev\Java\jdk-9\bin\java.exe
Process command line:
Process start time: 2017-10-08T12:23:46.474Z
Process total cputime accumulated: PT0.4368028S
Process user: manouti
Spawning: jshell --startup ./sleep.txt
### Visible processes info ###
... skipping some output
Process ID: 8060
Process arguments: []
Process executable: C:\Program Files (x86)\Google\Chrome\Application\chrome.exe
Process command line:
Process start time: 2017-10-08T12:20:04.758Z
Process total cputime accumulated: PT10.4676671S
Process user: manouti
Process ID: 7756
Process arguments: []
Process executable: D:\Dev\Java\jdk-9\bin\java.exe
Process command line:
Process start time: 2017-10-08T12:23:46.474Z
Process total cputime accumulated: PT0.8268053S
Process user: manouti
Process ID: 8080
Process arguments: []
Process executable: D:\Dev\Java\jdk-9\bin\jshell.exe
Process command line:
Process start time: 2017-10-08T12:23:46.992Z
Process total cputime accumulated: PT0.0780005S
Process user: manouti
当我在 Docker 上 运行 (Windows 7 with Docker 运行 在 boot2docker Linux 上),可见的进程子集要小得多,并且 PID 与主机上的进程不匹配。
$ docker run test/java9-processhandle-example:1.0
运行执行上述命令后,主机显示如下进程:
但是,下面生成的程序输出显示 PID 1 和 16,而不是 4291 和 4333。可见进程包括容器进程和派生进程。
我想知道这是否符合预期。由于我对 Docker 比较陌生,如果这是容器造成的限制,我会很高兴有人能解释一下(我也不确定这是否可以在不同的 Docker 上重现)设置,例如 Linux 或 Windows 服务器上的 Docker)。否则,这是否是 API 本身在容器中应用时的限制(Javadocs 中似乎没有提及)?
### Current process info ###
Process ID: 1
Process arguments: [ProcessHandleExamples]
Process executable: /usr/lib/jvm/java-9-openjdk-amd64/bin/java
Process command line: /usr/lib/jvm/java-9-openjdk-amd64/bin/java ProcessHandleExamples
Process start time: 2017-10-08T14:17:48.420Z
Process total cputime accumulated: PT0.35S
Process user: root
Spawning: jshell --startup ./sleep.txt
### Visible processes info ###
Process ID: 1
Process arguments: [ProcessHandleExamples]
Process executable: /usr/lib/jvm/java-9-openjdk-amd64/bin/java
Process command line: /usr/lib/jvm/java-9-openjdk-amd64/bin/java ProcessHandleExamples
Process start time: 2017-10-08T14:17:48.420Z
Process total cputime accumulated: PT0.6S
Process user: root
Process ID: 16
Process arguments: [--startup, ./sleep.txt]
Process executable: /usr/lib/jvm/java-9-openjdk-amd64/bin/jshell
Process command line: /usr/lib/jvm/java-9-openjdk-amd64/bin/jshell --startup ./sleep.txt
Process start time: 2017-10-08T14:17:49.070Z
Process total cputime accumulated: PT0.03S
Process user: root
这不是 Java 或 Java 9 特有的,它是 docker 主题。
每个容器都有自己的 PID 命名空间,容器中 运行 的第一个进程的 PID 为 1。
您可以在 docker documentation 中阅读更多相关信息,尤其是:
By default, all containers have the PID namespace enabled.
PID namespace provides separation of processes. The PID Namespace removes the view of the system processes, and allows process ids to be reused including pid 1.
因此 运行 需要一个带有 --pid=host
的容器,以允许 ProcessHandle.pid()
到 return 隐含的预期值在文档中(由操作系统分配的本机 PID)。
它还使 ProcessHandle.allProcesses()
return 系统可见进程,而不仅仅是绑定到容器的进程。
在尝试新的 ProcessHandle
API in Java 9 on a simple "Dockerized" Java program, I found a difference in terms of behavior when it comes to retrieving process IDs of running processes. Specifically when calling the method ProcessHandle.pid()
时,在 Docker 上生成的 PID 与主机上显示的本机 ID 不同 ,尽管文档说方法 "returns the native process ID of the process"。此外,ProcessHandle.allProcesses()
.
为了演示,下面的程序执行以下操作:
- 打印当前进程的PID,
- 生成一个休眠几秒钟的子进程(以便有时间打印其信息),
- 最后打印所有可见进程。
public static void main(String[] args) {
System.out.println("### Current process info ###");
ProcessHandle currentProcess = ProcessHandle.current();
printInfo(currentProcess);
System.out.println();
// Fork a child process that lasts for a few seconds
spawnProcess("jshell --startup ./sleep.txt");
printAllVisibleProcesses();
}
private static void printAllVisibleProcesses() {
System.out.println("### Visible processes info ###");
ProcessHandle.allProcesses().forEach(ProcessHandleExamples::printInfo);
System.out.println();
}
private static void spawnProcess(String command) {
System.out.println("Spawning: " + command);
try {
Runtime.getRuntime().exec(command);
} catch (IOException e) {
e.printStackTrace();
}
}
private static void printInfo(ProcessHandle processHandle) {
ProcessHandle.Info processInfo = processHandle.info();
System.out.println("Process ID: " + processHandle.pid());
System.out.println("Process arguments: " + Arrays.toString(processInfo.arguments().orElse(new String[0])));
System.out.println("Process executable: " + processInfo.command().orElse(""));
System.out.println("Process command line: " + processInfo.commandLine().orElse(""));
System.out.println("Process start time: " + processInfo.startInstant().orElse(null));
System.out.println("Process total cputime accumulated: " + processInfo.totalCpuDuration().orElse(null));
System.out.println("Process user: " + processInfo.user().orElse(""));
}
当运行正常运行应用程序时(没有Docker),输出符合预期;它包括当前进程的本机 PID、它的子进程和许多其他可见进程。
### Current process info ###
Process ID: 7756
Process arguments: []
Process executable: D:\Dev\Java\jdk-9\bin\java.exe
Process command line:
Process start time: 2017-10-08T12:23:46.474Z
Process total cputime accumulated: PT0.4368028S
Process user: manouti
Spawning: jshell --startup ./sleep.txt
### Visible processes info ###
... skipping some output
Process ID: 8060
Process arguments: []
Process executable: C:\Program Files (x86)\Google\Chrome\Application\chrome.exe
Process command line:
Process start time: 2017-10-08T12:20:04.758Z
Process total cputime accumulated: PT10.4676671S
Process user: manouti
Process ID: 7756
Process arguments: []
Process executable: D:\Dev\Java\jdk-9\bin\java.exe
Process command line:
Process start time: 2017-10-08T12:23:46.474Z
Process total cputime accumulated: PT0.8268053S
Process user: manouti
Process ID: 8080
Process arguments: []
Process executable: D:\Dev\Java\jdk-9\bin\jshell.exe
Process command line:
Process start time: 2017-10-08T12:23:46.992Z
Process total cputime accumulated: PT0.0780005S
Process user: manouti
当我在 Docker 上 运行 (Windows 7 with Docker 运行 在 boot2docker Linux 上),可见的进程子集要小得多,并且 PID 与主机上的进程不匹配。
$ docker run test/java9-processhandle-example:1.0
运行执行上述命令后,主机显示如下进程:
但是,下面生成的程序输出显示 PID 1 和 16,而不是 4291 和 4333。可见进程包括容器进程和派生进程。
我想知道这是否符合预期。由于我对 Docker 比较陌生,如果这是容器造成的限制,我会很高兴有人能解释一下(我也不确定这是否可以在不同的 Docker 上重现)设置,例如 Linux 或 Windows 服务器上的 Docker)。否则,这是否是 API 本身在容器中应用时的限制(Javadocs 中似乎没有提及)?
### Current process info ###
Process ID: 1
Process arguments: [ProcessHandleExamples]
Process executable: /usr/lib/jvm/java-9-openjdk-amd64/bin/java
Process command line: /usr/lib/jvm/java-9-openjdk-amd64/bin/java ProcessHandleExamples
Process start time: 2017-10-08T14:17:48.420Z
Process total cputime accumulated: PT0.35S
Process user: root
Spawning: jshell --startup ./sleep.txt
### Visible processes info ###
Process ID: 1
Process arguments: [ProcessHandleExamples]
Process executable: /usr/lib/jvm/java-9-openjdk-amd64/bin/java
Process command line: /usr/lib/jvm/java-9-openjdk-amd64/bin/java ProcessHandleExamples
Process start time: 2017-10-08T14:17:48.420Z
Process total cputime accumulated: PT0.6S
Process user: root
Process ID: 16
Process arguments: [--startup, ./sleep.txt]
Process executable: /usr/lib/jvm/java-9-openjdk-amd64/bin/jshell
Process command line: /usr/lib/jvm/java-9-openjdk-amd64/bin/jshell --startup ./sleep.txt
Process start time: 2017-10-08T14:17:49.070Z
Process total cputime accumulated: PT0.03S
Process user: root
这不是 Java 或 Java 9 特有的,它是 docker 主题。
每个容器都有自己的 PID 命名空间,容器中 运行 的第一个进程的 PID 为 1。
您可以在 docker documentation 中阅读更多相关信息,尤其是:
By default, all containers have the PID namespace enabled.
PID namespace provides separation of processes. The PID Namespace removes the view of the system processes, and allows process ids to be reused including pid 1.
因此 运行 需要一个带有 --pid=host
的容器,以允许 ProcessHandle.pid()
到 return 隐含的预期值在文档中(由操作系统分配的本机 PID)。
它还使 ProcessHandle.allProcesses()
return 系统可见进程,而不仅仅是绑定到容器的进程。