web-dev-qa-db-fra.com

Faire fonctionner une application JavaFX 11 sur Docker

J'essaie d'obtenir une application qui fonctionne parfaitement sur ma machine pour fonctionner sur docker, voici mon fichier docker:

FROM openjdk:11-jre-slim
VOLUME /tmp
ADD someJar.jar someJar.jar
ADD lib lib
ADD config.properties config.properties
ENTRYPOINT ["Java", "-javaagent:lib/aspectjweaver-1.9.2.jar", 
    "-javaagent:lib/spring-instrument-5.1.6.RELEASE.jar", "--module-path", 
    "lib/javafx-sdk-11.0.2", "--add-modules=javafx.controls", "- 
    Dprism.verbose=true", "-jar","someJar.jar"]

J'ai également essayé de le baser sur la version Alpine openjdk11 avec le même résultat:

FROM adoptopenjdk/openjdk11:Alpine
VOLUME /tmp
RUN apk update && apk add libx11 mesa-gl gtk+3.0 && apk update
ADD someJar.jar someJar.jar
ADD lib lib
ADD config.properties config.properties
ENTRYPOINT ["Java", "-javaagent:lib/aspectjweaver-1.9.2.jar", "-javaagent:lib/spring-instrument-5.1.6.RELEASE.jar", "--module-path", "lib", "--add-modules=javafx.controls", "-Dprism.verbose=true", "-jar","someJar.jar"]

Le dossier lib contient la saveur linux du runtime openJFX (fichiers .so et fichiers .jar). Je développe cela sur une machine Windows avec l'équivalent Windows du runtime openJDK et cela fonctionne parfaitement. Lors de l'exécution du conteneur, j'obtiens la sortie suivante:

Prism pipeline init order: es2 sw
Using Double Precision Marlin Rasterizer
Using dirty region optimizations
Not using texture mask for primitives
Not forcing power of 2 sizes for textures
Using hardware CLAMP_TO_ZERO mode
Opting in for HiDPI pixel scaling
Prism pipeline name = com.Sun.prism.es2.ES2Pipeline
Loading ES2 native library ... prism_es2
GraphicsPipeline.createPipeline failed for com.Sun.prism.es2.ES2Pipeline
Java.lang.UnsatisfiedLinkError: no prism_es2 in Java.library.path: [/usr/Java/packages/lib, /usr/lib/x86_64-linux-gnu/jni, /lib/x86_64-linux-gnu, /usr/lib/x86_64-linux-gnu, /usr/lib/jni, /lib, /usr/lib]
    at Java.base/Java.lang.ClassLoader.loadLibrary(ClassLoader.Java:2660)
    at Java.base/Java.lang.Runtime.loadLibrary0(Runtime.Java:829)
    at Java.base/Java.lang.System.loadLibrary(System.Java:1867)
    at javafx.graphics/com.Sun.glass.utils.NativeLibLoader.loadLibraryInternal(NativeLibLoader.Java:150)
    at javafx.graphics/com.Sun.glass.utils.NativeLibLoader.loadLibrary(NativeLibLoader.Java:52)
    at javafx.graphics/com.Sun.prism.es2.ES2Pipeline.lambda$static$0(ES2Pipeline.Java:68)
    at Java.base/Java.security.AccessController.doPrivileged(Native Method)
    at javafx.graphics/com.Sun.prism.es2.ES2Pipeline.<clinit>(ES2Pipeline.Java:50)
    at Java.base/Java.lang.Class.forName0(Native Method)
    at Java.base/Java.lang.Class.forName(Class.Java:315)
    at javafx.graphics/com.Sun.prism.GraphicsPipeline.createPipeline(GraphicsPipeline.Java:187)
    at javafx.graphics/com.Sun.javafx.tk.quantum.QuantumRenderer$PipelineRunnable.init(QuantumRenderer.Java:91)
    at javafx.graphics/com.Sun.javafx.tk.quantum.QuantumRenderer$PipelineRunnable.run(QuantumRenderer.Java:124)
    at Java.base/Java.lang.Thread.run(Thread.Java:834)
*** Fallback to Prism SW pipeline
Prism pipeline name = com.Sun.prism.sw.SWPipeline
(X) Got class = class com.Sun.prism.sw.SWPipeline
Initialized prism pipeline: com.Sun.prism.sw.SWPipeline
Exception in thread "main" Java.lang.reflect.InvocationTargetException
    at Java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at Java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.Java:62)
    at Java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.Java:43)
    at Java.base/Java.lang.reflect.Method.invoke(Method.Java:566)
    at org.springframework.boot.loader.MainMethodRunner.run(MainMethodRunner.Java:47)
    at org.springframework.boot.loader.Launcher.launch(Launcher.Java:86)
    at org.springframework.boot.loader.Launcher.launch(Launcher.Java:50)
    at org.springframework.boot.loader.JarLauncher.main(JarLauncher.Java:51)
