GoogleContainerTools / distroless

🥑 Language focused docker images, minus the operating system.
Apache License 2.0
18.98k stars 1.16k forks source link

Java 21 upgrade #1405

Open olivierboudet opened 1 year ago

olivierboudet commented 1 year ago

Hi,

Java 21 is GA, when can we hope to have an updated distroless image ?

thanks

zapodot commented 1 year ago

Looks like we need an image based on Debian 13 (trixie) to support this

theFoxley commented 1 year ago

Why ? There was java17 on debian11 even if it's not the default jre for this version

loosebazooka commented 1 year ago

If there's Java 21 on debian12, we'll add it. Perhaps a question to the debian maintainers?

sansnom commented 1 year ago

For me, it will be available. You can follow the package here: openjdk-21. But will need to wait for a few weeks (took one month for JDK 17). Minimum of 5 days between unstable and testing if I read well and then to stable.

EDIT: has been migrated to testing the 2023/09/26. Next step: testing->stable.

fragaLY commented 1 year ago

Hi,

Is it going to be released?)

loosebazooka commented 1 year ago

Is it available in debian?

fragaLY commented 1 year ago

Looks like we need an image based on Debian 13 (trixie) to support this

So we are going to wait till the 2025?

What is the problem to base on the debian12 (yes, I know support date of Debian 12 till 2028 and JDK21 till 2031)?

dlorenc commented 1 year ago

Shameless pointer, the wolfi-based Chainguard images are distroless as well and we just announced support for jdk 21:

 % syft cgr.dev/chainguard/jdk
 ✔ Loaded image                                                                                                                                                                                                                                                      cgr.dev/chainguard/jdk:latest
 ✔ Parsed image                                                                                                                                                                                                            sha256:c888584441cad85816725ae80ea8d874f623b67eab0240a24d6c62361111b2c4
 ✔ Cataloged packages              [54 packages]
NAME                    VERSION      TYPE
busybox                 1.36.1-r2    apk
ca-certificates-bundle  20230506-r0  apk
fontconfig-config       2.14.2-r2    apk
freetype                2.13.2-r1    apk
glibc                   2.38-r5      apk
glibc-locale-en         2.38-r5      apk
glibc-locale-posix      2.38-r5      apk
java-cacerts            20230106-r1  apk
java-common             0.1-r0       apk
jrt-fs                  21           java-archive
ld-linux                2.38-r5      apk
libbrotlicommon1        1.1.0-r0     apk
libbrotlidec1           1.1.0-r0     apk
libbz2-1                1.0.8-r5     apk
libcrypt1               2.38-r5      apk
libexpat1               2.5.0-r4     apk
libfontconfig1          2.14.2-r2    apk
libgcc                  13.2.0-r3    apk
libpng                  1.6.40-r0    apk
libstdc++               13.2.0-r3    apk
openjdk-21              21.35-r1     apk
openjdk-21-default-jdk  21.35-r1     apk
openjdk-21-default-jvm  21.35-r1     apk
openjdk-21-jre          21.35-r1     apk
openjdk-21-jre-base     21.35-r1     apk
wolfi-baselayout        20230201-r6  apk
zlib                    1.3-r0       apk

There's also a jre build:

% syft cgr.dev/chainguard/jre
 ✔ Pulled image
 ✔ Loaded image                                                                                                                                                                                                                                                      cgr.dev/chainguard/jre:latest
 ✔ Parsed image                                                                                                                                                                                                            sha256:6a519b42584aeaceaf029624f026c5f5157d5fda04c1843b58e13f00df3f71c4
 ✔ Cataloged packages              [45 packages]
