Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Graal Native Image build of project created with Micronaut Launch fails #154

Closed
msgilligan opened this issue Jun 30, 2021 · 13 comments · Fixed by #158
Closed

Graal Native Image build of project created with Micronaut Launch fails #154

msgilligan opened this issue Jun 30, 2021 · 13 comments · Fixed by #158

Comments

@msgilligan
Copy link
Contributor

./gradlew nativeImage results in Classes that should be initialized at run time got initialized during image building

Steps to Reproduce

  1. Create a new project using Micronaut Launch - Screenshot
  2. Add minimal YAML configuration for ACME
  3. ./gradlew nativeImage

Expected Behaviour

A Graal Native image (executable should be built)

Actual Behaviour

[application:1774]    classlist:   7,232.96 ms,  1.18 GB
47
[application:1774]        (cap):     895.02 ms,  1.18 GB
48
[application:1774]        setup:   3,089.46 ms,  1.18 GB
49
Error: Classes that should be initialized at run time got initialized during image building:
50
To see how the classes got initialized, use --trace-class-initialization=io.netty.buffer.AbstractPooledDerivedByteBuf,io.netty.buffer.UnpooledDirectByteBuf,io.netty.handler.ssl.ReferenceCountedOpenSslContext,io.netty.util.AbstractReferenceCounted,io.netty.buffer.UnpooledHeapByteBuf,io.netty.buffer.ByteBufUtil,io.netty.handler.ssl.PemPrivateKey,io.netty.buffer.UnpooledUnsafeDirectByteBuf,io.netty.buffer.UnpooledByteBufAllocator$InstrumentedUnpooledUnsafeDirectByteBuf,io.netty.buffer.PooledByteBufAllocator,io.netty.buffer.AbstractReferenceCountedByteBuf,io.netty.buffer.ByteBufAllocator,io.netty.buffer.PooledSlicedByteBuf,io.netty.handler.ssl.PemValue
51
 io.netty.buffer.AbstractPooledDerivedByteBuf the class was requested to be initialized at run time (subtype of io.netty.buffer.AbstractReferenceCountedByteBuf). To see why io.netty.buffer.AbstractPooledDerivedByteBuf got initialized use --trace-class-initialization=io.netty.buffer.AbstractPooledDerivedByteBuf
