keeganwitt / docker-gradle

Docker images with Gradle
https://hub.docker.com/_/gradle/
Apache License 2.0
148 stars 72 forks source link

Building in github actions for linux/arm/v7 with buildx fails due to missing module 'ant' #210

Open adamsong opened 2 years ago

adamsong commented 2 years ago

Full stack trace:

#10 1.985 org.gradle.api.internal.classpath.UnknownModuleException: Cannot locate JAR for module 'ant' in distribution directory '/opt/gradle'.
#10 1.987   at org.gradle.api.internal.classpath.DefaultModuleRegistry.loadExternalModule(DefaultModuleRegistry.java:109)
#10 1.987   at org.gradle.api.internal.classpath.DefaultModuleRegistry.getExternalModule(DefaultModuleRegistry.java:97)
#10 1.987   at org.gradle.api.internal.DefaultClassPathProvider.findClassPath(DefaultClassPathProvider.java:70)
#10 1.988   at org.gradle.api.internal.DefaultClassPathRegistry.getClassPath(DefaultClassPathRegistry.java:35)
#10 1.988   at org.gradle.launcher.bootstrap.ProcessBootstrap.runNoExit(ProcessBootstrap.java:48)
#10 1.988   at org.gradle.launcher.bootstrap.ProcessBootstrap.run(ProcessBootstrap.java:37)
#10 1.988   at org.gradle.launcher.GradleMain.main(GradleMain.java:31)

Docker file

FROM gradle:7.3.3-jdk17 AS build
COPY --chown=gradle:gradle . /home/gradle/src
WORKDIR /home/gradle/src
RUN gradle build --no-daemon

