From fe4b58ebb99c3b0494c9d2bb0edd46568ed34f75 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Champeau?= Date: Tue, 22 Oct 2024 13:39:23 +0200 Subject: [PATCH] Fix graalvm download url (#1041) * Fix GraalVM download URL This is the Gradle's counterpart to https://github.com/micronaut-projects/micronaut-maven-plugin/pull/1219 The fix is slightly different since we already had a way to define the base path, but not the full path. Now the plugin provides the option to completely override the GraalVM download URL, in case the derivation from the JDK and arch properties is not good enough. * Update Amazon Linux base image --- .../gradle/docker/NativeImageDockerfile.java | 40 ++++++++++++++++--- .../docker/DockerNativeFunctionalTest.groovy | 14 ++++--- gradle/libs.versions.toml | 1 + minimal-plugin/build.gradle | 1 + 4 files changed, 45 insertions(+), 11 deletions(-) diff --git a/docker-plugin/src/main/java/io/micronaut/gradle/docker/NativeImageDockerfile.java b/docker-plugin/src/main/java/io/micronaut/gradle/docker/NativeImageDockerfile.java index 541bd4bf..99557dec 100644 --- a/docker-plugin/src/main/java/io/micronaut/gradle/docker/NativeImageDockerfile.java +++ b/docker-plugin/src/main/java/io/micronaut/gradle/docker/NativeImageDockerfile.java @@ -57,6 +57,8 @@ */ public abstract class NativeImageDockerfile extends Dockerfile implements DockerBuildOptions { + public static final String AMAZON_LINUX_BASE_IMAGE = "public.ecr.aws/amazonlinux/amazonlinux:" + DefaultVersions.AMAZONLINUX; + private static final List SUPPORTED_JAVA_VERSIONS = List.of( // keep those in descending order 21, @@ -65,6 +67,11 @@ public abstract class NativeImageDockerfile extends Dockerfile implements Docker private static final String ARM_ARCH = "aarch64"; private static final String X86_64_ARCH = "x64"; + private static final String GRAALVM_DOWNLOAD_BASE_URL = "https://download.oracle.com/graalvm"; + private static final String GRAALVM_DISTRIBUTION_PATH = "/%s/%s/graalvm-jdk-%s_linux-%s_bin.tar.gz"; + //Latest version of GraalVM for JDK 17 available under the GraalVM Free Terms and Conditions (GFTC) licence + private static final String GRAALVM_FOR_JDK17 = "17.0.12"; + /** * @return The JDK version to use with native image. Defaults to the toolchain version, or the current Java version. */ @@ -132,6 +139,17 @@ public abstract class NativeImageDockerfile extends Dockerfile implements Docker @Optional public abstract Property getGraalReleasesUrl(); + /** + * Return the full URL of the GraalVM distribution to use. By default, it + * uses the base URL from {@link #getGraalReleasesUrl()} and searches in a + * location known to exist when the plugin was built. + * + * @return the URL of the GraalVM distribution to use + */ + @Input + @Optional + public abstract Property getGraalVMDistributionUrl(); + @Input @Override public abstract Property getTargetWorkingDirectory(); @@ -188,6 +206,17 @@ public NativeImageDockerfile() { getTargetWorkingDirectory().convention(DEFAULT_WORKING_DIR); getExposedPorts().convention(Collections.singletonList(8080)); getGraalImage().convention(getJdkVersion().map(NativeImageDockerfile::toGraalVMBaseImageName)); + getGraalReleasesUrl().convention(GRAALVM_DOWNLOAD_BASE_URL); + var distributionPath = getJdkVersion().zip(getGraalArch(), (jdk, arch) -> { + if ("17".equals(jdk)) { + getLogger().warn("You are using the latest release of GraalVM available under the GraalVM Free Terms and Conditions (GFTC) licence (" + GRAALVM_FOR_JDK17 + "). Consider upgrading to Java 21."); + return GRAALVM_DISTRIBUTION_PATH.formatted(jdk, "archive", GRAALVM_FOR_JDK17, arch); + } + return GRAALVM_DISTRIBUTION_PATH.formatted(jdk, "latest", jdk, arch); + }); + getGraalVMDistributionUrl().convention( + getGraalReleasesUrl().zip(distributionPath, (base, path) -> base + path) + ); getNativeImageOptions().convention(project .getTasks() .named(NativeImagePlugin.NATIVE_COMPILE_TASK_NAME, BuildNativeImageTask.class) @@ -431,13 +460,13 @@ private void setupInstructions(List additionalInstructions) { if (buildStrategy == DockerBuildStrategy.LAMBDA) { from(new From(imageResolver.resolve()).withStage("graalvm")); environmentVariable("LANG", "en_US.UTF-8"); - runCommand("yum install -y gcc gcc-c++ glibc-devel glibc-langpack-en curl-minimal bash zlib zlib-devel zlib-static zip tar gzip"); + runCommand("dnf update -y && dnf install -y gcc glibc-devel zlib-devel libstdc++-static tar && dnf clean all && rm -rf /var/cache/dnf"); String jdkVersion = getJdkVersion().get(); String graalArch = getGraalArch().get(); // https://download.oracle.com/graalvm/17/latest/graalvm-jdk-17_linux-aarch64_bin.tar.gz String fileName = "graalvm-jdk-" + jdkVersion + "_linux-" + graalArch + "_bin.tar.gz"; - String releasesUrl = getGraalReleasesUrl().getOrElse("https://download.oracle.com/graalvm"); - runCommand("curl -4 -L " + releasesUrl + "/" + jdkVersion + "/latest/" + fileName + " -o /tmp/" + fileName); + String graalvmDistributionUrl = getGraalVMDistributionUrl().get(); + runCommand("curl -4 -L " + graalvmDistributionUrl + " -o /tmp/" + fileName); runCommand("tar -zxf /tmp/" + fileName + " -C /tmp && ls -d /tmp/graalvm-jdk-"+ jdkVersion + "* | grep -v \"tar.gz\" | xargs -I_ mv _ /usr/lib/graalvm"); runCommand("rm -rf /tmp/*"); if (toMajorVersion(jdkVersion) < 21) { @@ -448,6 +477,7 @@ private void setupInstructions(List additionalInstructions) { defaultCommand("/usr/lib/graalvm/bin/native-image"); environmentVariable("PATH", "/usr/lib/graalvm/bin:${PATH}"); from(new From("graalvm").withStage("builder")); + runCommand("dnf update -y && dnf install -y zip && dnf clean all"); } else { from(new From(getGraalImage().get()).withStage("graalvm")); } @@ -504,7 +534,7 @@ private void setupInstructions(List additionalInstructions) { case LAMBDA: from(baseImageProvider); workingDir("/function"); - runCommand("yum install -y zip"); + runCommand("dnf install -y zip"); copyFile(new CopyFile(workDir + "/application", "/function/func").withStage("builder")); String funcCmd = String.join(" ", getArgs().map(strings -> { List newList = new ArrayList<>(strings.size() + 1); @@ -744,7 +774,7 @@ private String resolve() { String baseImage = getBaseImage().getOrNull(); if (strategy == DockerBuildStrategy.LAMBDA && baseImage == null) { - baseImage = "amazonlinux:2023"; + baseImage = AMAZON_LINUX_BASE_IMAGE; } else if (baseImage == null) { baseImage = "cgr.dev/chainguard/wolfi-base:latest"; } diff --git a/functional-tests/src/test/groovy/io/micronaut/gradle/docker/DockerNativeFunctionalTest.groovy b/functional-tests/src/test/groovy/io/micronaut/gradle/docker/DockerNativeFunctionalTest.groovy index d2138b4f..df38a0c1 100644 --- a/functional-tests/src/test/groovy/io/micronaut/gradle/docker/DockerNativeFunctionalTest.groovy +++ b/functional-tests/src/test/groovy/io/micronaut/gradle/docker/DockerNativeFunctionalTest.groovy @@ -17,7 +17,7 @@ class DockerNativeFunctionalTest extends AbstractEagerConfiguringFunctionalTest @Lazy String defaultDockerFrom = "FROM $defaultBaseImage" - def "test build docker native image for runtime #runtime"() { + def "test build docker native image for runtime #runtime (JDK #jdk)"() { given: settingsFile << "rootProject.name = 'hello-world'" println settingsFile.text @@ -45,6 +45,7 @@ class DockerNativeFunctionalTest extends AbstractEagerConfiguringFunctionalTest dockerfileNative { args('-Xmx64m') instruction \"\"\"HEALTHCHECK CMD curl -s localhost:8090/health | grep '"status":"UP"'\"\"\" + jdkVersion = "$jdk" } graalvmNative.binaries.all { @@ -101,10 +102,11 @@ micronaut: task.outcome == TaskOutcome.SUCCESS where: - runtime | nativeImage - "netty" | "FROM ghcr.io/graalvm/native-image-community:17-ol${DefaultVersions.ORACLELINUX}" - "lambda_provided" | 'FROM amazonlinux:2023 AS graalvm' - "jetty" | "FROM ghcr.io/graalvm/native-image-community:17-ol${DefaultVersions.ORACLELINUX}" + runtime | jdk | nativeImage + "netty" | 17 | "FROM ghcr.io/graalvm/native-image-community:17-ol${DefaultVersions.ORACLELINUX}" + "lambda_provided" | 17 | "FROM public.ecr.aws/amazonlinux/amazonlinux:${DefaultVersions.AMAZONLINUX} AS graalvm" + "lambda_provided" | 21 | "FROM public.ecr.aws/amazonlinux/amazonlinux:${DefaultVersions.AMAZONLINUX} AS graalvm" + "jetty" | 17 | "FROM ghcr.io/graalvm/native-image-community:17-ol${DefaultVersions.ORACLELINUX}" } void 'build mostly static native images when using distroless docker image for runtime=#runtime'() { @@ -649,7 +651,7 @@ micronaut: build "dockerfileNative" def dockerFile = normalizeLineEndings(file("build/docker/native-main/DockerfileNative").text) dockerFile = dockerFile.replaceAll("[0-9]\\.[0-9]+\\.[0-9]+", "4.0.0") - .trim() + .trim() then: dockerFile == """ diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index b17a8cf1..5f6dc97f 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -7,6 +7,7 @@ shadow = "8.1.1" groovy = "3.0.22" spock = "2.3-groovy-3.0" oraclelinux = "9" +amazonlinux = "2023-minimal" graalvmPlugin = "0.10.3" mockserver = "5.15.0" log4j2 = "2.24.1" diff --git a/minimal-plugin/build.gradle b/minimal-plugin/build.gradle index c509c357..81dd166e 100644 --- a/minimal-plugin/build.gradle +++ b/minimal-plugin/build.gradle @@ -28,6 +28,7 @@ var writeVersions = tasks.register("writeDefaultVersions", WriteVersions) { versions.put('test-resources', libs.versions.micronaut.testresources) versions.put('openapi', libs.versions.micronaut.openapi) versions.put('oraclelinux', libs.versions.oraclelinux) + versions.put('amazonlinux', libs.versions.amazonlinux) packageName = 'io.micronaut.gradle' }