NAME                    VERSION      TYPE
ca-certificates-bundle  20230506-r0  apk
fontconfig-config       2.14.2-r2    apk
freetype                2.13.2-r1    apk
glibc                   2.38-r5      apk
glibc-locale-en         2.38-r5      apk
glibc-locale-posix      2.38-r5      apk
java-cacerts            20230106-r1  apk
java-common             0.1-r0       apk
jrt-fs                  21           java-archive
ld-linux                2.38-r5      apk
libbrotlicommon1        1.1.0-r0     apk
libbrotlidec1           1.1.0-r0     apk
libbz2-1                1.0.8-r5     apk
libexpat1               2.5.0-r4     apk
libfontconfig1          2.14.2-r2    apk
libgcc                  13.2.0-r3    apk
libpng                  1.6.40-r0    apk
libstdc++               13.2.0-r3    apk
openjdk-21-default-jvm  21.35-r1     apk
openjdk-21-jre          21.35-r1     apk
openjdk-21-jre-base     21.35-r1     apk
wolfi-baselayout        20230201-r6  apk
zlib                    1.3-r0       apk
loosebazooka commented 1 year ago

Fundamentally it's easiest for us to do what debian does. I know we special case nodejs. And maybe we can do the same for Java -- we just don't right now. The wolfi images (or any other vendor) could fill the gap for you here until we find a Java 21 build.

ding-ma commented 1 year ago

I managed to build Java 21 and Python 3.12 distroless images based off of the debian SID release channel. I created my own debian package fetch script which generates a file similar to debian_archives.bzl.

Since I maintain a fork of this project at work, I can talk to my manager if I can contribute a part of my work back to this project. If I were to contribute back, we would need to modify the debian_package_manager so that it is able to fetch from the SID channel.

loosebazooka commented 1 year ago

I think we're just going to use temurin to do this: #1444

loosebazooka commented 1 year ago

So there should be some java21 images ready for testing. If you are using Java21, we would appreciate some feedback on if these are working for you.

gcr.io/distroless/java21-debian12 (amd64, arm64 and ppc64le). They are based on adoptium temurin java21 which does not seem to currently have an s390x build, so if you're using s390x you might be out of luck.

swi-jared commented 1 year ago

@loosebazooka I'm testing it now, and so far the only hiccup is that I had to upgrade jib which is probably good to do anyway (something about an unsupported image format). If there are any further hiccups I'll add them here.

Thanks!

loosebazooka commented 1 year ago

Glad to hear it's working, @swi-jared you probably should've run into that issue a while ago? Since we moved to oci media types (vs old docker media types) a few months ago.

jochenberger commented 1 year ago

I'm also running tests, looks good so far. :+1:

swi-jared commented 1 year ago

Glad to hear it's working, @swi-jared you probably should've run into that issue a while ago? Since we moved to oci media types (vs old docker media types) a few months ago.

This particular service has been using Temurin 17's base image, so we haven't run into this issue yet.

apostoliska commented 1 year ago

Hi all,

I am testing the java 21 distroless image and find some differences compared to Java 17 related to cacerts.

I am loading a custom trust store to /etc/ssl/certs/java/cacerts (through a volume) but is looks that it is ignored since the relevant symbolic link is missing.

Java 17:

/usr/lib/jvm/java-17-openjdk-amd64/lib/security $ ls -la total 8 drwxr-xr-x 2 root root 4096 Jul 24 09:57 . drwxr-xr-x 1 root root 4096 Jul 24 09:57 .. lrwxrwxrwx 1 root root 43 Jul 24 09:57 blocked.certs -> /etc/java-17-openjdk/security/blocked.certs lrwxrwxrwx 1 root root 27 Jul 24 09:57 cacerts -> /etc/ssl/certs/java/cacerts lrwxrwxrwx 1 root root 44 Jul 24 09:57 default.policy -> /etc/java-17-openjdk/security/default.policy lrwxrwxrwx 1 root root 52 Jul 24 09:57 public_suffix_list.dat -> /etc/java-17-openjdk/security/public_suffix_list.dat

Java 21:

/usr/lib/jvm/temurin21_jdk_amd64/lib/security $ ls -la total 436 drwxr-xr-x 2 root root 4096 Jan 1 2000 . drwxr-xr-x 5 root root 4096 Jan 1 2000 .. -r-xr-xr-x 1 root root 2488 Jan 1 2000 blocked.certs -r-xr-xr-x 1 root root 188019 Jan 1 2000 cacerts -r-xr-xr-x 1 root root 10657 Jan 1 2000 default.policy -r-xr-xr-x 1 root root 229405 Jan 1 2000 public_suffix_list.dat

