2017-10-08 2 views
2

En essayant la nouvelle API ProcessHandle en Java 9 sur un simple programme Java "Dockerized", j'ai trouvé une différence de comportement quand il s'agit de récupérer des ID de processus des processus en cours. Spécifiquement lors de l'appel de la méthode ProcessHandle.pid(), le PID résultant sur Docker est différent de l'ID natif affiché sur l'hôte, bien que les docs disent que la méthode "renvoie l'ID de processus natif du processus". En outre, il y avait une différence entre les résultats de ProcessHandle.allProcesses().Java 9 ProcessHandle API dans Docker: différence dans les valeurs PID et les processus visibles

Pour démontrer, le programme ci-dessous effectue les opérations suivantes:

  1. imprime le PID du processus en cours,
  2. génère un processus enfant qui dort pendant quelques secondes (pour laisser le temps d'imprimer son info)
  3. et imprime enfin tous les processus visibles.

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

Lors de l'exécution de l'application normalement (sans Docker), la sortie est comme prévu; il inclut le PID natif du processus en cours, son processus fils et beaucoup d'autres processus visibles.

### 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 

Quand je cours sur Docker (Windows 7 avec Docker en cours d'exécution sur un boot2docker Linux), beaucoup plus petit sous-ensemble de processus sont visibles, et les PIDs ne correspondent pas à ceux de l'hôte.

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

Après l'exécution de la commande ci-dessus, l'hôte présente les processus suivants:

enter image description here

Cependant, la sortie du programme résultant ci-dessous montre les PID 1 et 16, au lieu de 4291 et 4333. Et les processus visibles comprennent le processus conteneur et le processus engendré.

Je me demande si c'est prévu. Comme je suis relativement nouveau à Docker, si c'est une limitation causée par le conteneur, je serais content que quelqu'un puisse l'expliquer (je ne suis pas sûr que cela soit reproductible sur une autre configuration de Docker, par exemple Docker sous Linux ou Windows) Serveur). Sinon, est-ce une limitation de l'API elle-même lorsqu'elle est appliquée dans des conteneurs (ce qui ne semble pas être mentionné dans les 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 
+4

Je m'attendrais presque ceci. Le conteneur ne devrait avoir aucune connaissance de la séquence PID de l'hôte. – Makoto

+2

Possible duplication de [mappage PID entre docker et hôte] (https://stackoverflow.com/questions/33328841/pid-mapping-between-docker-and-host) .. Cela n'a pas grand chose à voir avec Java ou sa version IMO. Vous pouvez suivre les liens par VonC dans la réponse pour réaliser les détails. – nullpointer

+0

Déplacement ici et juste pour clarifier plus loin, est votre question comment utiliser ProcessHandler dans Docker (dont je doute par le contenu) OU obtenir différents PIDs dans le docker et l'hôte (dans ce cas je crois que c'est un doublon)? – nullpointer

Répondre

6

Ceci n'est pas spécifique à Java ou Java 9, c'est un thème docker.

Chaque conteneur possède son propre espace de noms PID et le premier processus qui est exécuté dans le conteneur a un PID 1.

Vous pouvez en lire plus à ce sujet dans le docker documentation, en particulier:

Par Par défaut, tous les conteneurs ont l'espace de noms PID activé.

L'espace de noms PID assure la séparation des processus. Le Namespace PID supprime le point de vue des processus du système, et permet processus ids de réutiliser, y compris pid 1.

+0

Ce n'est même pas spécifique au docker, tout ce qui utilise les espaces de noms pid mentionnés le verra. Vous pouvez le faire au niveau le plus bas via 'unshare', indépendant de tous les autres axes de nommage – the8472

0

Il faut donc lancer un récipient avec --pid=host est nécessaire pour permettre au ProcessHandle.pid() de retourner la valeur attendue comme implicite dans la documentation (PID natif attribué par le système d'exploitation).

Il rend également le renvoyer les processus visibles du système, par opposition aux seuls processus liés au conteneur.

+0

_native_pid en Java est ce que vous voyez normalement avec une commande' ps'. Ceci est en différence avec les identifiants de processus, par exemple 'jps'. Ce sont des identifiants de processus internes Java. _native_ dans les conteneurs Docker sont toujours des espaces de noms, c'est le sens de mettre des choses dans les conteneurs pour ne pas exposer les données hôtes (et les données des autres conteneurs) –

+0

@PJMeisch Fait sens, bien que la documentation indique "l'ID de processus natif est un numéro d'identification le système d'exploitation assigne au processus ". Peut-être que les docs peuvent prendre en compte cette différence dans le futur. – manouti

+0

donc la question est, quel est le système d'exploitation dans un contexte conteneurisé? Je comprends que c'est le conteneur et donc vous obtenez les ids confinés. –