Open FWiesner opened 4 years ago
when you try a build with the KubernetesClient
for native images, you need to make sure the binary includes support for TLS as well as all character sets. Easiest to do is to add a native-image.properties
in src/main/resources/META-INF/native-image/<groupId>/<artifactId>/
.
Here's an example that I use (includes the config for logback):
Args=\
--initialize-at-build-time=org.slf4j \
--initialize-at-build-time=ch.qos.logback \
-H:+AddAllCharsets \
--enable-https
Hi @FWiesner
I recently implemented a demo project using Kubernetes-Client and building a native image: https://github.com/marcnuri-demo/k8s-cli-java
Everything seems to work fine, could you provide some kind of example with reflection problems so we can implement a "fix".
@manusa please have a look at your project. It logs
Warning: Image 'kubectl-java' is a fallback image that requires a JDK for execution (use --no-fallback to suppress fallback image generation).
native image available at build/graal/kubectl-java (3 MB)
So, your container image will need a JDK. My proposal was to support --no-fallback
to not bundle a JVM in the image
when you build your binaries with --no-fallback
, then the JVM won't be there to help you with reflection. Makes your binary bigger (likely adds 50-100MB), but you can link it statically and don't need anything else in the container image
Ok, thnx for the feedback. I've tested GraalVM only on a couple of occasions and was completely unaware of that. We will look into it.
But internally kubernets-client uses quite a number of model classes based on Jackson:
/com.tietoevry.fss.garo.mainkt
setrlimit to increase file descriptor limit failed, errno 22
[main] ERROR io.fabric8.kubernetes.client.Config - Failed to parse the kubeconfig.
com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Cannot construct instance of `io.fabric8.kubernetes.api.model.Config` (no Creators, like default construct, exist): cannot deserialize from Object value (no delegate- or property-based Creator)
at [Source: (StringReader); line: 1, column: 1]
at com.fasterxml.jackson.databind.DeserializationContext.reportBadDefinition(DeserializationContext.java:1592)
at com.fasterxml.jackson.databind.DeserializationContext.handleMissingInstantiator(DeserializationContext.java:1058)
at com.fasterxml.jackson.databind.deser.BeanDeserializerBase.deserializeFromObjectUsingNonDefault(BeanDeserializerBase.java:1297)
at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserializeFromObject(BeanDeserializer.java:326)
at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:159)
at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:4218)
at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:3214)
at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:3182)
at io.fabric8.kubernetes.client.internal.KubeConfigUtils.parseConfigFromString(KubeConfigUtils.java:45)
at io.fabric8.kubernetes.client.Config.loadFromKubeconfig(Config.java:505)
at io.fabric8.kubernetes.client.Config.tryKubeConfig(Config.java:491)
at io.fabric8.kubernetes.client.Config.autoConfigure(Config.java:230)
at io.fabric8.kubernetes.client.Config.<init>(Config.java:214)
at io.fabric8.kubernetes.client.ConfigBuilder.<init>(ConfigBuilder.java:16)
at io.fabric8.kubernetes.client.ConfigBuilder.<init>(ConfigBuilder.java:13)
at io.fabric8.kubernetes.client.BaseClient.<init>(BaseClient.java:43)
at io.fabric8.kubernetes.client.DefaultKubernetesClient.<init>(DefaultKubernetesClient.java:97)
at com.tietoevry.fss.garo.MainKt.main(Main.kt:12)
Exception in thread "main" java.lang.ExceptionInInitializerError
at com.oracle.svm.core.hub.ClassInitializationInfo.initialize(ClassInitializationInfo.java:290)
at java.lang.Class.ensureInitialized(DynamicHub.java:496)
at com.oracle.svm.core.hub.ClassInitializationInfo.initialize(ClassInitializationInfo.java:235)
at java.lang.Class.ensureInitialized(DynamicHub.java:496)
at com.tietoevry.fss.garo.MainKt.main(Main.kt:13)
Caused by: java.util.MissingResourceException: Resource bundle not found org.apache.cxf.jaxrs.Messages. Register the resource bundle using the option -H:IncludeResourceBundles=org.apache.cxf.jaxrs.Messages.
at com.oracle.svm.core.jdk.LocalizationSupport.getCached(LocalizationSupport.java:66)
at java.util.ResourceBundle.getBundle(ResourceBundle.java:73)
at org.apache.cxf.common.i18n.BundleUtils.getBundle(BundleUtils.java:94)
at org.apache.cxf.jaxrs.AbstractJAXRSFactoryBean.<clinit>(AbstractJAXRSFactoryBean.java:69)
at com.oracle.svm.core.hub.ClassInitializationInfo.invokeClassInitializer(ClassInitializationInfo.java:350)
at com.oracle.svm.core.hub.ClassInitializationInfo.initialize(ClassInitializationInfo.java:270)
... 4 more
won't this become quite painful to handle in a whitelist?
This issue has been automatically marked as stale because it has not had any activity since 90 days. It will be closed if no further activity occurs within 7 days. Thank you for your contributions!
I'd like to propose a new extension, similar to the Helidon integration with GraalVM: https://github.com/oracle/helidon/tree/master/integrations/graal. There you find https://github.com/oracle/helidon/blob/master/integrations/graal/native-image-extension/src/main/java/io/helidon/integrations/graal/nativeimage/extension/HelidonReflectionFeature.java. This class scans (among others) for classes annotated with @io.helidon.common.Reflected
and adds them to the native-image reflection configuration programmatically. I think this would help a lot with listing all the Jackson model classes
@iocanel @oscerd @manusa @metacosm : Could you please share your thoughts on this?
Building native images requires additional processing, among other things, to enable reflection and to replace some of the classes which make use of incompatible or missing dependencies.
The easiest way to do this is by using additional pre-processing before generating the native-image, such as the one performed by the Kubernetes-Client extension in Quarkus.
Achieving the same result just by passing configurations to the GraalVM native-image build task, is really hard. It would also generate JSON files or configurations listing classes (thus the title of this issue).
Personally, to have a better opinion on the topic I need to check how Helidon works around this and if it provides a similar mechanism as Quarkus does.
Same would be applicable for Micronaut, or any other similar framekwork. However, I'm not sure the home for this extension should be this repository.
I don't have a strong opinion on this, but I do believe this extension should be placed somewhere else
not sure why you would want all of this in the microservice frameworks, especially as the operator pattern doesn't require a microservice framework at all. When your service is only depending on the Kubernetes client to interact with the API server, why would you want to use Quarkus, Micronaut, Helidon, etc.
On the other hand native image generation is modularized and all native image configurations are additive. Check the contents of Netty jars for example.
I guess I misunderstood your point (I thought Helidon provided something similar to Quarkus extensions) . Checking now what Helidon does. I didn't know that GraalVM extensions/features were a thing in a standalone fashion. It is poorly documented (at least I haven't found anything about that topic)
This HelidonReflectionFeature does something really similar to what the Quarkus extension does (Jandex is used there, but very similar nonetheless).
The problem with the Netty approach is that the client has many classes, and probably you won't be needing most of them at runtime. On the other hand, after the model split effort, models are more granular now, so maybe these reflection-config.json files wouldn't be that big.
I know this quite old, but are there any news on this front?
To build Kubernetes operators with significantly reduced image size, it would be great if you could natively support GraalVM native images. At the moment it is required to profile the using application in JVM mode with
-agentlib:native-image-agent=config-output-dir=$PWD/src/main/resources/META-INF/native-image/<groupId>/<artifactId>
.Please see details here: https://github.com/oracle/graal/blob/master/substratevm/REFLECTION.md
Thanks