Skip to content

Github action with low configuration fails and takes longer to run GraalVm native image compilation with V24 #11454

@anandjaisy

Description

@anandjaisy

Describe the Issue

Using Graalvm-CE 24 with micronuat application with below dependencies

plugins {
    id("io.micronaut.application") version "4.5.3"
    id("com.gradleup.shadow") version "8.3.6"
    id("io.micronaut.aot") version "4.5.3"
}

version = "0.1"
group = "#######"

repositories {
    mavenCentral()
}

dependencies {
    annotationProcessor("io.micronaut:micronaut-http-validation")
    annotationProcessor("io.micronaut.openapi:micronaut-openapi")
    annotationProcessor("io.micronaut.serde:micronaut-serde-processor")
    annotationProcessor("io.micronaut.validation:micronaut-validation-processor")

    implementation("io.micronaut.validation:micronaut-validation")
    implementation("jakarta.validation:jakarta.validation-api")
    implementation("io.micronaut.gcp:micronaut-gcp-logging")
    implementation("io.micronaut.serde:micronaut-serde-jackson")
    implementation("com.google.cloud:google-cloud-firestore:3.31.6")
    implementation("io.micronaut:micronaut-management")

    implementation("com.nimbusds:nimbus-jose-jwt:10.3")

    implementation("io.micronaut:micronaut-http-client")
    compileOnly("io.micronaut.openapi:micronaut-openapi-annotations")
    runtimeOnly("ch.qos.logback:logback-classic")

    testImplementation("io.micronaut:micronaut-http-client")
}


application {
    mainClass = "xxx.xxxx.XXXXXX"
}
java {
    sourceCompatibility = JavaVersion.toVersion("24")
    targetCompatibility = JavaVersion.toVersion("24")
}


graalvmNative.toolchainDetection = true

micronaut {
    runtime("netty")
    testRuntime("junit5")
    processing {
        incremental(true)
        annotations("xxxx.xxxxx.*")
    }
    aot {
        optimizeServiceLoading = false
        convertYamlToJava = false
        precomputeOperations = true
        cacheEnvironment = true
        optimizeClassLoading = true
        deduceEnvironment = true
        optimizeNetty = true
        replaceLogbackXml = true
    }
}
tasks.named<io.micronaut.gradle.docker.NativeImageDockerfile>("optimizedDockerfileNative") {
    jdkVersion = "24"
    baseImage = "gcr.io/distroless/base-debian12](http://gcr.io/distroless/base-debian12)"
}

Steps to follow

For optimized native image

- Step 1 - `./gradlew clean`
- Step 2 - `./gradlew build`
- Step 3 - `./gradlew nativeOptimizedCompile` // This step in not required in CI, because docker file has this step
- Step 4 - `./gradlew optimizedDockerfileNative`
- Step 5 - `./gradlew optimizedBuildNativelayersTask`
- Step 6 - `./gradlew optimizeddockerPrepareContext`

The docker file generated is as below