loosebazooka commented 1 year ago

Yeah looks like temurin ships it's own certs. Probably makes sense to just use those? Or in your script replace those files?

apostoliska commented 1 year ago

Yes, I can try to mount my trust store to _/usr/lib/jvm/temurin21_jdkamd64/lib/security/cacerts.

I think this change should be noted. Using a custom trust store is quite frequent.

loosebazooka commented 1 year ago

Its not clear to me if we should add the symlinks and move the certs over to be consistent with the debian?

jochenberger commented 1 year ago

IMHO, it would be best to stay compatible with previous releases of java*-debian* so this can be a drop-in replacement.

apostoliska commented 1 year ago

Its not clear to me if we should add the symlinks and move the certs over to be consistent with the debian?

I believe having the symlinks would be preferable to simplify the upgrade (at least in my case). After all, openjdk 17 has its own cacerts as well and the symlinks were there.

christopher-cudennec commented 1 year ago

Hey everyone! Since #1444 is already merged: Will you also add gcr.io/distroless/java21-debian12 to the list of available images in your documentation? Thanks, Christopher

loosebazooka commented 1 year ago

Hrmm... Also wondering if we should use temurins shipped trust root or the debian one. Using temurins would simplify our code a bit.

apostoliska commented 1 year ago

I think that gcr.io/distroless/java17-debian12 used the cacerts shipped with Debian.

If that's the case, I believe the same should apply for java 21.

loosebazooka commented 1 year ago

Hr... that is the case, however, the debian java distributions also ship blocked.certs, default.policy and public_suffix_list.dat separately with the JRE install and we will be missing those. Using those could result in some mismatch?

It's looking like we should just use the temurin install as is (easier to maintain, and how temurin generally behaves). Java users will be expected to inject their custom roots directly into the jvm directory as documented in the Java README?

apostoliska commented 1 year ago

There is another issue that I am facing.

I am using the below images:

I mount a custom cacerts to _/usr/lib/jvm/temurin21_jdkamd64/lib/security/cacerts . The application is performing an HTTPS request to a service that its certificated is loaded to the custom cacerts.

The results for each image are the following:

Caused by: javax.net.ssl.SSLHandshakeException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target at java.base/sun.security.ssl.Alert.createSSLException(Unknown Source) at java.base/sun.security.ssl.TransportContext.fatal(Unknown Source) at java.base/sun.security.ssl.TransportContext.fatal(Unknown Source) at java.base/sun.security.ssl.TransportContext.fatal(Unknown Source) at java.base/sun.security.ssl.CertificateMessage$T13CertificateConsumer.checkServerCerts(Unknown Source) at java.base/sun.security.ssl.CertificateMessage$T13CertificateConsumer.onConsumeCertificate(Unknown Source) at java.base/sun.security.ssl.CertificateMessage$T13CertificateConsumer.consume(Unknown Source) at java.base/sun.security.ssl.SSLHandshake.consume(Unknown Source) at java.base/sun.security.ssl.HandshakeContext.dispatch(Unknown Source) at java.base/sun.security.ssl.SSLEngineImpl$DelegatedTask$DelegatedAction.run(Unknown Source) at java.base/sun.security.ssl.SSLEngineImpl$DelegatedTask$DelegatedAction.run(Unknown Source) at java.base/java.security.AccessController.doPrivileged(Unknown Source) at java.base/sun.security.ssl.SSLEngineImpl$DelegatedTask.run(Unknown Source) at io.netty.handler.ssl.SslHandler.runDelegatedTasks(SslHandler.java:1647) at io.netty.handler.ssl.SslHandler.unwrap(SslHandler.java:1493) at io.netty.handler.ssl.SslHandler.decodeJdkCompatible(SslHandler.java:1334) ... 18 common frames omitted Caused by: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target at java.base/sun.security.validator.PKIXValidator.doBuild(Unknown Source) at java.base/sun.security.validator.PKIXValidator.engineValidate(Unknown Source) at java.base/sun.security.validator.Validator.validate(Unknown Source) at java.base/sun.security.ssl.X509TrustManagerImpl.checkTrusted(Unknown Source) at java.base/sun.security.ssl.X509TrustManagerImpl.checkServerTrusted(Unknown Source) ... 30 common frames omitted Caused by: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target at java.base/sun.security.provider.certpath.SunCertPathBuilder.build(Unknown Source) at java.base/sun.security.provider.certpath.SunCertPathBuilder.engineBuild(Unknown Source) at java.base/java.security.cert.CertPathBuilder.build(Unknown Source) ... 35 common frames omitted

The issue is resolved by running the app with the following parameter:

_-Djavax.net.ssl.trustStore=/usr/lib/jvm/temurin21_jdkamd64/lib/security/cacerts

However, adding the parameter should not be required as this is the default cacerts location. Additionally, there is a mismatch in the behavior between nonroot and debug-nonroot images. I find no other difference apart from the image tag.

Any ideas?

ding-ma commented 1 year ago

I'm still working on open sourcing the code. I'll submit PR once it is approved and you guys can decide which version to keep. The builds are based off of debian sid channel so it would be similar to the current java 17 builds.

@apostoliska, debug image contain java jdk whereas non-debug image does not.

I was wondering if we could make a jdk image without busybox. We would have the following:

  1. gcr.io/distroless/java21-debian12:{latest,debug...}
  2. gcr.io/distroless/java21-jdk-debian12:{latest,debug...}

The debug tag will only container busybox.

loosebazooka commented 11 months ago

@apostoliska I think @ding-ma answered your questions, but the detail is that regular images are jres, not jdks. So you need to use the jre path: /usr/lib/jvm/temurin21_jre_amd64/lib/security/cacerts But also maybe the names don't have to be different. Maybe both jre and jvm can just install to the same locaiton.

pstackle commented 11 months ago

I'll add myself as being in support of having separate images with the JDK versus the JRE. I had previously been operating under the assumption that the only difference between the debug and non-debug images was busybox being installed, so was surprised when I learned that the java debug image also used a JDK install instead of a JRE install.

I was wondering if we could make a jdk image without busybox.

My hope would be to also have a JRE image with busybox.

apostoliska commented 11 months ago

Thanks @loosebazooka for the clarification, I see the difference now. However, it is not possible to see the directory structure in a non debug container (no shell). I was under the same assumption with @pstackle that the only difference with debug was busybox as there is no mention of jre/jdk difference in the documentation.

loosebazooka commented 11 months ago

Yeah one option if you ever run into this again is a tool like dive which lets you traverse the file layout. Anyway, I'm going to switch this up to use a fixed directory for both jdk and jre.

loosebazooka commented 11 months ago

alright, so we're going to try to keep cacerts in /etc/ssl/certs/java/cacerts, and symlink to it from the temurin directory. #1459 has the full changes. But basically you should be able to keep your scripts for custom roots without knowing about the installed jvm location

loosebazooka commented 11 months ago

1459 was merged, any chance you could try your old workflows again and see if everything is working as expected (write your custom certs into /etc/ssl/certs/java/cacerts)

apostoliska commented 11 months ago

Verified from my side. Thank you for your efforts.

Booyaabes commented 11 months ago

Tested successfully here too. Thx

Nevertheless, I notice a different behavior between java21-debian12:(latest|nonroot) images, and all others java images. I can run without error this kind of command with non-java21 images:

docker run --rm -v "$(pwd)"/test/CheckCerts.java:/app/CheckCerts.java --entrypoint="java" gcr.io/distroless/java17-debian11:nonroot /app/CheckCerts.java

or even with java21 debug image:

docker run --rm -v "$(pwd)"/test/CheckCerts.java:/app/CheckCerts.java --entrypoint="java" gcr.io/distroless/java21-debian12:debug-nonroot /app/CheckCerts.java

But with gcr.io/distroless/java21-debian12:(latest|nonroot) image, I get the following error:

Error: A JNI error has occurred, please check your installation and try again
Exception in thread "main" java.lang.InternalError: Module jdk.compiler not in boot Layer
        at java.base/sun.launcher.LauncherHelper.loadModuleMainClass(Unknown Source)
        at java.base/sun.launcher.LauncherHelper.checkAndLoadMain(Unknown Source)

Do you have any clue of what's going on ?

pstackle commented 11 months ago

@Booyaabes I believe this is due to the difference that is being discussed above where the debug image has the JDK while the non-debug image only has a JRE (no JDK == no compiler).

from @ding-ma

debug image contain java jdk whereas non-debug image does not.

from @loosebazooka

I think @ding-ma answered your questions, but the detail is that regular images are jres, not jdks.

loosebazooka commented 11 months ago

Hrmm.. I think the implication was that the java17 jre images were able to do this?

Booyaabes commented 11 months ago

Distroless Java 11 & Java 17 images were able to do this, exactly. Should non-debug Java 21 image behaves as non-debug Java 11 & 17 images ? Or non-debug Java 11 & 17 images should not have had the compiler ? What should be the correction ?

swi-jared commented 11 months ago

In the spirit of distroless, I would prefer a smaller footprint and only include the jre. However, if history says it includes the full jdk that's not a deal-breaker. Perhaps there's room for image tags like gcr.io/distroless/{java,jre}21-debian12, where (perhaps) java includes the jdk, and jre includes only the jre?

Just a thought.

loosebazooka commented 11 months ago

I don't think we'll publish a non debug jdk image. Although at some point you should be able to just build them yourself using rules distroless.

jonesetc commented 11 months ago

An issue that I've run into that caused a huge headache is that jspawnhelper is not executable on java21-debian12. This causes all process spawning (ProcessBuilder as the main example) to fail by default. Here's a way to look at it (running on arm64 which effects the paths below)

# bad
> docker run -it --rm --entrypoint ls gcr.io/distroless/java21-debian12:debug -l /usr/lib/jvm/temurin21_jdk_arm64/lib/jspawnhelper
-rw-r--r--    1 root     root         72448 Jan  1  2000 /usr/lib/jvm/temurin21_jdk_arm64/lib/jspawnhelper

# good
> docker run -it --rm --entrypoint ls gcr.io/distroless/java17-debian12:debug -l /usr/lib/jvm/java-17-openjdk-arm64/lib/jspawnhelper
-rwxr-xr-x    1 root     root         67488 Oct 31 23:39 /usr/lib/jvm/java-17-openjdk-arm64/lib/jspawnhelper

to reproduce:

class HelloLs { public static void main(String[] args) throws Exception { new ProcessBuilder("ls").inheritIO().start().waitFor(); } }

- compile with java 17 (so you can try on both versions) `javac hello-ls.java`
- run with java 17 image to see it work
```bash
> docker run --rm -it -v "$PWD/HelloLs.class:/HelloLs.class" --entrypoint java gcr.io/distroless/java17-debian12:debug HelloLs
HelloLs.class  boot           dev            home           proc           run            sys            usr
bin            busybox        etc            lib            root           sbin           tmp            var
loosebazooka commented 11 months ago

We can make jspawnhelper executable

loosebazooka commented 11 months ago

I haven't had a chance to figure out why @Booyaabes issue is popping up though

Glup3 commented 9 months ago

hey, are there any updates on this?

loosebazooka commented 9 months ago

I think I might need to use something different than the bazel pkg_tar rule. I'll throw something together but it'll be brittle if the directory layout or executable permissions change on the jre archive.

jhawkins1 commented 6 months ago

What is the ETA of publishing Java 21 Debian 12 Image as one of the supported Distroless Images? Do you need additional testers? Seems like this was moving along, but stalled?

loosebazooka commented 6 months ago

I mean it's probably good to go now. I'm not super fond of how I'm unpacking the tar in https://github.com/GoogleContainerTools/distroless/blob/main/private/remote/temurin_archive.bzl but I guess that's just an implementation detail.

markallanson commented 6 months ago

I have some feedback on the Java21 images.

In the Java17 images, config was symlinked from a common location in /etc/java-17-openjdk - a common directory without any architecture specifications.

This made it easy to build derived base images with tweaked config.

The currently published java21 images don't symlink in the config, which makes things a bit more annoying to deal with.

loosebazooka commented 6 months ago

@markallanson can you provide a little more detail? We can probably fix this pretty easily. We're just going to end up organizing a temurin package like a debian java release.