# Yes, this is the same base image as before, unfortunately I cannot find an arm/v7 JRE17 image
FROM gradle:7.3.3-jdk17
RUN mkdir /app
COPY --from=build /home/gradle/src/build/libs/*.jar /app/GhostBot.jar
ENTRYPOINT ["java", "-jar", "/app/GhostBot.jar"]
keeganwitt commented 2 years ago

Have you considered eclipse-temurin:17-jre as a runtime image? It's got linux/arm/v7 and linux/arm64/v8 images. There's also a eclipse-temurin:17-jdk image you might consider.

I'm not sure offhand why this is happening. The jar is in that directory.

# ls $GRADLE_HOME/lib/ant-1*.jar
/opt/gradle/lib/ant-1.10.11.jar
keeganwitt commented 2 years ago

Do you know of another place to test this? I'm not able to reproduce on Arm64 in Travis.

https://github.com/keeganwitt/gradle-on-arm-tests https://app.travis-ci.com/github/keeganwitt/gradle-on-arm-tests/builds/245610034

Andavin commented 2 years ago

I'm having this exact same issue when attempting to build for arm/v7. Note that it is not arm64. Is there a workaround for this? Are we supposed to build our own Gradle image using Eclipse Temurin?

keeganwitt commented 2 years ago

I was referring to using Temurin images as runtime image, not as a build time image. You don't need to build your own Gradle image, that's the point of this image.

jdk17 and jdk17-focal images are both available for arm v7 (as well as other tags).

keeganwitt commented 2 years ago

If possible, can you make a PR against https://github.com/keeganwitt/gradle-on-arm-tests or create a new repo with a reproduction of this? I haven't been able to reproduce this to figure out what might be going wrong.

afkfish commented 1 year ago

I am having the same issue in buildx on all platforms as the base platform i am building on:

docker buildx build --platform linux/arm/v7 .

the . at the end referring to the Dockerfile's location My Dockerfile:

FROM arm32v7/gradle:7.6-jdk19 AS builder
COPY --chown=gradle:gradle . /home/gradle/src
WORKDIR /home/gradle/src
RUN gradle build --no-daemon

FROM eclipse-temurin:19-jdk
RUN mkdir /app
COPY --from=builder /home/gradle/src/build/libs/*all.jar /app/Opal.jar

ENTRYPOINT ["java","-jar","/app/Opal.jar"]

And the output when i try to build the image:

[+] Building 4.0s (13/14)
 => [internal] load build definition from Dockerfile                                                                                                                                                                                                                                                           0.0s
 => => transferring dockerfile: 339B                                                                                                                                                                                                                                                                           0.0s 
 => [internal] load .dockerignore                                                                                                                                                                                                                                                                              0.0s 
 => => transferring context: 2B                                                                                                                                                                                                                                                                                0.0s 
 => [internal] load metadata for docker.io/library/eclipse-temurin:19-jdk                                                                                                                                                                                                                                      1.3s 
 => [internal] load metadata for docker.io/library/gradle:7.6-jdk19                                                                                                                                                                                                                                            1.6s 
 => [auth] library/eclipse-temurin:pull token for registry-1.docker.io                                                                                                                                                                                                                                         0.0s
 => [auth] library/gradle:pull token for registry-1.docker.io                                                                                                                                                                                                                                                  0.0s
 => [internal] load build context                                                                                                                                                                                                                                                                              0.1s
 => => transferring context: 39.66kB                                                                                                                                                                                                                                                                           0.1s 
 => CACHED [builder 1/4] FROM docker.io/library/gradle:7.6-jdk19@sha256:7b0d5ddb28458a90fe235884f89f89f216dac9604ae2d2e8504462af3f75ad61                                                                                                                                                                       0.0s 
 => => resolve docker.io/library/gradle:7.6-jdk19@sha256:7b0d5ddb28458a90fe235884f89f89f216dac9604ae2d2e8504462af3f75ad61                                                                                                                                                                                      0.0s 
 => [stage-1 1/3] FROM docker.io/library/eclipse-temurin:19-jdk@sha256:17e3d3b61ca4a7606490f596feb77f69980939fecacf91a1f13ea7b17147058f                                                                                                                                                                        0.0s 
 => => resolve docker.io/library/eclipse-temurin:19-jdk@sha256:17e3d3b61ca4a7606490f596feb77f69980939fecacf91a1f13ea7b17147058f                                                                                                                                                                                0.0s 
 => CACHED [stage-1 2/3] RUN mkdir /app                                                                                                                                                                                                                                                                        0.0s 
 => [builder 2/4] COPY --chown=gradle:gradle . /home/gradle/src                                                                                                                                                                                                                                                0.1s
 => [builder 3/4] WORKDIR /home/gradle/src                                                                                                                                                                                                                                                                     0.1s
 => ERROR [builder 4/4] RUN gradle build --no-daemon                                                                                                                                                                                                                                                           2.0s
------
 > [builder 4/4] RUN gradle build --no-daemon:
#0 1.922 org.gradle.api.internal.classpath.UnknownModuleException: Cannot locate JAR for module 'ant' in distribution directory '/opt/gradle'.
#0 1.928        at org.gradle.api.internal.classpath.DefaultModuleRegistry.loadExternalModule(DefaultModuleRegistry.java:145)
#0 1.928        at org.gradle.api.internal.classpath.DefaultModuleRegistry.getExternalModule(DefaultModuleRegistry.java:133)
#0 1.929        at org.gradle.api.internal.DefaultClassPathProvider.findClassPath(DefaultClassPathProvider.java:70)
#0 1.930        at org.gradle.api.internal.DefaultClassPathRegistry.getClassPath(DefaultClassPathRegistry.java:35)
#0 1.930        at org.gradle.launcher.bootstrap.ProcessBootstrap.runNoExit(ProcessBootstrap.java:48)
#0 1.931        at org.gradle.launcher.bootstrap.ProcessBootstrap.run(ProcessBootstrap.java:37)
#0 1.932        at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:104)
#0 1.933        at java.base/java.lang.reflect.Method.invoke(Method.java:578)
#0 1.933        at org.gradle.launcher.GradleMain.main(GradleMain.java:34)
------
Dockerfile:4
--------------------
   2 |     COPY --chown=gradle:gradle . /home/gradle/src
   3 |     WORKDIR /home/gradle/src
   4 | >>> RUN gradle build --no-daemon
   5 |
   6 |     FROM eclipse-temurin:19-jdk
--------------------
ERROR: failed to solve: process "/bin/sh -c gradle build --no-daemon" did not complete successfully: exit code: 1

Edit

I tried som stuff and the ant file is there but hten the build with gradle is still failing. I don't get it. It's there but not.

image
afkfish commented 1 year ago

Maybe its because gradle is not searching recursively in the /opt/gradle folder and not finding the ant file which is located in the /opt/gradle/lib?

keeganwitt commented 1 year ago

Are you invoking Ant from Gradle?

afkfish commented 1 year ago

The default gradle is, in the image. Or I suppose

keeganwitt commented 1 year ago

I'm asking about what's in your build.gradle. Are you doing something like this? https://docs.gradle.org/current/userguide/ant.html

afkfish commented 1 year ago

No I don't think so.

plugins {
    id 'com.github.johnrengelman.shadow' version '7.1.2'
    id 'java'
}

group 'com.afkfish'
version '0.2'

repositories {
    mavenCentral()
    maven {
        url 'https://m2.dv8tion.net/releases'
    }
}

dependencies {
    implementation 'org.javacord:javacord:3.7.0'
    implementation 'com.sedmelluq:lavaplayer:1.3.78'

    implementation 'org.apache.logging.log4j:log4j-api:2.19.0'
    implementation 'org.apache.logging.log4j:log4j-core:2.19.0'
    implementation 'org.apache.logging.log4j:log4j-slf4j18-impl:2.18.0'
}

jar {
    manifest {
        attributes 'Main-Class': 'com.afkfish.Opal'
    }
}
littlegamer757 commented 1 year ago

Are there any updates on this matter?

keeganwitt commented 1 year ago

@afkfish I just noticed the warning that you're running an Arm image on x86 hardware. I'm wondering if Ant has some native code in it that isn't working right when there's a platform mismatch. Could it be you need to try running the image that matches your hardware?

afkfish commented 1 year ago

I tried that the final solution was to change to arm64 (V8) and it worked just like a charm. But this is due to my lack of knowledge in raspberry pis chipset so I was able to switch to it. Still don't know why it happened on armv7

afkfish commented 1 year ago

So I assume it's an armv7 on x64 problem

keeganwitt commented 1 year ago

The only other issues I found that looked related to this were these

But those were discussions about the wrapper, which shouldn't really be used with this image generally (it makes this image redundant). The Dockerfiles for this project validate the download of the Gradle archives, so I don't see how it could be an incomplete install either.

littlegamer757 commented 1 year ago

Thanks for the quick response. What's the further plan of action here? I kinda need to be able to build armv7 images on x64, should I use a vanilla JDK image and invoke the wrapper directly?

keeganwitt commented 1 year ago

Eclipse Temurin, which is the base image for this image doesn't have a 64 bit arm7 image that I can see (https://hub.docker.com/_/eclipse-temurin). Nor do I see it for the Amazon Corretto images (https://hub.docker.com/_/amazoncorretto). I'm not aware of an image I could use as a base image to offer 64 bit arm7 support. Do you know of one? It's not on Docker's list of officially supported architectures (https://github.com/docker-library/official-images#architectures-other-than-amd64), so I doubt you'd be able to even use a vanilla JDK image and run the wrapper.

Or did I misunderstand the architecture you're trying to target (sorry, I don't really have any experience with ARM)?

littlegamer757 commented 1 year ago

I'm trying to cross-compile an image for my Raspberry Pi (32-bit armv7) on my desktop (64-bit x86). To compile my software, I'm using the arm32v7/gradle:jdk17 image, and the above error occurs upon invoking my gradle task.

I apologize if my previous message caused confusion, I just now realized I wrote "x64" instead of "x86-64".

keeganwitt commented 1 year ago

So I am able to reproduce this on my Windows x86-64 Docker Desktop setup.

> docker run --rm --platform linux/arm/v7 gradle:latest gradle --version
org.gradle.api.internal.classpath.UnknownModuleException: Cannot locate JAR for module 'ant' in distribution directory '/opt/gradle'.
        at org.gradle.api.internal.classpath.DefaultModuleRegistry.loadExternalModule(DefaultModuleRegistry.java:145)
        at org.gradle.api.internal.classpath.DefaultModuleRegistry.getExternalModule(DefaultModuleRegistry.java:133)
        at org.gradle.api.internal.DefaultClassPathProvider.findClassPath(DefaultClassPathProvider.java:71)
        at org.gradle.api.internal.DefaultClassPathRegistry.getClassPath(DefaultClassPathRegistry.java:35)
        at org.gradle.launcher.bootstrap.ProcessBootstrap.runNoExit(ProcessBootstrap.java:48)
        at org.gradle.launcher.bootstrap.ProcessBootstrap.run(ProcessBootstrap.java:37)
        at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
        at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.base/java.lang.reflect.Method.invoke(Method.java:568)
        at org.gradle.launcher.GradleMain.main(GradleMain.java:34)

I thought maybe this was a problem with the QEMU emulation possibly, but it doesn't explain why the wrapper works

> docker run --platform linux/arm/v7 --rm -v "%cd%:/home/gradle/project" -w /home/gradle/project eclipse-temurin:11-jdk ./gradlew --version
Downloading https://services.gradle.org/distributions/gradle-8.1.1-bin.zip
...........10%............20%............30%............40%............50%............60%............70%............80%...........90%............100%

Welcome to Gradle 8.1.1!

Here are the highlights of this release:
 - Stable configuration cache
 - Experimental Kotlin DSL assignment syntax
 - Building with Java 20

For more details see https://docs.gradle.org/8.1.1/release-notes.html

------------------------------------------------------------
Gradle 8.1.1
------------------------------------------------------------

Build time:   2023-04-21 12:31:26 UTC
Revision:     1cf537a851c635c364a4214885f8b9798051175b

Kotlin:       1.8.10
Groovy:       3.0.15
Ant:          Apache Ant(TM) version 1.10.11 compiled on July 10 2021
JVM:          11.0.19 (Eclipse Adoptium 11.0.19+7)
OS:           Linux 5.15.90.1-microsoft-standard-WSL2 arm
keeganwitt commented 1 year ago

It also works when using the same zip I downloaded in this image. This doesn't make sense. Maybe there's an issue in the Docker Library's Jenkins setup. Lemme see if I can ask them about that.

docker run --platform linux/arm/v7 --rm bash -c 'apt-get update && apt-get install -y unzip wget && wget -nv -O gradle.zip https://services.gradle.org/distributions/gradle-8.1.1-bin.zip && unzip gradle.zip && mv gradle-* gradle && ./gradle/bin/gradle --version'
tianon commented 1 year ago

Interesting - I was able to reproduce using QEMU user-mode emulation on my x86 machine, but I fired up a full system-mode emulation VM running "native" arm32v7 and it works fine there, so I'm inclined to think this has something to do with the emulation (which has been known to have issues with Java in the past). :grimacing:

I did an strace on it from my user-mode emulation version, and at some point before the backtrace is printed some part of the startup gets a segfault, but it's not clear exactly what causes it.

Edit: here's the output from my "native" (system-mode emulation) arm32v7 system:

$ docker run -it --rm gradle gradle --version

Welcome to Gradle 8.1.1!

Here are the highlights of this release:
 - Stable configuration cache
 - Experimental Kotlin DSL assignment syntax
 - Building with Java 20

For more details see https://docs.gradle.org/8.1.1/release-notes.html

------------------------------------------------------------
Gradle 8.1.1
------------------------------------------------------------

Build time:   2023-04-21 12:31:26 UTC
Revision:     1cf537a851c635c364a4214885f8b9798051175b

Kotlin:       1.8.10
Groovy:       3.0.15
Ant:          Apache Ant(TM) version 1.10.11 compiled on July 10 2021
JVM:          17.0.7 (Eclipse Adoptium 17.0.7+7)
OS:           Linux 4.19.0-8-armmp-lpae arm
keeganwitt commented 1 year ago

Tianon pointed out I wasn't comparing apples to apples also. I forgot the latest tag is Java 17, and I was comparing that to Java 11. Java 11 appears to work, but 17 was not.

$ docker run --platform linux/arm/v7 --rm gradle:jdk11 gradle --version
Welcome to Gradle 8.1.1!

Here are the highlights of this release:
 - Stable configuration cache
 - Experimental Kotlin DSL assignment syntax
 - Building with Java 20

For more details see https://docs.gradle.org/8.1.1/release-notes.html

------------------------------------------------------------
Gradle 8.1.1
------------------------------------------------------------

Build time:   2023-04-21 12:31:26 UTC
Revision:     1cf537a851c635c364a4214885f8b9798051175b

Kotlin:       1.8.10
Groovy:       3.0.15
Ant:          Apache Ant(TM) version 1.10.11 compiled on July 10 2021
JVM:          11.0.19 (Eclipse Adoptium 11.0.19+7)
OS:           Linux 5.15.90.1-microsoft-standard-WSL2 arm
krasander commented 1 year ago

So, is there a solution for this? I'm also trying to build an image for Raspberry Pi 3B+, but it's failing with the same error as described in the issue. My dockerfile:

FROM arm32v7/gradle:jdk17 AS build
COPY --chown=gradle:gradle . /home/gradle/src
WORKDIR /home/gradle/src
RUN gradle build --no-daemon

FROM arm32v7/eclipse-temurin:17

EXPOSE 8080

RUN mkdir /app

COPY --from=build /home/gradle/src/build/libs/*.war /app/spring-boot-application.war

ENTRYPOINT ["java", "-XX:+UnlockExperimentalVMOptions", "-Djava.security.egd=file:/dev/./urandom","-jar","/app/spring-boot-application.war"]

And the command to build: docker buildx build --platform linux/arm/v7 .

Maybe worth noting that it is a Spring Boot application written in Kotlin.

tianon commented 1 year ago

You could probably cross compile using $TARGETPLATFORM vs $BUILDPLATFORM in your Dockerfile

krasander commented 1 year ago

I'm not sure if this is what you meant, but I changed first line in Dockerfile to use $TARGETPLATFORM like so:

FROM --platform=$TARGETPLATFORM gradle:8-jdk17 AS build
COPY --chown=gradle:gradle . /home/gradle/src
WORKDIR /home/gradle/src
RUN gradle build --no-daemon

FROM arm32v7/eclipse-temurin:17

EXPOSE 8080

RUN mkdir /app

COPY --from=build /home/gradle/src/build/libs/*.war /app/spring-boot-application.war

ENTRYPOINT ["java", "-XX:+UnlockExperimentalVMOptions", "-Djava.security.egd=file:/dev/./urandom","-jar","/app/spring-boot-application.war"]

but the same error still persists. Is there anything else I could try?

tianon commented 1 year ago

Sorry, I meant something more like this:

FROM --platform=$BUILDPLATFORM gradle:8-jdk17 AS build
...
FROM --platform=$TARGETPLATFORM eclipse-temurin:17-jre
COPY --from=build ...
...

Then something like docker buildx build --platform=linux/arm/v7 ... -- in this way, the gradle build step would run on amd64 (or arm64, depending on your host architecture) but the actual end result would be the linux/arm/v7 image you're looking for.

As long as all the build artifacts are platform-independent files (such as compiled JVM bytecode) and do not contain platform specific artifacts such as .so files, this should mostly work fine.

joergrech commented 6 months ago

Is there now a better solution to build linux/arm/v7 systems with gradle and Java 17 (or higher)? Is this still a problem with higher versions of Gradle and Java or just Gradle 7.6 and Java 17?

keeganwitt commented 6 months ago

Just for Gradle 7.6. Once Adoptium added the upstream images, I started building using them, but that means it started with whatever version of Gradle was current at the time.