Caused by: Java.lang.UnsupportedOperationException: Unable to open DISPLAY
    at javafx.graphics/com.Sun.glass.ui.gtk.GtkApplication.lambda$new$6(GtkApplication.Java:173)
    at Java.base/Java.security.AccessController.doPrivileged(Native Method)
    at javafx.graphics/com.Sun.glass.ui.gtk.GtkApplication.<init>(GtkApplication.Java:171)
    at javafx.graphics/com.Sun.glass.ui.gtk.GtkPlatformFactory.createApplication(GtkPlatformFactory.Java:41)
    at javafx.graphics/com.Sun.glass.ui.Application.run(Application.Java:144)
    at javafx.graphics/com.Sun.javafx.tk.quantum.QuantumToolkit.startup(QuantumToolkit.Java:258)
    at javafx.graphics/com.Sun.javafx.application.PlatformImpl.startup(PlatformImpl.Java:269)
    at javafx.graphics/com.Sun.javafx.application.PlatformImpl.startup(PlatformImpl.Java:158)
    at javafx.graphics/com.Sun.javafx.application.LauncherImpl.startToolkit(LauncherImpl.Java:658)
    at javafx.graphics/com.Sun.javafx.application.LauncherImpl.launchApplication1(LauncherImpl.Java:678)
    at javafx.graphics/com.Sun.javafx.application.LauncherImpl.lambda$launchApplication$2(LauncherImpl.Java:195)
    at Java.base/Java.lang.Thread.run(Thread.Java:834)

Une idée de comment obtenir une application Java basée sur OpenJFX11 pour travailler dans Docker?

******METTRE À JOUR******

J'ai fait quelques progrès à ce sujet. J'ai trouvé que le fait de placer mes fichiers d'exécution openJFX DIRECTEMENT dans mon dossier lib faisait progresser un peu plus. La nouvelle erreur est devenue ceci:

ImportError: libGL.so.1: cannot open shared object file: No such file or directory

Après un peu de recherche, j'ai ajouté cette commande RUN dans mon dockerfile:

RUN apt-get update && apt-get install libgl1-mesa-glx -y

Cela me donne une nouvelle stacktrace:

Prism pipeline init order: es2 sw
Using Double Precision Marlin Rasterizer
Using dirty region optimizations
Not using texture mask for primitives
Not forcing power of 2 sizes for textures
Using hardware CLAMP_TO_ZERO mode
Opting in for HiDPI pixel scaling
Prism pipeline name = com.Sun.prism.es2.ES2Pipeline
Loading ES2 native library ... prism_es2
    succeeded.
GLFactory using com.Sun.prism.es2.X11GLFactory
(X) Got class = class com.Sun.prism.es2.ES2Pipeline
GraphicsPipeline.createPipeline: error initializing pipeline 
com.Sun.prism.es2.ES2Pipeline
*** Fallback to Prism SW pipeline
Prism pipeline name = com.Sun.prism.sw.SWPipeline
(X) Got class = class com.Sun.prism.sw.SWPipeline
Initialized prism pipeline: com.Sun.prism.sw.SWPipeline
Exception in thread "main" Java.lang.reflect.InvocationTargetException
    at Java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at Java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.Java:62)
    at Java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.Java:43)
    at Java.base/Java.lang.reflect.Method.invoke(Method.Java:566)
    at org.springframework.boot.loader.MainMethodRunner.run(MainMethodRunner.Java:47)
    at org.springframework.boot.loader.Launcher.launch(Launcher.Java:86)
    at org.springframework.boot.loader.Launcher.launch(Launcher.Java:50)
    at org.springframework.boot.loader.JarLauncher.main(JarLauncher.Java:51)
Caused by: Java.lang.UnsupportedOperationException: Unable to open DISPLAY
    at javafx.graphics/com.Sun.glass.ui.gtk.GtkApplication.lambda$new$6(GtkApplication.Java:173)
    at Java.base/Java.security.AccessController.doPrivileged(Native Method)
    at javafx.graphics/com.Sun.glass.ui.gtk.GtkApplication.<init>(GtkApplication.Java:171)
    at javafx.graphics/com.Sun.glass.ui.gtk.GtkPlatformFactory.createApplication(GtkPlatformFactory.Java:41)
    at javafx.graphics/com.Sun.glass.ui.Application.run(Application.Java:144)
    at javafx.graphics/com.Sun.javafx.tk.quantum.QuantumToolkit.startup(QuantumToolkit.Java:258)
    at javafx.graphics/com.Sun.javafx.application.PlatformImpl.startup(PlatformImpl.Java:269)
    at javafx.graphics/com.Sun.javafx.application.PlatformImpl.startup(PlatformImpl.Java:158)
    at javafx.graphics/com.Sun.javafx.application.LauncherImpl.startToolkit(LauncherImpl.Java:658)
    at javafx.graphics/com.Sun.javafx.application.LauncherImpl.launchApplication1(LauncherImpl.Java:678)
    at javafx.graphics/com.Sun.javafx.application.LauncherImpl.lambda$launchApplication$2(LauncherImpl.Java:195)
    at Java.base/Java.lang.Thread.run(Thread.Java:834)

****** UNE AUTRE MISE À JOUR ******

En fouillant dans le code JavaFX du fichier GtkApplication.class, voici la section qui échoue:

int libraryToLoad = _queryLibrary(gtkVersion, gtkVersionVerbose);

AccessController.doPrivileged((PrivilegedAction<Void>) () -> {
        if (libraryToLoad == QUERY_NO_DISPLAY) {
            throw new UnsupportedOperationException("Unable to open DISPLAY");
        } else if (libraryToLoad == QUERY_USE_CURRENT) {
            if (gtkVersionVerbose) {
                System.out.println("Glass GTK library to load is already loaded");
            }
        } else if (libraryToLoad == QUERY_LOAD_GTK2) {
            if (gtkVersionVerbose) {
                System.out.println("Glass GTK library to load is glassgtk2");
            }
            NativeLibLoader.loadLibrary("glassgtk2");
        } else if (libraryToLoad == QUERY_LOAD_GTK3) {
            if (gtkVersionVerbose) {
                System.out.println("Glass GTK library to load is glassgtk3");
            }
            NativeLibLoader.loadLibrary("glassgtk3");
        } else {
            throw new UnsupportedOperationException("Internal Error");
        }
        return null;
    });

Ai-je une bibliothèque manquante ou quelque chose?

... AIDEZ-MOI?

Merci

17
Martin

J'ai finalement réussi à faire fonctionner ça! J'ai dû installer VcXsrv sur mon hôte Windows et l'ajouter à la commande docker run:

-e DISPLAY=MY IP ADDRESS:0.0

Mon application démarre maintenant correctement et affiche les éléments suivants avant de réellement commencer l'initialisation de Spring:

Prism pipeline init order: es2 sw
Using Double Precision Marlin Rasterizer
Using dirty region optimizations
Not using texture mask for primitives
Not forcing power of 2 sizes for textures
Using hardware CLAMP_TO_ZERO mode
Opting in for HiDPI pixel scaling
Prism pipeline name = com.Sun.prism.es2.ES2Pipeline
Loading ES2 native library ... prism_es2
    succeeded.
GLFactory using com.Sun.prism.es2.X11GLFactory
MESA-LOADER: failed to open swrast (search paths /usr/lib/xorg/modules/dri)
libGL error: failed to load driver: swrast
Prism-ES2 Error : GL_VERSION (major.minor) = 1.4
(X) Got class = class com.Sun.prism.es2.ES2Pipeline
GraphicsPipeline.createPipeline: error initializing pipeline com.Sun.prism.es2.ES2Pipeline
*** Fallback to Prism SW pipeline
Prism pipeline name = com.Sun.prism.sw.SWPipeline
(X) Got class = class com.Sun.prism.sw.SWPipeline
Initialized prism pipeline: com.Sun.prism.sw.SWPipeline
MESA-LOADER: failed to open swrast (search paths /usr/lib/xorg/modules/dri)
libGL error: failed to load driver: swrast
vsync: true vpipe: false 

Il y a encore quelques erreurs que je vais essayer de résoudre, mais cela commence en fait maintenant!

Dockerfile complet comme demandé, je travaille toujours sur les erreurs qui le font revenir au pipeline de prisme, sera mis à jour plus tard:

FROM adoptopenjdk/openjdk11:Alpine
VOLUME /tmp
RUN apk update && apk add libx11 mesa-gl gtk+3.0 mesa-dri-swrast mesa-demos 
    && apk update
ADD someJar.jar someJar.jar
ADD lib lib
ADD config.properties config.properties
ENTRYPOINT ["Java", "-javaagent:lib/aspectjweaver-1.9.2.jar", "-javaagent:lib/spring-instrument-5.1.6.RELEASE.jar", "--module-path", "lib", "--add-modules=javafx.controls", "-Dprism.verbose=true", "-Djava.awt.headless=true", "-jar","someJar.jar"]

****** CONFIGURATION FINALE ******

J'ai creusé dans les erreurs libGL et les tracas de faire fonctionner le pipeline ES2 ne valent même pas la peine pour mes besoins. Cela impliquerait de jouer avec les pilotes Nvidia et CUDA et est totalement inutile car mon application n'est de toute façon qu'un service d'arrière-plan. Voici la configuration finale pour que tout fonctionne:

Dockerfile (repassé en openjdk pour plus de cohérence avec mon autre application et compris les paquets minimums à installer)

FROM openjdk:11-jre-slim
RUN apt-get update && apt-get install libgtk-3-0 libglu1-mesa -y && apt-get update
VOLUME /tmp
ADD someJar.jar someJar.jar
ADD lib lib
ADD config.properties config.properties
ENTRYPOINT ["Java", "-javaagent:lib/aspectjweaver-1.9.2.jar", "-javaagent:lib/spring-instrument-5.1.6.RELEASE.jar", "--module-path", "lib/javafx-sdk-11.0.2", "-jar", "someJar.jar"]

Commande de construction Docker

docker build -f Dockerfile -t some_service .

Commande d'exécution Docker

docker run -t --name Some_Service -e DISPLAY=MY IP:0.0 -e SOME_VARIABLE= --link mySQLSRV:mysql some_service

J'espère que cela aide quelqu'un, cela m'a pris des jours pour commencer à travailler!

10
Martin