Java 11 docker alpine

Building Docker images for Java applications

With the rise of the container-first Java frameworks (Micronaut, Quarkus, etc) and the JVM itself evolving to work smoothly with containers, there’s been never a better time to embrace Java in a continuous cloud-native workflow. In this post, we’ll examine some of the practices that can improve and enhance building the Docker images for Java applications that are packaged as JARs.

Building a Docker image

To build a Docker image of a Java application, we need to

  • build a JAR (with a build tool such as Maven or Gradle)
  • copy the JAR to an image that contains the Java runtime
  • expose the necessary port(s), and
  • launch the JAR using the java command

Consider a JAR built by Maven (which dumps the JAR file in /target directory), we can describe the Docker image by the following Dockerfile .

FROM adoptopenjdk:11 WORKDIR /usr/home/app COPY target/*.jar app.jar EXPOSE 8080 CMD ["java", "-jar", "app.jar"] 

The adoptopenjdk:11 image alone is 440MB in size. Say, your application’s JAR is 15MB in size. That’s a 455MB image to run your Java application 😮! This image contains the operating system, the JDK, and the actual application.

Читайте также:  Сортировка массива вставками питон

Use a JRE-based image to provide the runtime

But come to think of it, you don’t need the entire JDK to run your application. Unless your application specifically requires the JDK, a JRE should suffice the purpose. If that is the case, you’re better off using adoptopenjdk/openjdk11:alpine-jre in the Dockerfile .

FROM adoptopenjdk/openjdk11:alpine-jre WORKDIR /usr/home/app COPY target/*.jar app.jar EXPOSE 8080 CMD ["java", "-jar", "app.jar"] 

adoptopenjdk/openjdk11:alpine-jre is only 150 MB in size. Hence the resultant image is about 165 MB, which is around a third the size of the JDK-based image.

  • Use JRE-based images to run the Java applications, unless you specifically need the JDK.
  • Use smaller variants of the base images, if your application doesn’t specifically depend on the functionality available in the full-fledged images. This could save you disk space and speed-up your build pipeline. Linux-based Docker images often come in different variants many of which (like slim and alpine variants) are significantly smaller in size.

Immutability with multi-stage builds

Building a JAR and copying it in a Docker image may work on one machine and not on the other depending on which version of the dependencies are available on their CLASSPATH . This can happen if your CI server builds multiple Java applications. Containers provide consistent environments that can effectively isolate a build and help avoid such problems.

To take advantage of the container environment, identify exactly what needs to be built and copy only those artefacts. To cache and reuse the dependencies, fetch them in a separate step. However, this can bloat your image with dependencies that are required only during the build. This problem can be solved with the multi-stage builds introduced in Docker 17.05. In one stage, you can build the JAR, in the other stage, you can copy the JAR and launch it.

Читайте также:  Динамический язык программирования python

The Dockerfile would look like this for such a workflow.

 FROM maven:3.6.3-jdk-11 as builder  WORKDIR /usr/home/app  COPY pom.xml .  RUN mvn -e -B dependency:resolve  COPY src ./src  RUN mvn -e -B package    FROM adoptopenjdk/openjdk11:alpine-jre  COPY --from=builder /usr/home/app/target/app-*.jar app.jar EXPOSE 8080 CMD ["java", "-jar", "app.jar"] 

Reduce the security footprint with a non-privileged user

Many times, the image you build runs with a privileged ( root ) user. For development purposes, it is fine but it is not recommended in general (see Principle of least privilege for more details). Therefore, you should create a non-root user and provide appropriate privileges to them to run the application and finally switch to that user in the image. For the adoptopenjdk/openjdk11:alpine-jre image, you can do something like this.

 FROM maven:3.6.3-jdk-11 as builder  WORKDIR /usr/home/app  COPY pom.xml .  RUN mvn -e -B dependency:resolve  COPY src ./src  RUN mvn -e -B package    FROM adoptopenjdk/openjdk11:alpine-jre  RUN addgroup -S javausergroup && adduser -S javauser -G javausergroup USER javauser:javausergroup COPY --from=builder /usr/home/app/target/app-*.jar app.jar EXPOSE 8080 CMD ["java", "-jar", "app.jar"] 

The instructions to create a user may differ based on the type of image that you may be using.

Reduce the security footprint with distroless images

Distroless 🤔? Google describes it as a Docker image that contains only your application and its runtime dependencies. Everything non-essential, including package managers, shells, etc, is not available in such an image.

You may wonder why would someone choose to create a distroless image. Here are a few reasons:

  • It reduces the surface for attack.
  • It improves the signal to noise of security scanners like CVE.
  • It reduces the complexity of the inception of an image, both in terms of resources and cost. You ship only what you need.
  • Potential upgrades to the components are less disruptive.

To use a distroless image, edit your Dockerfile as follows.

 FROM maven:3.6.3-jdk-11 as builder  WORKDIR /usr/home/app  COPY pom.xml .  RUN mvn -e -B dependency:resolve  COPY src ./src  RUN mvn -e -B package    FROM gcr.io/distroless/java:11  COPY --from=builder /usr/home/app/target/*.jar app.jar EXPOSE 8080 CMD ["app.jar"] 

Note that instead of adoptopenjdk/openjdk11:alpine-jre , we’re using gcr.io/distroless/java:11 which is the official distroless Docker image for Java provided by Google.

You should specify the ENTRYPOINT or CMD commands in their exec (JSON array) form since the distroless images don’t contain a shell to launch.

For a non-root user, the distroless images provide a nonroot user; you can switch to this user as follows.

 FROM maven:3.6.3-jdk-11 as builder  WORKDIR /usr/home/app  COPY pom.xml .  RUN mvn -e -B dependency:resolve  COPY src ./src  RUN mvn -e -B package    FROM gcr.io/distroless/java:11  COPY --from=builder /usr/home/app/target/*.jar app.jar USER nonroot EXPOSE 8080 CMD ["app.jar"] 

Alternatively, you can use a distroless image that comes with the non-root user set as default.

 FROM maven:3.6.3-jdk-11 as builder  WORKDIR /usr/home/app  COPY pom.xml .  RUN mvn -e -B dependency:resolve  COPY src ./src  RUN mvn -e -B package    FROM gcr.io/distroless/java:11-nonroot  COPY --from=builder /usr/home/app/target/*.jar app.jar EXPOSE 8080 CMD ["app.jar"] 

To search the list of all the available distroless images, you can refer to the distroless Container Registry.

Источник

Saved searches

Use saved searches to filter your results more quickly

You signed in with another tab or window. Reload to refresh your session. You signed out in another tab or window. Reload to refresh your session. You switched accounts on another tab or window. Reload to refresh your session.

Dockerfile for the OpenJDK11 Alpine Linux builds: http://jdk.java.net/11/

License

keckelt/openjdk11-alpine

This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Name already in use

A tag already exists with the provided branch name. Many Git commands accept both tag and branch names, so creating this branch may cause unexpected behavior. Are you sure you want to create this branch?

Sign In Required

Please sign in to use Codespaces.

Launching GitHub Desktop

If nothing happens, download GitHub Desktop and try again.

Launching GitHub Desktop

If nothing happens, download GitHub Desktop and try again.

Launching Xcode

If nothing happens, download Xcode and try again.

Launching Visual Studio Code

Your codespace will open once ready.

There was a problem preparing your codespace, please try again.

Latest commit

Git stats

Files

Failed to load latest commit information.

README.md

The Alpine JDK port is an unsupported release, which is why there were only early access builds. The Dockerfile in this repo uses the last of these builds, but they are no longer hosted by java.net:

The Alpine Linux build previously available on this page was removed as of JDK 11 GA. It’s not production-ready because it hasn’t been tested thoroughly enough to be considered a GA build.

Consider using one of the OpenJDK images instead (e.g. 12-jdk-alpine ) or checkout the Java12 branch.

The JDK port for the Alpine Linux distribution, and in particular the musl C library, is part of the Portola Project.

docker build -t openjdk11-alpine . 

Run interactive ( -i ) to use jshell:

docker run -it openjdk11-alpine 

Источник

Saved searches

Use saved searches to filter your results more quickly

You signed in with another tab or window. Reload to refresh your session. You signed out in another tab or window. Reload to refresh your session. You switched accounts on another tab or window. Reload to refresh your session.

This is image that installed binary file of openjdk 11 on alpine linux.

License

h-r-k-matsumoto/alpine-openjdk-11

This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Name already in use

A tag already exists with the provided branch name. Many Git commands accept both tag and branch names, so creating this branch may cause unexpected behavior. Are you sure you want to create this branch?

Sign In Required

Please sign in to use Codespaces.

Launching GitHub Desktop

If nothing happens, download GitHub Desktop and try again.

Launching GitHub Desktop

If nothing happens, download GitHub Desktop and try again.

Launching Xcode

If nothing happens, download Xcode and try again.

Launching Visual Studio Code

Your codespace will open once ready.

There was a problem preparing your codespace, please try again.

Latest commit

Git stats

Files

Failed to load latest commit information.

README.md

This is image that installed binary file of openjdk 11 on alpine linux.

Please refer to the following for the background that I needed. https://qiita.com/h-r-k-matsumoto/items/1725fc587ce127671560

There are people who still use this docker image.
I recommend using image of alpine tag of AdoptOpenJDK.
It is not musl base, but it is lightweight.

The size of 1 GB has been reduced to about 85 MB. Image size is the result output by the docker images command.

image type jlink size
openjdk:11-jdk not used 1GB
openjdk:11-jdk used 468MB
hirokimatsumoto/alpine-openjdk-11 not used 336MB
hirokimatsumoto/alpine-openjdk-11 used 84.6MB

The docker image of openjdk 11 is published in the official respoitory of docker hub. https://hub.docker.com/_/openjdk/

This image has the following problem.

  • openjdk:11-jdk tag image size is large. There is about 1 GB.
  • Even if you use jlink, image size is 400 MB.
  • Java Flight Recorder does not work in jre tag images.

The file size was confirmed with the following command.

$ sudo docker images |grep jdk docker.io/openjdk 11-jdk f684efd78557 2 weeks ago 979 MB $ 

I confirmed that libjvm.so becomes larger when using jlink.

$ docker run -it --rm openjdk:11-jdk /bin/sh # ls -l /usr/lib/jvm/java-11-openjdk-amd64/lib/server/ total 34944 -rw-r--r-- 1 root root 1322 Jul 27 03:41 Xusage.txt -r--r--r-- 1 root root 18210816 Jul 27 22:22 classes.jsa -rw-r--r-- 1 root root 14440 Jul 27 03:41 libjsig.so -rw-r--r-- 1 root root 17551048 Jul 27 03:41 libjvm.so # jlink \ --module-path /opt/java/jmods \ --compress=2 \ --add-modules java.base,java.logging,jdk.jfr \ --no-header-files \ --no-man-pages \ --output /opt/jdk-11-mini-runtime # ls -l /opt/jdk-11-mini-runtime/lib/server/ total 414452 -rw-r--r-- 1 root root 1322 Aug 14 09:41 Xusage.txt -rw-r--r-- 1 root root 25384 Aug 14 09:41 libjsig.so -rw-r--r-- 1 root root 424362808 Aug 14 09:41 libjvm.so # 

The generated libjvm.so increased to 424 MB. This problem is probably part of the following issue issue. docker-library/openjdk#217

About

This is image that installed binary file of openjdk 11 on alpine linux.

Источник

Оцените статью