52
io.netty.buffer.UnpooledDirectByteBuf the class was requested to be initialized at run time (subtype of io.netty.buffer.AbstractReferenceCountedByteBuf). To see why io.netty.buffer.UnpooledDirectByteBuf got initialized use --trace-class-initialization=io.netty.buffer.UnpooledDirectByteBuf
53
[application:1774]     analysis:  71,810.24 ms,  2.32 GB
54
io.netty.handler.ssl.ReferenceCountedOpenSslContext the class was requested to be initialized at run time (from jar:file:///home/runner/.gradle/caches/modules-2/files-2.1/io.micronaut/micronaut-http-netty/2.5.7/f89453037f3ac9c683fa14b350967d637361fa3c/micronaut-http-netty-2.5.7.jar!/META-INF/native-image/io.micronaut/micronaut-http-netty/native-image.properties). To see why io.netty.handler.ssl.ReferenceCountedOpenSslContext got initialized use --trace-class-initialization=io.netty.handler.ssl.ReferenceCountedOpenSslContext
55
io.netty.util.AbstractReferenceCounted the class was requested to be initialized at run time (from jar:file:///home/runner/.gradle/caches/modules-2/files-2.1/io.netty/netty-common/4.1.64.Final/ac71ac92f9181516ce889880501e0ccbde319edc/netty-common-4.1.64.Final.jar!/META-INF/native-image/io.netty/common/native-image.properties). To see why io.netty.util.AbstractReferenceCounted got initialized use --trace-class-initialization=io.netty.util.AbstractReferenceCounted
56
io.netty.buffer.UnpooledHeapByteBuf the class was requested to be initialized at run time (subtype of io.netty.buffer.AbstractReferenceCountedByteBuf). To see why io.netty.buffer.UnpooledHeapByteBuf got initialized use --trace-class-initialization=io.netty.buffer.UnpooledHeapByteBuf
57
io.netty.buffer.ByteBufUtil the class was requested to be initialized at run time (from jar:file:///home/runner/.gradle/caches/modules-2/files-2.1/io.netty/netty-buffer/4.1.64.Final/2376719ecb7fa692e153c7542f3d24b1ef5b116/netty-buffer-4.1.64.Final.jar!/META-INF/native-image/io.netty/buffer/native-image.properties). To see why io.netty.buffer.ByteBufUtil got initialized use --trace-class-initialization=io.netty.buffer.ByteBufUtil
58
io.netty.handler.ssl.PemPrivateKey the class was requested to be initialized at run time (subtype of io.netty.util.AbstractReferenceCounted). To see why io.netty.handler.ssl.PemPrivateKey got initialized use --trace-class-initialization=io.netty.handler.ssl.PemPrivateKey
59
io.netty.buffer.UnpooledUnsafeDirectByteBuf the class was requested to be initialized at run time (subtype of io.netty.buffer.AbstractReferenceCountedByteBuf). To see why io.netty.buffer.UnpooledUnsafeDirectByteBuf got initialized use --trace-class-initialization=io.netty.buffer.UnpooledUnsafeDirectByteBuf
60
io.netty.buffer.UnpooledByteBufAllocator$InstrumentedUnpooledUnsafeDirectByteBuf the class was requested to be initialized at run time (subtype of io.netty.buffer.AbstractReferenceCountedByteBuf). To see why io.netty.buffer.UnpooledByteBufAllocator$InstrumentedUnpooledUnsafeDirectByteBuf got initialized use --trace-class-initialization=io.netty.buffer.UnpooledByteBufAllocator$InstrumentedUnpooledUnsafeDirectByteBuf
61
io.netty.buffer.PooledByteBufAllocator the class was requested to be initialized at run time (from jar:file:///home/runner/.gradle/caches/modules-2/files-2.1/io.netty/netty-buffer/4.1.64.Final/2376719ecb7fa692e153c7542f3d24b1ef5b116/netty-buffer-4.1.64.Final.jar!/META-INF/native-image/io.netty/buffer/native-image.properties). To see why io.netty.buffer.PooledByteBufAllocator got initialized use --trace-class-initialization=io.netty.buffer.PooledByteBufAllocator
62
io.netty.buffer.AbstractReferenceCountedByteBuf the class was requested to be initialized at run time (from jar:file:///home/runner/.gradle/caches/modules-2/files-2.1/io.netty/netty-buffer/4.1.64.Final/2376719ecb7fa692e153c7542f3d24b1ef5b116/netty-buffer-4.1.64.Final.jar!/META-INF/native-image/io.netty/buffer/native-image.properties). To see why io.netty.buffer.AbstractReferenceCountedByteBuf got initialized use --trace-class-initialization=io.netty.buffer.AbstractReferenceCountedByteBuf
63
io.netty.buffer.ByteBufAllocator the class was requested to be initialized at run time (from jar:file:///home/runner/.gradle/caches/modules-2/files-2.1/io.netty/netty-buffer/4.1.64.Final/2376719ecb7fa692e153c7542f3d24b1ef5b116/netty-buffer-4.1.64.Final.jar!/META-INF/native-image/io.netty/buffer/native-image.properties). To see why io.netty.buffer.ByteBufAllocator got initialized use --trace-class-initialization=io.netty.buffer.ByteBufAllocator
64
io.netty.buffer.PooledSlicedByteBuf the class was requested to be initialized at run time (subtype of io.netty.buffer.AbstractReferenceCountedByteBuf). To see why io.netty.buffer.PooledSlicedByteBuf got initialized use --trace-class-initialization=io.netty.buffer.PooledSlicedByteBuf
65
io.netty.handler.ssl.PemValue the class was requested to be initialized at run time (subtype of io.netty.util.AbstractReferenceCounted). To see why io.netty.handler.ssl.PemValue got initialized use --trace-class-initialization=io.netty.handler.ssl.PemValue
66

67
Error: Use -H:+ReportExceptionStackTraces to print stacktrace of underlying exception
68
Error: Image build request failed with exit status 1
69

70
> Task :nativeImage FAILED
71

72
15 actionable tasks: 15 executed
73
FAILURE: Build failed with an exception.

For complete build results in a Github Actions environment, see:
https://github.com/msgilligan/micronaut-acme-sample/actions/runs/987817985

Environment Information

  • Operating System: Ubuntu 20.04 LTS
  • Micronaut Version: 2.5.7
  • JDK Version: GraalVM 21.1.0-java11

Example Application

https://github.com/msgilligan/micronaut-acme-sample

@ilopmar
Copy link
Contributor

ilopmar commented Jul 1, 2021

Adding the following to build.gradle makes possible to create the native image using GraalVM 21.1.0:

nativeImage {
    args = [
        '--initialize-at-run-time=io.netty.handler.ssl.OpenSsl,io.netty.handler.ssl.OpenSslPrivateKeyMethod,io.netty.internal.tcnative.CertificateVerifier,io.netty.internal.tcnative.SSL,io.netty.internal.tcnative.SSLPrivateKeyMethod'
    ]
}

Can you please test it on your side and make sure the execution of the let's encrypt stuff works (sorry but I can't test that part)

@msgilligan
Copy link
Contributor Author

Thanks @ilopmar! I'll add it to both my sample project (to test the build) and to my real project (to test both build and usage) and let you know.

msgilligan added a commit to msgilligan/micronaut-acme-sample that referenced this issue Jul 1, 2021
These were recommended by @ilopmar in a comment
on micronaut-acme Issue 154:
micronaut-projects/micronaut-acme#154 (comment)
@msgilligan
Copy link
Contributor Author

msgilligan added a commit to ConsensusJ/btcproxy that referenced this issue Jul 1, 2021
These were recommended by @ilopmar in a comment
on micronaut-acme Issue 154:
micronaut-projects/micronaut-acme#154 (comment)
@msgilligan
Copy link
Contributor Author

@ilopmar I added the nativeImage args to my actual application (https://github.com/ConsensusJ/btc-proxyd), rebuilt the docker container, replaced the OpenJDK (JIT) container on a test server with the graal/native container and the application still works (I did not actually test creation of a certificate because an existing cert was preserved in a host directory, but I will test that case in the next few days as well)

@ilopmar
Copy link
Contributor

ilopmar commented Jul 2, 2021

@msgilligan Thanks for the update. Once you test the full handshake of renewing the certificate, let me know and I'll include the configuration in this module so it works for everyone without adding the config in the application.

@msgilligan
Copy link
Contributor Author

I'm working on it today. (Ignore the comment I previously posted and deleted -- it was a false alarm)

@msgilligan
Copy link
Contributor Author

Maybe it wasn't a false alarm. I'm seeing the following error with the graalvm version of my docker image, but I have things working with the JIT version:

22:20:46.846 [main] WARN  o.s.acme4j.connector.HttpConnector - Could not read library version
java.lang.NullPointerException: inStream parameter is null
	at java.util.Objects.requireNonNull(Objects.java:246)
	at java.util.Properties.load(Properties.java:406)
	at org.shredzone.acme4j.connector.HttpConnector.<clinit>(HttpConnector.java:40)
	at com.oracle.svm.core.classinitialization.ClassInitializationInfo.invokeClassInitializer(ClassInitializationInfo.java:375)
	at com.oracle.svm.core.classinitialization.ClassInitializationInfo.initialize(ClassInitializationInfo.java:295)
	at org.shredzone.acme4j.provider.AbstractAcmeProvider.createHttpConnector(AbstractAcmeProvider.java:128)
	at org.shredzone.acme4j.provider.AbstractAcmeProvider.connect(AbstractAcmeProvider.java:51)
	at org.shredzone.acme4j.Session.connect(Session.java:213)
	at org.shredzone.acme4j.AccountBuilder.createLogin(AccountBuilder.java:194)
	at io.micronaut.acme.services.AcmeService.doLogin(AcmeService.java:208)
	at io.micronaut.acme.services.AcmeService.orderCertificate(AcmeService.java:165)
	at io.micronaut.acme.background.AcmeCertRefresherTask.renewCertIfNeeded(AcmeCertRefresherTask.java:121)
	at io.micronaut.acme.background.AcmeCertRefresherTask.onStartup(AcmeCertRefresherTask.java:83)
	at io.micronaut.acme.background.$AcmeCertRefresherTaskDefinition$$exec2.invokeInternal(Unknown Source)
	at io.micronaut.context.AbstractExecutableMethod.invoke(AbstractExecutableMethod.java:151)
	at io.micronaut.context.DefaultBeanContext$BeanExecutionHandle.invoke(DefaultBeanContext.java:3412)
	at io.micronaut.aop.chain.AdapterIntroduction.intercept(AdapterIntroduction.java:81)
	at io.micronaut.aop.chain.MethodInterceptorChain.proceed(MethodInterceptorChain.java:96)
	at io.micronaut.acme.background.AcmeCertRefresherTask$ApplicationEventListener$onStartup1$Intercepted.onApplicationEvent(Unknown Source)
	at io.micronaut.context.DefaultBeanContext.notifyEventListeners(DefaultBeanContext.java:1326)
	at io.micronaut.context.DefaultBeanContext.publishEvent(DefaultBeanContext.java:1311)
	at io.micronaut.http.server.netty.NettyHttpServer.fireStartupEvents(NettyHttpServer.java:512)
	at io.micronaut.http.server.netty.NettyHttpServer.start(NettyHttpServer.java:355)
	at io.micronaut.http.server.netty.NettyHttpServer.start(NettyHttpServer.java:114)
	at io.micronaut.runtime.Micronaut.lambda$start$2(Micronaut.java:77)
	at java.util.Optional.ifPresent(Optional.java:183)
	at io.micronaut.runtime.Micronaut.start(Micronaut.java:75)
	at org.consensusj.bitcoin.proxyd.Application.main(Application.java:21)
22:20:54.787 [main] ERROR i.m.acme.services.AcmeService - ACME certificate order failed. Failed to authorize the domain [dns=testnet-btcproxy.consensusj.org]
org.shredzone.acme4j.exception.AcmeException: ACME certificate order failed. Challenge of type tls-alpn-01 failed. With error : Connection refused, for domaindns=testnet-btcproxy.consensusj.org ... Giving up.
	at io.micronaut.acme.services.AcmeService.doChallengeAuthorization(AcmeService.java:416)
	at io.micronaut.acme.services.AcmeService.authorize(AcmeService.java:368)
	at io.micronaut.acme.services.AcmeService.orderCertificate(AcmeService.java:169)
	at io.micronaut.acme.background.AcmeCertRefresherTask.renewCertIfNeeded(AcmeCertRefresherTask.java:121)
	at io.micronaut.acme.background.AcmeCertRefresherTask.onStartup(AcmeCertRefresherTask.java:83)
	at io.micronaut.acme.background.$AcmeCertRefresherTaskDefinition$$exec2.invokeInternal(Unknown Source)
	at io.micronaut.context.AbstractExecutableMethod.invoke(AbstractExecutableMethod.java:151)
	at io.micronaut.context.DefaultBeanContext$BeanExecutionHandle.invoke(DefaultBeanContext.java:3412)
	at io.micronaut.aop.chain.AdapterIntroduction.intercept(AdapterIntroduction.java:81)
	at io.micronaut.aop.chain.MethodInterceptorChain.proceed(MethodInterceptorChain.java:96)
	at io.micronaut.acme.background.AcmeCertRefresherTask$ApplicationEventListener$onStartup1$Intercepted.onApplicationEvent(Unknown Source)
	at io.micronaut.context.DefaultBeanContext.notifyEventListeners(DefaultBeanContext.java:1326)
	at io.micronaut.context.DefaultBeanContext.publishEvent(DefaultBeanContext.java:1311)
	at io.micronaut.http.server.netty.NettyHttpServer.fireStartupEvents(NettyHttpServer.java:512)
	at io.micronaut.http.server.netty.NettyHttpServer.start(NettyHttpServer.java:355)
	at io.micronaut.http.server.netty.NettyHttpServer.start(NettyHttpServer.java:114)
	at io.micronaut.runtime.Micronaut.lambda$start$2(Micronaut.java:77)
	at java.util.Optional.ifPresent(Optional.java:183)
	at io.micronaut.runtime.Micronaut.start(Micronaut.java:75)
	at org.consensusj.bitcoin.proxyd.Application.main(Application.java:21)

@msgilligan
Copy link
Contributor Author

I should also mention that after the certificate is generated, I can switch back to the graalvm version and the server still works.

I also noticed that I can't access the server via Debian's curl, so I opened Issue #156

@ilopmar
Copy link
Contributor

ilopmar commented Jul 12, 2021

The error:

Could not read library version
java.lang.NullPointerException: inStream parameter is null
	at java.util.Objects.requireNonNull(Objects.java:246)
	at java.util.Properties.load(Properties.java:406)
	at org.shredzone.acme4j.connector.HttpConnector.<clinit>(HttpConnector.java:40)
...

Is because the version.properties file https://github.com/shred/acme4j/blob/master/acme4j-client/src/main/java/org/shredzone/acme4j/connector/HttpConnector.java#L38 is not included in the native-image.

Please create the file src/main/resources/META-INF/native-image/your.package/your-application/resource-config.json with the following content:

{
   "resources": [
        { "pattern": "\\Qorg/shredzone/acme4j/version.properties\\E" }
   ]
}

And create the native image again. That config should include that missing version.properties file in the native image.

@msgilligan
Copy link
Contributor Author

msgilligan commented Jul 12, 2021

Yep. That did the trick! I now have two instances running with micronaut-acme one with the native-image container and one with the JIT container. Both were able to successfully complete the ACME process.

Thanks, @ilopmar !

@ilopmar
Copy link
Contributor

ilopmar commented Jul 13, 2021

Awesome! I'll include those changes in this module so it works for everyone.

ilopmar added a commit that referenced this issue Jul 13, 2021
ilopmar added a commit that referenced this issue Jul 13, 2021
* Upgrade to Micronaut 2.5.8

* Upgrade Micronaut Test 2.3.6

* Upgrade Groovy and Spock

* Upgrade Gradle to 7.1.1

* Upgrade acme version to 2.12

* New major version targeting micronaut 3.0

* Use Micronaut nullability annotations

* Switch to Jakarta annotations

* Add support for GraalVM

Fixes #154

* Initialize missing class at run-time for GraalVM support
@ilopmar
Copy link
Contributor

ilopmar commented Jul 13, 2021

@msgilligan I've released 3.0.0-RC1 which is compatible with Micronaut 2.5.x

@msgilligan
Copy link
Contributor Author

Awesome @ilopmar !

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

Successfully merging a pull request may close this issue.

2 participants