es4x
es4x copied to clipboard
Docker issues appear after upgrade from 0.13.3 to 0.14.0
It appears as though you can no longer use a slim java as a 'first layer' in docker.
In my Dockerfile I have the equivalent of
ARG BASEIMAGE=<any-slim-jdk-java11>
... <other commands omitted for brevity>
RUN tar xvfz <path-to-es4x-pm-0.14.0-bin.tar.gz> --strip-components=1 -C /usr/local \
&& es4x install \
&& es4x jlink --target=${JVM_TMP_DIR}
...
COPY --from=<baseimage>/lib/x86_64-linux-gnu/libz.so.1 /usr/lib
ENTRYPOINT [ "/usr/bin/java", "--module-path=node_modules/.jvmci", "-XX:+UnlockExperimentalVMOptions", "-XX:+EnableJVMCI", "--upgrade-module-path=node_modules/.jvmci/compiler.jar", "-XX:+UseContainerSupport", "-jar", "./node_modules/.bin/es4x-launcher.jar" ]
which worked fine in 0.13.3
I now get the following stacktrace
Installing JVMCI Compiler...
Installing GraalJS...
Skipping install (recent successful run)
Exception in thread "main" java.lang.module.FindException: Module org.graalvm.sdk not found, required by com.oracle.truffle.regex
at java.base/java.lang.module.Resolver.findFail(Resolver.java:877)
at java.base/java.lang.module.Resolver.resolve(Resolver.java:191)
at java.base/java.lang.module.Resolver.resolve(Resolver.java:140)
at java.base/java.lang.module.Configuration.resolve(Configuration.java:422)
at java.base/java.lang.module.Configuration.resolve(Configuration.java:256)
at jdk.jdeps/com.sun.tools.jdeps.JdepsConfiguration.<init>(JdepsConfiguration.java:117)
at jdk.jdeps/com.sun.tools.jdeps.JdepsConfiguration$Builder.build(JdepsConfiguration.java:563)
at jdk.jdeps/com.sun.tools.jdeps.JdepsTask.buildConfig(JdepsTask.java:589)
at jdk.jdeps/com.sun.tools.jdeps.JdepsTask.run(JdepsTask.java:543)
at jdk.jdeps/com.sun.tools.jdeps.JdepsTask.run(JdepsTask.java:519)
at jdk.jdeps/com.sun.tools.jdeps.Main.main(Main.java:49)
/opt/java/openjdk/bin/jdeps exit with status: 1
Doing an
--add-modules \
org.graalvm.sdk
seems to work for the org.graalvm.sdk. but then it complains about org.graalvm.truffle. Module org.graalvm.truffle not found, required by com.oracle.truffle.regex
Doing an
--add-modules \
org.graalvm.sdk,org.graalvm.truffle
doesn't seem to work as it shows a same error as above
If I change to ARG BASEIMAGE=oracle/graalvm-ce:20.3.0-java11
it seems to get past that but then I run into other issues like missing the libz.so.1 file. Ex:
COPY --from=<baseimage>/lib/x86_64-linux-gnu/libz.so.1 /usr/lib
so I have to change it to
COPY --from=<baseimage>/usr/lib/x64/libz.so.1 /usr/lib
That works but now I get complaints about the truffle-api not being on the classpath. So i add it like:
COPY --from=<baseimage> /opt/graalvm-ce-java11-20.3.0/lib/truffle/ /tmp/truffle/
ENTRYPOINT [ <replacing the -jar cmd with this> "-cp","./node_modules/.bin/es4x-launcher.jar:/tmp/truffle/*","io.reactiverse.es4x.ES4X", <all-other-params-the same> ...]
Which leads me to a
Exception in thread "main" java.lang.IllegalAccessError: superclass access check failed: class com.oracle.truffle.polyglot.PolyglotImpl (in unnamed module @0x2cbb3d47) cannot access class org.graalvm.polyglot.impl.AbstractPolyglotImpl (in module org.graalvm.sdk) because module org.graalvm.sdk does not export org.graalvm.polyglot.impl to unnamed module
Which seems to be a quarkus bug? https://github.com/quarkusio/quarkus/issues/10226 and https://stackoverflow.com/questions/62520374/com-oracle-truffle-polyglot-polyglotimpl-in-unnamed-module-cannot-access-class
You can see where this is going...
It can be a rabbit-hole to try and get the dockerfile working again between 0.13.3->0.14.0. Is that now a hard-requirement to use the graalvm as the base-layer?
As a sidenote, I see the entrypoint command mentions the .jvmci twice. The docker image at the final stage does not have the node_modules/.jvmci directory so I guess it just ignored those flags. If I copy the .jvmci folder into the final image I start getting errors about
Error occurred during initialization of boot layer java.lang.module.FindException: Module java.management not found, required by org.graalvm.truffle
Hi,
Just wondering if there was any movement on this, or when we could expect a release with this this fix.
Thanks!!
Not yet. Things get complicated when trying to support all combinations of VMs and builds. The current version creates docker containers using jlink of adoptopenjdk
java11 images and runs on distroless
base image to reduce the overall space. If the goal is to run on graalvm
base image, I think just adding the application layer is small and faster that forcing a jdeps
runtime. The base image will be on the server already so the final layer is very small and fast to deploy.
If this is really needed then if you could figure out the right modules that should be passed to jlink
I can quickly add a validation, if target is stock jvm, current behavior, else new one.
Regarding the release. Vert.x is about to release 4.0.1 so I am waiting for that moment to perform a full build and release. This will fix many TS "bugs" related to missing annotations upstream.
I would opt to keep using adoptopenjdk/distroless and not to use the graalvm base image. I just run into multiple hurdles when attempting to do so (as shown in the original post). If I'm understanding you correctly, will the 4.0.1 Vert.x release help resolve these?
FWIW I tried following the directions here using 0.14.0 as the target but the instructions don't work. https://reactiverse.io/es4x/get-started/package.html#jlink
In step #2 it complains about the -o/--only flag not being valid even though the docs show it is. If I remove it I end up in the same place as this ticket where the jlink can't find the org.graalvm.truffle module. No matter what I do with the jlink command (pointing to the correct jar, adding the module, etc) I cannot get past this. I wonder if there is an issue with the es4x jlink which prevents it from successfully linking (whereas the non es4x jlink might work differently)
It seems as though I've discovered a couple issues with the directions shown at : https://reactiverse.io/es4x/get-started/package.html#jlink
- It assumes the graal/truffle jars are in node_modules/.lib folder. They are not. They exist in the node_modules/.jvmci folder. I have to run a copy command in docker to put them there. I cannot use jlinks module-path as the es4x jlink seems hardcoded to only allow the node_modules/.lib folder.
- The es4x curl command outputs to /usr/local. The es4x jlink also outputs to /usr/local. If left with these defaults, jlink will error out saying /usr/local already exists. The former should probably be output to /es4x and have specific references changed to point to it
- Using the debian-stable image when I run it I get an error like: Failed in deploying verticle caused by SyntaxError: /usr/src/app/node_modules/@vertx/core/options.js:17:65 Expected ; but found SSLEngineOptions KeyCertOptions: Java.type('io.vertx.core.net.KeyCertOptions') SSLEngineOptions: Java.type('io.vertx.core.net.SSLEngineOptions') TrustOptions: Java.type('io.vertx.core.net.TrustOptions')/// <reference types="@vertx/core/options" /> at org.graalvm.sdk/org.graalvm.polyglot.Context.eval(Context.java:347) at io.reactiverse.es4x.Runtime$1.apply(Runtime.java:103) at io.reactiverse.es4x.Runtime$1.apply(Runtime.java:58) at js _load(file:/usr/src/app/node_modules/.lib/es4x-0.14.0.jar!/io/reactiverse/es4x/jvm-npm.js:68-71:2056-2187)
I have also tried doing an es4x dockerfile command. It has the same errors about the es4x -o/--only flag as shown 2 posts up. It has the same errors about the missing truffle/graalvm jars as in the previous post. Resolving them leads to the same error about SSSLEngineOptions as shown in the previous post.
I have tried every iteration that I can think of to get this working, but the es4x dockerfile command seems inherently broken within 0.14.0 as I cannot get the docker file up and running.
The only modification I made to the es4x dockerfile was changing:
RUN es4x install --only=prod
to
RUN es4x install && cp node_modules/.jvmci/* node_modules/.lib
FYI I filed a bug for the SyntaxError here : https://github.com/eclipse-vertx/vert.x/issues/3770
I got it to work. I had to:
- Manually override the options.js file with the syntax fix
- Copy the .jvmci contents into .lib
- Remove the --only property from es4x install
Hopefully these changes (or modifications of them) can be rolled into the es4x 0.14.1 release so it works out of the box.
@UglyHobbitFeet can you paste your resulting dockerfile here? I still have issues...
Sorry, I don't have it anymore. We've moved on to using a different tech stack.
On Tue, May 11, 2021 at 10:13 AM Benedikt Stemmildt < @.***> wrote:
@UglyHobbitFeet https://github.com/UglyHobbitFeet can you paste your resulting dockerfile here? I still have issues...
— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/reactiverse/es4x/issues/471#issuecomment-838547149, or unsubscribe https://github.com/notifications/unsubscribe-auth/ALBDS7W5X7PNCOW425XQZKLTNE3PPANCNFSM4UTVGX3A .
@UglyHobbitFeet thx for replying anyways!
@BeneStem have you seen this template?
https://github.com/reactiverse/es4x/blob/develop/pm/src/main/resources/META-INF/es4x-commands/Dockerfile
It doesn't rely on graal images anymore, just plain openjdk and the final image runs on google distroless which makes it reasonably small.
Can you share what is not working for you?
@pmlopes this actually did not work for me as the jlink step needs graal and therefore the openjdk11 baseimage is not working... Could be because of mac m1 docker issues but i doubt that.
And I'd recommend to use "npm ci" instead of "npm install" in ci/cd or docker scenarios :)
I can share the exact error this evening!
I am now using alpine... which is okayish but having distroless would be better ;)
FROM node:lts AS NPM
RUN ln -s /bin/true /usr/bin/es4x
WORKDIR /usr/src/app
COPY . .
RUN npm --unsafe-perm ci --only=prod
FROM adoptopenjdk/openjdk11 AS ES4X
RUN curl -sL https://github.com/reactiverse/es4x/releases/download/0.14.2/es4x-pm-0.14.2-bin.tar.gz | tar zx --strip-components=1 -C /usr/local
COPY --from=NPM /usr/src/app /usr/src/app
WORKDIR /usr/src/app
RUN es4x install --only=prod
FROM adoptopenjdk/openjdk11:jre-11.0.11_9-alpine
COPY --from=ES4X /usr/src/app /usr/src/app
WORKDIR /usr/src/app
ENTRYPOINT [ "java", "--module-path=node_modules/.jvmci", "-XX:+UnlockExperimentalVMOptions", "-XX:+EnableJVMCI", "--upgrade-module-path=node_modules/.jvmci/compiler.jar", "-XX:+UseContainerSupport", "-jar", "./node_modules/.bin/es4x-launcher.jar" ]
@pmlopes here is the error I get with the 0.14.2 default Dockerfile:
#18 21.41 Error: Missing dependencies: classes not found from the module path and classpath.
#18 21.41 To suppress this error, use --ignore-missing-deps to continue.
#18 21.41
#18 21.41 io.netty.codec
#18 21.41 io.netty.handler.codec.compression.JZlibDecoder -> com.jcraft.jzlib.Inflater not found
#18 21.41 io.netty.handler.codec.compression.JZlibDecoder -> com.jcraft.jzlib.JZlib not found
AND SO ON....
#18 21.43
#18 21.43 /opt/java/openjdk/bin/jdeps exit with status: 1
------
executor failed running [/bin/sh -c es4x jlink --target=/es4x]: exit code: 1
@BeneStem can you make a short project and dockerfile showing the error? It would be great help to solve this
Sure thing... When I was removing the --only=prod
from RUN es4x install --only=prod
it got better but still did not work...
@BeneStem sorry for the long wait, I've checked and we can get it to work more reliably with:
# Use official node for build
FROM node:lts AS NPM
# Disable calls to es4x command (this container has no JVM)
RUN ln -s /bin/true /usr/bin/es4x
# Create app directory
WORKDIR /usr/src/app
# Add the application to the container
COPY . .
# npm is run with unsafe permissions because the default docker user is root
# also all dev packages are not installed
RUN npm --unsafe-perm install --only=prod
# Second stage (build the JVM related code)
FROM adoptopenjdk/openjdk11 AS JVM
# Download the ES4X runtime tool
RUN curl -sL https://github.com/reactiverse/es4x/releases/download/0.14.2/es4x-pm-0.14.2-bin.tar.gz | tar zx --strip-components=1 -C /usr/local
# Copy the previous build step
COPY --from=NPM /usr/src/app /usr/src/app
# use the copied workspace
WORKDIR /usr/src/app
# force es4x maven resolution only to consider production dependencies
RUN es4x install --only=prod
# Third stage (contain)
FROM gcr.io/distroless/java:11
# Collect the jars from the previous step
COPY --from=JVM /usr/src/app /usr/src/app
WORKDIR /usr/src/app
# define the entrypoint
ENTRYPOINT [ "/usr/bin/java", "--module-path=node_modules/.jvmci", "-XX:+UnlockExperimentalVMOptions", "-XX:+EnableJVMCI", "--upgrade-module-path=node_modules/.jvmci/compiler.jar", "-XX:+UseContainerSupport", "-jar", "./node_modules/.bin/es4x-launcher.jar" ]
This avoids the jlink
step but still uses the distroless container, so in the end the size is ~250MB
I think until the jlink step is more reliable we should use this method, as it will be easier for end users to customize.
For reference 250MB isn't that big:
$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
es4x-flower latest d13911ffb716 28 seconds ago 267MB
adoptopenjdk/openjdk11 jre-11.0.11_9-alpine 98d92815b3d8 13 days ago 148MB
node lts 9153ee3e2ced 2 weeks ago 943MB
adoptopenjdk/openjdk11 latest c537c6b0cca2 4 weeks ago 437MB
hello-world latest d1165f221234 2 months ago 13.3kB
gcr.io/distroless/java 11 3ed3813dd91b 51 years ago 200MB
No problem. Thank you very much!
Using alpine, like I do a few comments above makes it 220mb...
Both ways are fine for me.
Is there any downside to using alpine?