2017-10-08 65 views
2

在簡單的「Dockerized」Java程序中嘗試使用Java 9中的新的ProcessHandle API時,發現在檢索進程ID時行爲方面存在差異正在運行的進程。特別是在調用方法ProcessHandle.pid(),時,Docker上生成的PID與主機上顯示的本機ID不同,儘管文檔說該方法「返回進程的本機進程ID」。另外,ProcessHandle.allProcesses()的結果有差異。Docker中的Java 9 ProcessHandle API:PID值和可見進程的差異

爲了演示,下面的程序執行以下操作:

  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("")); 
} 

當正常運行的應用程序(不多克爾)時,如預期的輸出;它包含當前進程的本地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 

當我(與上一boot2docker的Linux運行泊塢的Windows 7)上運行的泊塢窗,流程更小的子集是可見的,的PID不匹配主機上的人。

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

運行上述命令後,主機顯示了以下過程:

enter image description here

然而,得到的程序輸出下面示出的代替的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 
+4

我幾乎期待這一點。容器不應該知道主機的PID序列。 – Makoto

+2

[docker和host之間的PID映射]的可能重複(https://stackoverflow.com/questions/33328841/pid-mapping-between-docker-and-host)..這與Java沒有多大關係,或者其版本IMO。您可以在答案中關注VonC的鏈接以瞭解詳細信息。 – nullpointer

+0

搬到這裏,只是爲了進一步闡明,你的問題是如何在Docker中使用ProcessHandler(我懷疑內容)或在docker和host中獲取不同的PID(在這種情況下,我相信它是重複的)? – nullpointer

回答

6

這不是特定於Java或Java 9,它是一個碼頭主題。

每個容器都有自己的PID命名空間和在該容器中運行的第一個進程有1

您可以在docker documentation閱讀更多關於這一點,特別是PID:

通過默認情況下,所有容器都啓用了PID名稱空間。

PID名稱空間提供進程分離。的PID命名空間移除系統進程的視圖,並允許過程ID,以包括PID被重用1.

+0

它甚至不是特定於docker的,任何使用提到的pid命名空間的東西都會遇到這種情況。您可以通過'unshare'在最低級別執行此操作,與所有其他命名空間軸無關。 – the8472

0

所以運行的容器--pid=host需要以允許如所暗示的ProcessHandle.pid()返回預期值文檔(由操作系統分配的本地PID)。

它也使得ProcessHandle.allProcesses()返回系統可見進程,而不僅僅是綁定到容器的進程。

+0

Java中的nnative_pid是您通常使用'ps'命令查看的內容。這與處理標識符有所不同,例如「jps」顯示。這些是Java內部進程ID。 Docker容器中的_native_始終是名稱空間的ID,這就是將容器放入容器而不是公開主機數據(以及來自其他容器的數據)的意義 –

+0

@PJMeisch儘管文檔中提到「本機進程ID是一個標識號操作系統分配給進程「。也許文檔可以在將來考慮這種差異。 – manouti

+0

所以問題是,在集裝箱環境中的操作系統是什麼?我明白這是容器,所以你得到了集裝箱ID。 –