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

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

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

  1. 打印当前进程的PID,
  2. 产生一个睡眠几秒钟的subprocess(以允许打印其信息),
  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("")); } 

正常运行应用程序(不使用Docker)时,输出结果如预期; 它包括当前进程的本地PID,其subprocess和许多其他可见进程。

 ### 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上运行(在Boot2docker Linux上运行Docker的Windows 7 )时,可以看到更小的进程子集,并且PID与主机上的PID不匹配。

$ docker run test/java9-processhandle-example:1.0

运行以上命令后,主机显示如下进程:

在这里输入图像说明

但是,下面生成的程序输出显示PID 1和16,而不是4291和4333.可见进程包括容器进程和生成进程。

我想知道这是否是预期的。 由于我对Docker相对来说比较陌生,如果这是容器造成的限制,我会很高兴如果有人能解释它(我也不确定这是否可以在不同的Docker设置上重现,例如Linux或Windows上的Docker服务器)。 否则,这是API本身在应用于容器时的一个限制(这在Javadoc中似乎没有提到过)?

 ### 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文档中阅读更多关于这方面的信息 ,尤其是:

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

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

因此,需要使用--pid=host运行容器,以允许ProcessHandle.pid()返回文档中隐含的期望值(由操作系统分配的本地PID)。

它也使得ProcessHandle.allProcesses()返回系统可见进程 ,而不仅仅是绑定到容器的进程。