I am struggling with making an old JavaFX (+ JFoenix) school project work inside a Docker container. I made a multi-project Gradle build config (commons, server and client) that runs well with Java 21 directly on my computer (Manjaro 6.6.32 64-bits / Wayland / Intel Core 11th Gen i3-1115G4 x4), but not with the following Dockerfile for the client app :
FROM gradle:8-jdk21-alpine AS builder
WORKDIR /home/gradle
COPY --chown=gradle:gradle . .
RUN gradle build
FROM eclipse-temurin:21-jre-alpine
WORKDIR /usr/app
COPY --from=builder /home/gradle/client/build/distributions/client.tar .
RUN tar -xf client.tar
ENTRYPOINT ["./client/bin/client"]
With the command docker build -t jfxclient . && docker run --rm -e DISPLAY=$DISPLAY -v /tmp/.X11-unix:/tmp/.X11-unix:ro jfxclient
.
I have already solved some issues by adding the following line in the last stage :
RUN apk add --no-cache libx11 libxxf86vm mesa-gl mesa-dri-gallium
And running sudo xhost +local:docker
before to start the container.
Now, I am facing the following error at startup, and I have not been able to solve it:
MESA: error: Failed to query drm device.
glx: failed to create dri3 screen
failed to load driver: iris
#
# A fatal error has been detected by the Java Runtime Environment:
#
# SIGSEGV (0xb) at pc=0x0000000000003fe6, pid=7, tid=34
#
# JRE version: OpenJDK Runtime Environment Temurin-21.0.3+9 (21.0.3+9) (build 21.0.3+9-LTS)
# Java VM: OpenJDK 64-Bit Server VM Temurin-21.0.3+9 (21.0.3+9-LTS, mixed mode, sharing, tiered, compressed oops, compressed class ptrs, g1 gc, linux-amd64)
# Problematic frame:
# C [libprism_es2.so+0x8a1a] Java_com_sun_prism_es2_X11GLFactory_nInitialize+0x1fa
#
# Core dump will be written. Default location: Core dumps may be processed with "/usr/lib/systemd/systemd-coredump %P %u %g %s %t %c %h" (or dumping to /usr/app/core.7)
#
# An error report file with more information is saved as:
# /usr/app/hs_err_pid7.log
#
# If you would like to submit a bug report, please visit:
# https://github.com/adoptium/adoptium-support/issues
# The crash happened outside the Java Virtual Machine in native code.
# See problematic frame for where to report the bug.
#
Aborted (core dumped)
Changing the entrypoint to ENTRYPOINT ["/bin/sh"]
, I obtained the file /usr/app/hs_err_pid7.log
, but it is pretty long, 1181 lines. Here are what I consider to be the most interesting parts:
Stack: [0x00007fad00684000,0x00007fad00784a90], sp=0x00007fad00783600, free space=1021k
Native frames: (J=compiled Java code, j=interpreted, Vv=VM code, C=native code)
C [libprism_es2.so+0x8a1a] Java_com_sun_prism_es2_X11GLFactory_nInitialize+0x1fa
j com.sun.prism.es2.X11GLFactory.nInitialize([I)J+0 javafx.graphics@21.0.3
j com.sun.prism.es2.X11GLFactory.initialize(Ljava/lang/Class;Lcom/sun/prism/es2/GLPixelFormat$Attributes;)Z+73 javafx.graphics@21.0.3
j com.sun.prism.es2.ES2Pipeline.<clinit>()V+52 javafx.graphics@21.0.3
v ~StubRoutines::call_stub 0x00007fad53a64cc6
V [libjvm.so+0x912765] JavaCalls::call_helper(JavaValue*, methodHandle const&, JavaCallArguments*, JavaThread*)+0x2e5
V [libjvm.so+0x8ea08d] InstanceKlass::call_class_initializer(JavaThread*)+0x2ed
V [libjvm.so+0x8eb173] InstanceKlass::initialize_impl(JavaThread*)+0x6f3
V [libjvm.so+0x9f105d] find_class_from_class_loader(JNIEnv_*, Symbol*, unsigned char, Handle, Handle, unsigned char, JavaThread*)+0x7d
V [libjvm.so+0x9f9d40] JVM_FindClassFromCaller+0x110
C [libjava.so+0xe4d7] Java_java_lang_Class_forName0+0xd7
j java.lang.Class.forName0(Ljava/lang/String;ZLjava/lang/ClassLoader;Ljava/lang/Class;)Ljava/lang/Class;+0 java.base@21.0.3
j java.lang.Class.forName(Ljava/lang/String;Ljava/lang/Class;)Ljava/lang/Class;+19 java.base@21.0.3
j java.lang.Class.forName(Ljava/lang/String;)Ljava/lang/Class;+6 java.base@21.0.3
j com.sun.prism.GraphicsPipeline.createPipeline()Lcom/sun/prism/GraphicsPipeline;+183 javafx.graphics@21.0.3
j com.sun.javafx.tk.quantum.QuantumRenderer$PipelineRunnable.init()V+0 javafx.graphics@21.0.3
j com.sun.javafx.tk.quantum.QuantumRenderer$PipelineRunnable.run()V+1 javafx.graphics@21.0.3
j java.lang.Thread.runWith(Ljava/lang/Object;Ljava/lang/Runnable;)V+5 java.base@21.0.3
j java.lang.Thread.run()V+19 java.base@21.0.3
v ~StubRoutines::call_stub 0x00007fad53a64cc6
V [libjvm.so+0x912765] JavaCalls::call_helper(JavaValue*, methodHandle const&, JavaCallArguments*, JavaThread*)+0x2e5
V [libjvm.so+0x9140ab] JavaCalls::call_virtual(JavaValue*, Handle, Klass*, Symbol*, Symbol*, JavaThread*)+0x1cb
V [libjvm.so+0x9ee64a] thread_entry(JavaThread*, JavaThread*)+0x8a
V [libjvm.so+0x928ccf] JavaThread::thread_main_inner() [clone .part.0]+0xaf
V [libjvm.so+0xf82c98] Thread::call_run()+0xa8
V [libjvm.so+0xd0b23a] thread_native_entry(Thread*)+0x12a
Java frames: (J=compiled Java code, j=interpreted, Vv=VM code)
j com.sun.prism.es2.X11GLFactory.nInitialize([I)J+0 javafx.graphics@21.0.3
j com.sun.prism.es2.X11GLFactory.initialize(Ljava/lang/Class;Lcom/sun/prism/es2/GLPixelFormat$Attributes;)Z+73 javafx.graphics@21.0.3
j com.sun.prism.es2.ES2Pipeline.<clinit>()V+52 javafx.graphics@21.0.3
v ~StubRoutines::call_stub 0x00007fad53a64cc6
j java.lang.Class.forName0(Ljava/lang/String;ZLjava/lang/ClassLoader;Ljava/lang/Class;)Ljava/lang/Class;+0 java.base@21.0.3
j java.lang.Class.forName(Ljava/lang/String;Ljava/lang/Class;)Ljava/lang/Class;+19 java.base@21.0.3
j java.lang.Class.forName(Ljava/lang/String;)Ljava/lang/Class;+6 java.base@21.0.3
j com.sun.prism.GraphicsPipeline.createPipeline()Lcom/sun/prism/GraphicsPipeline;+183 javafx.graphics@21.0.3
j com.sun.javafx.tk.quantum.QuantumRenderer$PipelineRunnable.init()V+0 javafx.graphics@21.0.3
j com.sun.javafx.tk.quantum.QuantumRenderer$PipelineRunnable.run()V+1 javafx.graphics@21.0.3
j java.lang.Thread.runWith(Ljava/lang/Object;Ljava/lang/Runnable;)V+5 java.base@21.0.3
j java.lang.Thread.run()V+19 java.base@21.0.3
v ~StubRoutines::call_stub 0x00007fad53a64cc6
Internal exceptions (7 events):
Event: 0.098 Thread 0x00007fad616eb890 Implicit null exception at 0x00007fad540049e3 to 0x00007fad54004b40
Event: 0.100 Thread 0x00007fad616eb890 Exception <a 'java/lang/NoSuchMethodError'{0x000000008f2e7dc8}: 'void java.lang.invoke.DirectMethodHandle$Holder.invokeStatic(java.lang.Object, java.lang.Object, java.lang.Object, java.lang.Object)'> (0x000000008f2e7dc8)
thrown [src/hotspot/share/interpreter/linkResolver.cpp, line 772]
[...]
VM Arguments:
jvm_args: --module-path=/usr/app/client/lib/client.jar:/usr/app/client/lib/commun.jar:/usr/app/client/lib/jfoenix-9.0.10.jar:/usr/app/client/lib/javafx-fxml-21.0.3-linux.jar:/usr/app/client/lib/javafx-controls-21.0.3-linux.jar:/usr/app/client/lib/javafx-graphics-21.0.3-linux.jar:/usr/app/client/lib/javafx-base-21.0.3-linux.jar -Djdk.module.main=application.client
java_command: application.client/application.client.Main
java_class_path (initial): \"\"
Launcher Type: SUN_STANDARD
Logging:
Log output configuration:
#0: stdout all=warning uptime,level,tags foldmultilines=false
#1: stderr all=off uptime,level,tags foldmultilines=false
Environment Variables:
JAVA_HOME=/opt/java/openjdk
PATH=/opt/java/openjdk/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
LD_LIBRARY_PATH=/opt/java/openjdk/lib/server:/opt/java/openjdk/lib:/opt/java/openjdk/../lib
DISPLAY=:0
LANG=en_US.UTF-8
LC_ALL=en_US.UTF-8
TERM=xterm
I have installed mesa-demos
package and been successful to run glxgears
inside the container. It still prints the following message though:
MESA: error: Failed to query drm device.
glx: failed to create dri3 screen
failed to load driver: iris
Here is some info provided by glxinfo
:
name of display: :0
MESA: error: Failed to query drm device.
glx: failed to create dri3 screen
failed to load driver: iris
display: :0 screen: 0
direct rendering: Yes
server glx vendor string: SGI
server glx version string: 1.4
OpenGL vendor string: Mesa
OpenGL renderer string: llvmpipe (LLVM 17.0.5, 256 bits)
OpenGL core profile version string: 4.5 (Core Profile) Mesa 23.3.6
OpenGL core profile shading language version string: 4.50
eglinfo
has more info:
GBM platform:
eglinfo: eglInitialize failed
Wayland platform:
error: XDG_RUNTIME_DIR is invalid or not set in the environment.
error: XDG_RUNTIME_DIR is invalid or not set in the environment.
error: XDG_RUNTIME_DIR is invalid or not set in the environment.
eglinfo: eglInitialize failed
X11 platform:
MESA: error: Failed to query drm device.
libEGL warning: egl: failed to create dri2 screen
MESA: error: ZINK: vkCreateInstance failed (VK_ERROR_INCOMPATIBLE_DRIVER)
libEGL warning: egl: failed to create dri2 screen
EGL API version: 1.5
EGL vendor string: Mesa Project
EGL version string: 1.5
EGL client APIs: OpenGL OpenGL_ES
EGL driver name: swrast
I have tried many suggestions found on SO or elsewhere, but none did work so far.
I am now completely lost here. Any help would be greatly appreciated!
I resumed it just today and I got it.
From within the container with entrypoint /bin/sh
, I modified the client/bin/client
shell script to add the -Dprism.order=sw -Dprism.verbose=true
options in DEFAULT_JVM_OPTS=""
, as recommended by user jewelsea. (Actually, I could have just executed export JAVA_OPTS="-Dprism.order=sw"
before running the script to achieve the same result, so that's what I have done after.)
The first line when running the script changed from Prism pipeline init order: es2 sw
to [...]: sw
.
A new error log told me about ld-linux-x86-64.so.2: No such file or directory
and java.lang.UnsatisfiedLinkError: no glassgtk3 in java.library.path
. I have also installed libc6-compat
to fix it.
Then, finally, the app launched successfully. So far so good! Thanks to @jewelsea for the tip to finish this.
Final Dockerfile, run command and Docker Compose
FROM gradle:8-jdk21-alpine AS builder
WORKDIR /home/gradle
COPY --chown=gradle:gradle . .
RUN gradle build
FROM eclipse-temurin:21-jre-alpine AS client
WORKDIR /usr/app
RUN apk upgrade --no-cache && apk add --no-cache gtk+3.0 libc6-compat libcanberra-gtk3
# no more mesa packages required with sw, but I added libcanberra to fix a warning
COPY --from=builder /home/gradle/client/build/distributions/client.tar .
RUN tar -xf client.tar
ENV JAVA_OPTS="-Dprism.order=sw"
ENTRYPOINT ["./client/bin/client"]
sudo xhost +local:docker
# Reverse command: sudo xhost -local:docker
docker build -t client . && docker run -it --rm -e DISPLAY=$DISPLAY -e NO_AT_BRIDGE=1 -v /tmp/.X11-unix:/tmp/.X11-unix:ro --net=host --name client client
# $DISPLAY contains `:0`
services:
client:
build:
target: client
environment:
DISPLAY: $DISPLAY
NO_AT_BRIDGE: 1 # to ignore some warnings raised by GTK
network_mode: host
ports: []
volumes:
- /tmp/.X11-unix:/tmp/.X11-unix:ro
Other clues I found while doing research, but that did not fixed anything or not even tried:
-Djdk.gtk.version=3 -Djdk.gtk.verbose=true
-e XAUTHORITY=/tmp/.docker.xauth
-v /dev/dri:/dev/dri:ro
or -v /tmp/.docker.xauth:/tmp/.docker.xauth:ro
--platform linux/x86_64
(not tried)