Skip to content

Add GraalVM native image support for Fabric8 autoconfig module#2247

Open
kamalcis wants to merge 4 commits into
spring-cloud:mainfrom
kamalcis:fix/graalvm-aot-sck-support
Open

Add GraalVM native image support for Fabric8 autoconfig module#2247
kamalcis wants to merge 4 commits into
spring-cloud:mainfrom
kamalcis:fix/graalvm-aot-sck-support

Conversation

@kamalcis

@kamalcis kamalcis commented Jun 7, 2026

Copy link
Copy Markdown

Problem

Spring Cloud Kubernetes Fabric8 autoconfig module does not support
GraalVM native image compilation. The README explicitly states native
images are unsupported. Native builds fail at runtime with:

java.lang.ClassNotFoundException:
io.fabric8.kubernetes.client.impl.KubernetesClientImpl

Closes #1350

Testing Environment

Tested on:

  • GraalVM CE 25.0.2
  • Spring Boot 4.1.0-SNAPSHOT
  • Spring Cloud Kubernetes 5.0.2-SNAPSHOT
  • Kubernetes 1.34.1 (live kubeadm cluster)

Reproduce

  • Cloned the sck library from https://github.com/spring-cloud/spring-cloud-kubernetes
  • Installed the sck library to local repo.
    cd spring-cloud-kubernetes> ./mvnw clean install -DskipTests -Dspring-boot.build-image.skip=true
  • The link of app repo I used to test: https://github.com/kamalcis/graalvm-sck-app
  • Build the app. cd graalvm-sck-app> ./mvnw -Pnative native:compile -DskipTests
  • Now the Aot Binary is ready in the target folder. (Build outside because container does not refer local repo)
  • Used Podman to build the docker image. ( Docker just copied the aot binary file into working directory)
  • Deploy the Kubernetes Objects ( Deployment, Service, Secret, Configmap, Service Account, Role, Rolebinding) using
    https://github.com/kamalcis/graalvm-sck-app/blob/main/k8s.yaml ( kubectl apply -f k8s.yaml)
  • Once Kubernetes is up and running set the image to deployment that has been built by podman, make sure rollout restart .
  • This is important to keep the same name for the app, configmap, secret name e.g. (In this case graalvm-sck-app)
  • Expect to see no error if PR is merged. Before merge ClassNotFoundException should be thrown in kubernetes

Solution

Add Fabric8RuntimeHints implementing RuntimeHintsRegistrar to register:

  • Reflection hints for KubernetesClientImpl, KubernetesClientBuilder,
    and Config
  • Reflection hint for Fabric8ProfileEnvironmentPostProcessor
  • Resource hints for Kubernetes service account and kubeconfig files

Note

User applications must set spring.main.cloud-platform=kubernetes
in their configuration to enable SCK auto-configuration in
native image environments. Auto-detection of the Kubernetes
platform is not yet supported in native images and is a
separate concern from this PR.

Results on Merge:
Deployed the user application image ( containing the SCK library ) into Kubeadm cluster. Pods started successfully, logs were clean, and SCK auto-configuration loaded correctly at runtime. Pods start instantly, logs are clean, and SCK auto-configuration loads correctly at runtime.

@kamalcis kamalcis force-pushed the fix/graalvm-aot-sck-support branch from d272d9d to 9b6a0eb Compare June 7, 2026 21:24
@kamalcis kamalcis mentioned this pull request Jun 8, 2026
@kamalcis kamalcis marked this pull request as draft June 20, 2026 09:22
@kamalcis

kamalcis commented Jun 21, 2026

Copy link
Copy Markdown
Author
Controller kub-result

Validated end-to-end on a live kubeadm cluster (Kubernetes 1.34.1, GraalVM CE 25.0.2, Spring Cloud Kubernetes 5.0.2-SNAPSHOT, Spring Boot 4.1.0-SNAPSHOT). Called the REST endpoint from within the cluster and received the expected response — both ConfigMap and Secret values were successfully injected into the application via Spring Cloud Kubernetes at native image runtime, as demonstrated in the screenshot above.

