Quest for the Holy Graal
Tags: java, linux, docker, performance
Published: 2021-02-19 19:05:01

Statically linked Java images are a superb idea; what's not to love about super small, super fast images that have a low attack surface. However, the reality is far from it. This post is describing some of the ~~fun~~ frustration I've had trying to get something rather basic working: namely [Cloud Logging](https://cloud.google.com/logging). 

# `UnknownHostException` #

The first problem is statically linked Graal Native Images cannot do some things without `libc` set, in this case they can't perform a DNS lookup which results in a `java.net.UnknownHostException`. I'm not going to dwell on how stupid this is and just move on. There are rough instructions available on the [Graal site](https://www.graalvm.org/reference-manual/native-image/StaticImages/) to use `musl` for this but a quick Google came up with something from, erm, [Google Cloud]
(https://cloud.google.com/blog/topics/developers-practitioners/comparing-containerization-methods-buildpacks-jib-and-dockerfile). I bodged this into Helidon and... it didn't build:

```
#11 274.5 [WARNING] Error: Detected a direct/mapped ByteBuffer in the image heap. A direct ByteBuffer has a pointer to unmanaged C memory, and C memory from the image generator is not available at image runtime.A mapped ByteBuffer references a file descriptor, which is no longer open and mapped at run time.   To see how this object got instantiated use --trace-object-instantiation=java.nio.DirectByteBuffer. The object was probably created by a class initializer and is reachable from a static field. You can request class initialization at image runtime by using the option --initialize-at-run-time=<class-name>. Or you can write your own initialization methods and call them explicitly from your main entry point.
#11 274.5 [WARNING] Trace: Object was reached by
#11 274.5 [WARNING]     reading field io.grpc.netty.shaded.io.netty.buffer.PoolChunk.memory of
#11 274.5 [WARNING]             constant io.grpc.netty.shaded.io.netty.buffer.PoolChunk@42d125b0 reached by
...
```

# Googling #

The build problem was due to the embedded Netty within the gRPC libraries. Fortunately the fix for this was pretty easy: [Google have their own library](https://github.com/GoogleCloudPlatform/google-cloud-graalvm-support) for it:

```xml
<dependency>
  <groupId>com.google.cloud</groupId>
  <artifactId>google-cloud-graalvm-support</artifactId>
  <version>0.3.0</version>
</dependency>
```

With this added it built and ran, but now it couldn't find any GCP config:

```
java.lang.IllegalArgumentException: A project ID is required for this service but could not be determined from the builder or the environment.  Please set a project ID using the builder.
        at com.google.common.base.Preconditions.checkArgument(Preconditions.java:142)
        at com.google.cloud.ServiceOptions.<init>(ServiceOptions.java:304)
```

# Confuddling #

Normally, I would have just mounted the volume into the users home, but it appears Graal doesn't have value for `user.home`. I've not digged into this to confirm it, so thought I'd just work around it:

```powershell
docker run --rm -it -p 8080:8080 `
  -e CLOUDSDK_CONFIG=/gcloud `
  -v $Env:APPDATA/gcloud/:/gcloud:ro `
  helidon-quickstart-mp:native
```
Booom! It ran up without any errors.

Alas, there was one final hiccup which was answered by [microsoft/WSL#5324](https://github.com/microsoft/WSL/issues/5324). In a nutshell, if you let Windows go to sleep then the clock in WSL2 drifts. That meant I couldn't find any of my log messages as they were timestamped incorrectly. With WSL restarted we got some logs in Cloud Logging. Hurrah!

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/a3gh7gk6jy2ni8xbtfmu.png)

The resulting image is a somewhat portly 116MB which is 24MB larger than [last time](/dansiviter/java-16-ea-alpine-jlink-vs-graal-243d) and only 11MB off Alpine JLink. I don't think could be explained by the extra libraries but something to worry about another day. However, it starts in around 160ms with `-m 32m` set on the docker container which can't be sniffed at. Regardless of how compelling Graal is, there are lots of bear traps to be aware of. I hope this improves soon.

Now for metrics and tracing...