FROM [ghcr.io/graalvm/native-image-community:24-ol9](http://ghcr.io/graalvm/native-image-community:24-ol9) AS graalvm
WORKDIR /home/app
COPY --link layers/libs /home/app/libs
COPY --link layers/app /home/app/
RUN mkdir /home/app/config-dirs
RUN mkdir -p /home/app/config-dirs/generateResourcesConfigFile
RUN mkdir -p /home/app/config-dirs/io.netty\netty-common\4.1.115.Final
RUN mkdir -p /home/app/config-dirs/io.netty\netty-transport\4.1.115.Final
RUN mkdir -p /home/app/config-dirs/ch.qos.logback.contrib\logback-json-classic\0.1.5
RUN mkdir -p /home/app/config-dirs/ch.qos.logback\logback-classic\1.4.9
RUN mkdir -p /home/app/config-dirs/org.apache.httpcomponents\httpclient\4.5.14
RUN mkdir -p /home/app/config-dirs/com.google.protobuf\protobuf-java-util\3.21.12
RUN mkdir -p /home/app/config-dirs/io.grpc\grpc-core\1.69.0
COPY --link config-dirs/generateResourcesConfigFile /home/app/config-dirs/generateResourcesConfigFile
COPY --link config-dirs/io.netty/netty-common/4.1.115.Final /home/app/config-dirs/io.netty/netty-common/4.1.115.Final
COPY --link config-dirs/io.netty/netty-transport/4.1.115.Final /home/app/config-dirs/io.netty/netty-transport/4.1.115.Final
COPY --link config-dirs/ch.qos.logback.contrib/logback-json-classic/0.1.5 /home/app/config-dirs/ch.qos.logback.contrib/logback-json-classic/0.1.5
COPY --link config-dirs/ch.qos.logback/logback-classic/1.4.9 /home/app/config-dirs/ch.qos.logback/logback-classic/1.4.9
COPY --link config-dirs/org.apache.httpcomponents/httpclient/4.5.14 /home/app/config-dirs/org.apache.httpcomponents/httpclient/4.5.14
COPY --link config-dirs/com.google.protobuf/protobuf-java-util/3.21.12 /home/app/config-dirs/com.google.protobuf/protobuf-java-util/3.21.12
COPY --link config-dirs/io.grpc/grpc-core/1.69.0 /home/app/config-dirs/io.grpc/grpc-core/1.69.0
RUN native-image --exclude-config .*/libs/netty-buffer-4.1.119.Final.jar ^/META-INF/native-image/.* --exclude-config .*/libs/netty-common-4.1.119.Final.jar ^/META-INF/native-image/.* --exclude-config .*/libs/netty-transport-4.1.119.Final.jar ^/META-INF/native-image/.* --exclude-config .*/libs/netty-codec-http-4.1.119.Final.jar ^/META-INF/native-image/.* --exclude-config .*/libs/grpc-core-1.71.0.jar ^/META-INF/native-image/.* --exclude-config .*/libs/netty-codec-http2-4.1.119.Final.jar ^/META-INF/native-image/.* --exclude-config .*/libs/netty-handler-4.1.119.Final.jar ^/META-INF/native-image/.* -cp /home/app/libs/*.jar:/home/app/resources:/home/app/application.jar --no-fallback -o application -H:ConfigurationFileDirectories=/home/app/config-dirs/generateResourcesConfigFile,/home/app/config-dirs/io.netty/netty-common/4.1.115.Final,/home/app/config-dirs/io.netty/netty-buffer/4.1.80.Final,/home/app/config-dirs/io.netty/netty-transport/4.1.115.Final,/home/app/config-dirs/io.netty/netty-codec-http/4.1.80.Final,/home/app/config-dirs/io.netty/netty-handler/4.1.80.Final,/home/app/config-dirs/io.netty/netty-codec-http2/4.1.80.Final,/home/app/config-dirs/ch.qos.logback.contrib/logback-json-classic/0.1.5,/home/app/config-dirs/ch.qos.logback/logback-classic/1.4.9,/home/app/config-dirs/org.apache.httpcomponents/httpclient/4.5.14,/home/app/config-dirs/com.google.protobuf/protobuf-java-util/3.21.12,/home/app/config-dirs/io.grpc/grpc-core/1.69.0 xxx.health.MsAddinApplication -H:+StaticExecutableWithDynamicLibC
FROM [gcr.io/distroless/base-debian12](http://artifactory.devops.xxx-aws.com.au/xxx-docker-gcr-remote-prod/distroless/base-debian12)
EXPOSE 8080
COPY --link --from=graalvm /home/app/application /app/application
ENTRYPOINT ["/app/application"]

The Github action to build the native image for Micronaut application, takes too long and Github action keeps failling, with a custom runner as custom-runners-linux with low configuration

#9 [graalvm  2/23] WORKDIR /home/app
#9 DONE 3.4s
#10 [graalvm  3/23] COPY --link layers/libs /home/app/libs
#10 DONE 0.5s
#11 [graalvm  4/23] COPY --link layers/app /home/app/
#11 DONE 0.0s
#12 [graalvm  5/23] COPY --link layers/resources /home/app/resources
#12 DONE 0.0s
#13 [graalvm  6/23] RUN mkdir /home/app/config-dirs
#13 DONE 0.2s
#14 [graalvm  7/23] RUN mkdir -p /home/app/config-dirs/generateResourcesConfigFile
#14 DONE 0.3s
#15 [graalvm  8/23] RUN mkdir -p /home/app/config-dirs/io.netty/netty-common/4.1.115.Final
#15 DONE 0.4s
#16 [graalvm  9/23] RUN mkdir -p /home/app/config-dirs/io.netty/netty-transport/4.1.115.Final
#16 DONE 0.4s
#17 [graalvm 10/23] RUN mkdir -p /home/app/config-dirs/ch.qos.logback.contrib/logback-json-classic/0.1.5
#17 DONE 0.3s
#18 [graalvm 11/23] RUN mkdir -p /home/app/config-dirs/ch.qos.logback/logback-classic/1.4.9
#18 DONE 0.3s
#19 [graalvm 12/23] RUN mkdir -p /home/app/config-dirs/org.apache.httpcomponents/httpclient/4.5.14
#19 DONE 0.3s
#20 [graalvm 13/23] RUN mkdir -p /home/app/config-dirs/com.google.protobuf/protobuf-java-util/3.21.12
#20 DONE 0.3s
#21 [graalvm 14/23] RUN mkdir -p /home/app/config-dirs/io.grpc/grpc-core/1.69.0
#21 DONE 0.4s
#22 [graalvm 15/23] COPY --link config-dirs/generateResourcesConfigFile /home/app/config-dirs/generateResourcesConfigFile
#22 DONE 0.0s
#23 [graalvm 16/23] COPY --link config-dirs/io.netty/netty-common/4.1.115.Final /home/app/config-dirs/io.netty/netty-common/4.1.115.Final
#23 DONE 0.0s
#24 [graalvm 17/23] COPY --link config-dirs/io.netty/netty-transport/4.1.115.Final /home/app/config-dirs/io.netty/netty-transport/4.1.115.Final
#24 DONE 0.0s
#25 [graalvm 18/23] COPY --link config-dirs/ch.qos.logback.contrib/logback-json-classic/0.1.5 /home/app/config-dirs/ch.qos.logback.contrib/logback-json-classic/0.1.5
#25 DONE 0.0s
#26 [graalvm 19/23] COPY --link config-dirs/ch.qos.logback/logback-classic/1.4.9 /home/app/config-dirs/ch.qos.logback/logback-classic/1.4.9
#26 DONE 0.0s
#27 [graalvm 20/23] COPY --link config-dirs/org.apache.httpcomponents/httpclient/4.5.14 /home/app/config-dirs/org.apache.httpcomponents/httpclient/4.5.14
#27 DONE 0.0s
#28 [graalvm 21/23] COPY --link config-dirs/com.google.protobuf/protobuf-java-util/3.21.12 /home/app/config-dirs/com.google.protobuf/protobuf-java-util/3.21.12
#28 DONE 0.0s
#29 [graalvm 22/23] COPY --link config-dirs/io.grpc/grpc-core/1.69.0 /home/app/config-dirs/io.grpc/grpc-core/1.69.0
#29 DONE 0.0s
#30 [graalvm 23/23] RUN native-image --exclude-config .*/libs/netty-buffer-4.1.119.Final.jar ^/META-INF/native-image/.* --exclude-config .*/libs/netty-common-4.1.119.Final.jar ^/META-INF/native-image/.* --exclude-config .*/libs/netty-transport-4.1.119.Final.jar ^/META-INF/native-image/.* --exclude-config .*/libs/netty-codec-http-4.1.119.Final.jar ^/META-INF/native-image/.* --exclude-config .*/libs/grpc-core-1.71.0.jar ^/META-INF/native-image/.* --exclude-config .*/libs/netty-codec-http2-4.1.119.Final.jar ^/META-INF/native-image/.* --exclude-config .*/libs/netty-handler-4.1.119.Final.jar ^/META-INF/native-image/.* -cp /home/app/libs/*.jar:/home/app/resources:/home/app/application.jar --no-fallback -o application -H:ConfigurationFileDirectories=/home/app/config-dirs/generateResourcesConfigFile,/home/app/config-dirs/io.netty/netty-common/4.1.115.Final,/home/app/config-dirs/io.netty/netty-buffer/4.1.80.Final,/home/app/config-dirs/io.netty/netty-transport/4.1.115.Final,/home/app/config-dirs/io.netty/netty-codec-ht
#30 0.251 Warning: The option '-H:+StaticExecutableWithDynamicLibC' is experimental and must be enabled via '-H:+UnlockExperimentalVMOptions' in the future.
#30 0.251 Warning: Please re-evaluate whether any experimental option is required, and either remove or unlock it. The build output lists all active experimental options, including where they come from and possible alternatives. If you think an experimental option should be considered as stable, please file an issue.
#30 11.92 ========================================================================================================================
#30 11.92 GraalVM Native Image: Generating 'application' (static executable)...
#30 11.92 ========================================================================================================================
#30 11.92 For detailed information and explanations on the build output, visit:
#30 11.92 https://github.com/oracle/graal/blob/master/docs/reference-manual/native-image/BuildOutput.md
#30 11.92 ------------------------------------------------------------------------------------------------------------------------
#30 16.75 [1/8] Initializing...                                                                                   (15.2s @ 0.25GB)
#30 16.75  Java version: 24.0.1+9, vendor version: GraalVM CE 24.0.1+9.1
#30 16.75  Graal compiler: optimization level: 2, target machine: x86-64-v3
#30 16.75  C compiler: gcc (redhat, x86_64, 11.5.0)
#30 16.75  Garbage collector: Serial GC (max heap size: 80% of RAM)
#30 16.75  5 user-specific feature(s):
#30 16.75  - com.google.api.gax.grpc.nativeimage.GrpcNettyFeature
#30 16.75  - com.google.api.gax.nativeimage.GoogleJsonClientFeature
#30 16.75  - com.google.api.gax.nativeimage.OpenCensusFeature
#30 16.75  - com.oracle.svm.thirdparty.gson.GsonFeature
#30 16.75  - io.micronaut.core.io.service.ServiceLoaderFeature
#30 16.75 ------------------------------------------------------------------------------------------------------------------------
#30 16.75  1 experimental option(s) unlocked:
#30 16.75  - '-H:+StaticExecutableWithDynamicLibC' (origin(s): command line)
#30 16.75 ------------------------------------------------------------------------------------------------------------------------
#30 16.75 Build resources:
#30 16.75  - 5.70GB of memory (75.6% of 7.55GB system memory, determined at start)
#30 16.75  - 2 thread(s) (100.0% of 2 available processor(s), determined at start)
#30 17.20 Jun 20, 2025 3:10:19 AM com.google.api.gax.nativeimage.NativeImageUtils registerClassForReflection
#30 17.20 WARNING: Failed to find io.grpc.netty.shaded.io.netty.channel.ProtocolNegotiators on the classpath for reflection.
#30 224.5 [2/8] Performing analysis...  [*****]                                                                  (207.0s @ 2.47GB)
#30 224.5    25,526 reachable types   (90.8% of   28,125 total)
#30 224.5    46,669 reachable fields  (61.5% of   75,889 total)
#30 224.7   195,663 reachable methods (65.0% of  301,027 total)
#30 224.7    10,145 types, 2,248 fields, and 54,201 methods registered for reflection
#30 224.7        83 types,    84 fields, and    69 methods registered for JNI access
#30 224.7         4 native libraries: dl, pthread, rt, z
#30 248.7 [3/8] Building universe...                                                                              (24.0s @ 3.21GB)
#30 271.7 [4/8] Parsing methods...      [*****]                                                                   (23.0s @ 1.79GB)
#30 283.4 [5/8] Inlining methods...     [***]                                                                     (11.0s @ 2.25GB)
#30 472.2 [6/8] Compiling methods...    [*************]                                                          (188.8s @ 2.59GB)
#30 519.4 [7/8] Layouting methods...    [*******]                                                                 (47.1s @ 3.24GB)

Using the latest version of GraalVM can resolve many issues.

GraalVM Version

Graalvm 24

Operating System and Version

Linux on Github action

Build Command

Github action

  build-java-app:
    name: Java Build and Test
    runs-on: custom-runners-linux
    steps:
      - uses: actions/checkout@v4

      - name: Setup Graalvm
        uses: graalvm/setup-graalvm@v1
        with:
          java-version: '24'
          distribution: 'graalvm-community'
          github-token: ${{ secrets.GITHUB_TOKEN }}

      - name: Check Java version and vendor
        run:  java -version

      - name: Make gradlew executable
        working-directory: ${{ env.JAVA_API_PATH }}
        run: chmod +x ./gradlew

      - name: Clean Build & Test
        working-directory: ${{ env.JAVA_API_PATH }}
        run: ./gradlew clean build test

      - name: Build Native layers Task
        working-directory: ${{ env.JAVA_API_PATH }}
        run: ./gradlew buildNativelayersTask

      - name: Docker Prepare Context
        working-directory: ${{ env.JAVA_API_PATH }}
        run: ./gradlew dockerPrepareContext

      - name: Docker Prepare Context
        working-directory: ${{ env.JAVA_API_PATH }}
        run: ./gradlew dockerfileNative

      - name: Upload build files
        uses: actions/upload-artifact@v4
        with:
          name: published-java-app
          path: ${{ env.JAVA_BUILD_DIR }}

Then I have a docker build command in another Job as below which takes  the files from above

  dockerBuildPush:
    name: Docker Build & Push
    runs-on: custom-runners-linux
    needs: build-java-app
    defaults:
      run:
        shell: bash
    steps:
      - name: Download build files
        uses: actions/download-artifact@v4
        with:
          name: published-java-app
          path: ${{ env.JAVA_BUILD_DIR }}

      -     name: Set up Docker Buildx
        uses: docker/setup-buildx-action@v3
      -
        name: Build and push
        uses: docker/build-push-action@v6
        with:
          push: false
          tags: user/app:latest

      docker buildx build -f Dockerfile -t `${app-version_numer}` .

Expected Behavior

The build process shouldn't take too long

Actual Behavior

The whole progress takes forever, keeps failing

Github Runner

Run echo "Memory Info:"
#step:6:24)Memory Info:
total used free shared buff/cache available
#step:6:26)Mem: 7.5Gi 669Mi 4.4Gi 62Mi 2.5Gi 6.6Gi
Swap: 0B 0B 0B
Run echo "CPU Info:"
Info:
Architecture: x86_64
CPU op-mode(s): 32-bit, 64-bit
Address sizes: 48 bits physical, 48 bits virtual
Byte Order: Little Endian
CPU(s): 2
On-line CPU(s) list: 0,1
Vendor ID: AuthenticAMD
Model name: AMD EPYC 7R13 Processor
CPU family: 25
Model: 1
Thread(s) per core: 2
Core(s) per socket: 1
Socket(s): 1
Stepping: 1
BogoMIPS: 5299.99
Flags: fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush mmx fxsr sse sse2 ht syscall nx mmxext fxsr_opt pdpe1gb rdtscp lm constant_tsc rep_good nopl nonstop_tsc cpuid extd_apicid aperfmperf tsc_known_freq pni pclmulqdq ssse3 fma cx16 pcid sse4_1 sse4_2 x2apic movbe popcnt aes xsave avx f16c rdrand hypervisor lahf_lm cmp_legacy cr8_legacy abm sse4a misalignsse 3dnowprefetch topoext invpcid_single ssbd ibrs ibpb stibp vmmcall fsgsbase bmi1 avx2 smep bmi2 invpcid rdseed adx smap clflushopt clwb sha_ni xsaveopt xsavec xgetbv1 clzero xsaveerptr rdpru wbnoinvd arat npt nrip_save vaes vpclmulqdq rdpid
Hypervisor vendor: KVM
Virtualization type: full
L1d cache: 32 KiB (1 instance)
L1i cache: 32 KiB (1 instance)
L2 cache: 512 KiB (1 instance)
L3 cache: 4 MiB (1 instance)
NUMA node(s): 1
NUMA node0 CPU(s): 0,1
Vulnerability Gather data sampling: Not affected
Vulnerability Itlb multihit: Not affected
Vulnerability L1tf: Not affected
Vulnerability Mds: Not affected

Metadata

Metadata

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions