Docker中的Java 9 ProcessHandle API:PID值和可见进程的差异

man*_*uti 2 java docker java-9 processhandle

ProcessHandle简单的"Dockerized"Java程序中尝试使用Java 9中的新API时,我发现在检索正在运行的进程的进程ID时,行为方面存在差异.特别是在调用方法时ProcessHandle.pid(),Docker上生成的PID与主机上显示的本机ID不同,尽管文档说该方法"返回进程的本机进程ID".另外,结果之间存在差异ProcessHandle.allProcesses().

为了演示,以下程序执行以下操作:

  1. 打印当前进程的PID,
  2. 产生一个睡眠时间为几秒钟的子进程(以便有时间打印其信息),
  3. 最后打印所有可见的进程.

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(""));
}
Run Code Online (Sandbox Code Playgroud)

正常运行应用程序(没有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
Run Code Online (Sandbox Code Playgroud)

当我在Docker上运行(Windows 7,在Boot2docker Linux上运行Docker)时,可以看到更小的进程子集,并且PID与主机上的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
Run Code Online (Sandbox Code Playgroud)

P.J*_*sch 6

这不是Java或Java 9特有的,它是一个docker主题.

每个容器都有自己的PID命名空间,容器中运行的第一个进程的PID为1.

您可以在docker文档中阅读更多相关信息,尤其是:

默认情况下,所有容器都启用了PID命名空间.

PID命名空间提供进程分离.PID命名空间删除系统进程的视图,并允许重用进程ID,包括pid 1.