kamalcis added 4 commits June 22, 2026 14:04
Signed-off-by: Abu Hena Mostafa Kamal <kamalcis@gmail.com>
Add RuntimeHintsRegistrar and @ConstructorBinding fixes to enable
Spring Cloud Kubernetes to run as a GraalVM native image.

Changes:
- Add Fabric8RuntimeHints implementing RuntimeHintsRegistrar with
  reflection hints for Fabric8 client classes (KubernetesClientImpl,
  KubernetesClientBuilder, Config, ConfigBuilder), Kubernetes resources
  (ConfigMap, ConfigMapList, Secret, SecretList, ObjectMeta), and
  config properties (ConfigMapConfigProperties, SecretsConfigProperties)
- Remove @ImportRuntimeHints(Fabric8RuntimeHints.class) from
  Fabric8AutoConfiguration and register Fabric8RuntimeHints via
  META-INF/spring/aot.factories instead for proper AOT processing
- Add @ConstructorBinding to ConfigMapConfigProperties constructor to
  ensure correct binding behavior in native AOT mode
- Add @ConstructorBinding to SecretsConfigProperties constructor for
  the same reason
- Register KubernetesConfigDataLoader in spring.factories to fix silent
  config data loading failure in native AOT mode

Validated on GraalVM CE 25.0.2 with Spring Boot 4.1.0-SNAPSHOT and
Kubernetes 1.34.1 on a live kubeadm cluster (93ms startup time).

Fixes: native image startup failure with NoSuchMethodException for
ConfigMapConfigProperties and SecretsConfigProperties, and silent
config data load skip in AOT mode.

Signed-off-by: Abu Hena Mostafa Kamal <kamalcis@gmail.com>
Remove @ConstructorBinding from ConfigMapConfigProperties and SecretsConfigProperties as it is not needed in this case.

Register both classes in Fabric8RuntimeHints with INVOKE_DECLARED_CONSTRUCTORS
to ensure GraalVM can construct them at runtime.

Add unit tests for Fabric8RuntimeHints covering reflection hint registrations
for Fabric8 client classes, Kubernetes API resources, and config properties.

Signed-off-by: Abu Hena Mostafa Kamal <kamalcis@gmail.com>
Spring Boot AOT engine automatically processes ConfigDataLoader
registrations from META-INF/spring/ imports file, making the
spring.factories entry unnecessary and redundant.

Signed-off-by: Abu Hena Mostafa Kamal <kamalcis@gmail.com>
@kamalcis kamalcis force-pushed the fix/graalvm-aot-sck-support branch from 607b9d6 to 4dd0f5a Compare June 22, 2026 08:09
@kamalcis kamalcis marked this pull request as ready for review June 22, 2026 10:56
@kamalcis

kamalcis commented Jun 22, 2026

Copy link
Copy Markdown
Author

Hi @ryanjbaxter, I hope you're well!
I have completed the end-to-end validation of this PR. Now ConfigMap, Secret, and environment variable injection are all working correctly in the native image as shown in the attached screenshots.
Would you be able to take a look at the implementation when you get a chance? I would love to get your feedback and am keen to collaborate further on this. Happy to make any adjustments you suggest.
Thank you for your time!

@ryanjbaxter

Copy link
Copy Markdown
Contributor

Thanks! I think this would be a good feature for our 2026 release which will be sometime towards the end of the year

@kamalcis

Copy link
Copy Markdown
Author

Thanks! I think this would be a good feature for our 2026 release which will be sometime towards the end of the year

Thank you so much for triaging this and adding it to the 2026.0.0-M1 milestone. Please let me know if there's anything you'd like me to address. Looking forward to collaborating on this!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

Status: Todo

Development

Successfully merging this pull request may close these issues.

Spring Native support

3 participants