Installing JDK in Docker: Control your tools

Install latest and updated JDK, in Docker OS and patch level of choice, without using package manager `apt`, `deb` or `yum`

When it comes to Dockerizing your applications, optimizing the installation of essential components like the Java Development Kit (JDK) is crucial. The JDK is a fundamental requirement for many Java-based applications and services. In this blog post, we'll walk you through a Dockerfile snippet that simplifies the process of installing the JDK, making your Docker images more efficient and lightweight.

The official Eclipse Temurin Docker images are good but have a challenge for the security-obsessed engineer. We need the latest OS patches, and the latest Java patched version, and control the distribution of the OS, all at the same time. We want to release every month, for as long as the application needs it. But the updates on these images will stop soon after.

Java Feature versions are the future

As Java speeds up its language development, some people, especially developers, will want to develop on the latest.

The people at the forefront of the release will want a "supported" and stable version. The Feature releases for OpenJDK are exactly that middle ground. Well tested, and security patched releases, every 6 months. Like clockwork.

So, whether you agree with this philosophy, or not, you will agree that the version of JDK and JRE that you want to work with, or ship, needs to be in your control.

This is exactly the purpose of this code snippet. To enable a custom distribution, and decouple from the official images, while still using Eclipse Temurin distribution of OpenJDK relevant for you.

Why Efficient JDK Installation Matters

Efficiency in Docker images is essential, as it impacts factors such as image size, deployment speed, and resource utilization. Installing the JDK can be a critical step in your Docker setup, and the approach we'll outline here ensures that you're making the most of your Docker containers.

The Dockerfile Snippet

Let's dive right into the Dockerfile snippet that automates the installation of the JDK. This script ensures that you're using the correct JDK version and optimizes the image's size:

FROM debian:stable-slim

# Tools needed by vscode
# trim down sources.list for faster operation \
RUN \
  export DEBIAN_FRONTEND="noninteractive" \
  && apt-get update \
  # basic tools for developer tooling \
  && apt-get install --no-install-recommends --yes jq wget curl unzip ca-certificates \
  && apt-get autoremove --yes \
  && apt-get clean --yes \
  && rm -rf /var/lib/{apt,dpkg,cache,log}/ \
  && echo "Done installing OS tools"

# setup the Java runtime in the path
ENV JAVA_HOME=/opt/java 
ENV PATH=${JAVA_HOME}/bin:$PATH

# install JDK, ref https://github.com/adoptium/api.adoptium.net/blob/main/docs/cookbook.adoc
RUN \
  echo "Installing JDK" \
  && if [ "$(uname -m)" = "x86_64" ]; then \
      ARCH="x64"; \
    elif [ "$(uname -m)" = "aarch64" ]; then \
      ARCH="aarch64"; \
    else \
      echo "Unsupported architecture"; exit 1; \
    fi \
  && echo "Arch: ${ARCH}" \
  && FEATURE_VERSION=$(curl -s https://api.adoptium.net/v3/info/available_releases | jq '.most_recent_feature_release') \
  && echo "JDK version [${FEATURE_VERSION}]" \
  && OS=linux && IMAGE_TYPE=jdk \
  && API_URL="https://api.adoptium.net/v3/binary/latest/${FEATURE_VERSION}/ga/${OS}/${ARCH}/${IMAGE_TYPE}/hotspot/normal/eclipse" \
  && echo "Downloading from ${API_URL}" \
  # Fetch the archive
  && FETCH_URL=$(curl -s -w %{redirect_url} "${API_URL}") \
  && echo "File fetch url: [${FETCH_URL}]" \
  # download the file
  && FILENAME=$(curl -OLs -w %{filename_effective} "${FETCH_URL}") \
  # Validate the checksum \
  && curl -Ls "${FETCH_URL}.sha256.txt" | sha256sum -c --status \
  && echo "Downloaded successfully as ${FILENAME}" \
  && mkdir -p ${JAVA_HOME} \
  && echo "extract jdk into jvm path (${JAVA_HOME})" \
  && echo "tar -xzvf ${FILENAME} -C ${JAVA_HOME} --strip-components=1" \
  && tar -xzvf ${FILENAME} -C ${JAVA_HOME} --strip-components=1 \
  && rm -f ${FILENAME} \
  && echo "Cleanup jdk distribution files not needed in image" \
  && rm -rf ${JAVA_HOME}/man ${JAVA_HOME}/man \
  && echo "Done"

Explanation of the code

  1. ENV JAVA_HOME=/opt/java

    ENV PATH=${JAVA_HOME}/bin:$PATH

    These lines set up the path and JAVA_HOME environment for the runtime of the container. Do not need any additional OS-level file changes for that.

  2. if [ "$(uname -m)" = "x86_64" ]; then
    ARCH="x64"
    elif [ "$(uname -m)" = "aarch64" ]; then
    ARCH="aarch64"
    else
    echo "Unsupported architecture"
    exit 1
    fi:
    This section determines the architecture of the system by checking the value returned by the uname -m command. If the image is being built for the Intel/AMD (x64) platform, it sets ARCH to "x64," and if it's for the Apple/ARM processors, it sets ARCH to "aarch64."

  3. FEATURE_VERSION=$(curl -s https://api.adoptium.net/v3/info/available_releases | jq '.most_recent_feature_release')
    This command retrieves the most recent feature release version of the JDK using the curl tool and the jq tool to parse the JSON response. the most_recent_feature_release can be changed to most_recent_lts if that is your intent.

  4. FETCH_URL=$(curl -s -w %{redirect_url} "${API_URL}")
    This command fetches the final URL for the JDK binary, including the redirects, if any. The -w %{redirect_url} option is used to get the actual download URL after any redirects.

  5. FILENAME=$(curl -OLs -w %{filename_effective} "${FETCH_URL}")
    This line downloads the JDK binary using the -O option, and saves the file with the name specified in the URL. The -L option follows redirects, though that should no longer be necessary. The filename_effective format specifier in -w is used to get the effective filename after all redirections.

  6. curl -Ls "${FETCH_URL}.sha256.txt" | sha256sum -c --status
    This command ensures that the checksum for the downloaded file matches the one mentioned on the site.

What Makes This Approach Effective

This Dockerfile snippet offers several advantages for your Docker workflow:

  1. Architecture-Agnostic: The script detects the system architecture (x86_64 or aarch64) and installs the appropriate JDK version. This makes it suitable for a wide range of environments.

  2. Latest Feature Release: It automatically fetches the most recent feature release of the JDK, ensuring that you're working with the latest and greatest version.

  3. Checksum Verification: The script checks the integrity of the downloaded file by verifying its checksum, ensuring that your installation is secure.

  4. Size Optimization: Unnecessary files are removed after installation to optimize the size of your Docker image, if relevant, resulting in a smaller footprint.

By using this approach, you can enhance your Docker workflow, save storage space, and ensure that your applications have access to the most secure and correct JDK distribution relevant for your application.

Conclusion

In the world of containerization, flexibility and freedom are paramount. The Dockerfile snippet we've explored in this article exemplifies the power you gain when you're not bound to official Docker images. It's about taking control of your Java Development Kit (JDK) installation and adapting it to your specific needs.

By using this approach, you have the freedom to select the JDK version that best suits your application. You're not constrained by pre-built images that may or may not align with your project's requirements. Whether it's the latest feature release or a specific version, you can choose the right JDK for the job.

Moreover, the script accommodates different architectures, allowing you to deploy your applications on a wide range of hardware without the hassle of creating multiple Dockerfiles. You can seamlessly adapt to x86_64 or aarch64 systems and ensure your Docker containers are compatible across different environments.

In summary, this Dockerfile snippet empowers you to wield the JDK installation process in Docker containers. It's a testament to the versatility of containerization, where you can tailor your environment to your liking, ensuring that your applications run smoothly and efficiently.

Give this approach a try, embrace the freedom it offers, and see how it fits perfectly into your workflow. If you have questions or feedback, we welcome your thoughts in the comments below. It's your Docker journey, and with this newfound power, you're in the driver's seat.

Originally published at: https://blog.mandraketech.in/installing-jdk-in-docker-control-your-tools

Did you find this article valuable?

Support MandrakeTech Blog by becoming a sponsor. Any amount is appreciated!