Choosing Java Docker Base Images & JDKs: Optimize Shutdown, Memory, and DNS

This article explains how to select the proper base image (Alpine or Debian), decide between JDK and JRE, choose Oracle or OpenJDK, handle graceful shutdown signals in Docker, configure memory limits across JDK versions, manage DNS caching, and optionally compile Java applications to native binaries with GraalVM.

Open Source Linux
Open Source Linux
Open Source Linux
Choosing Java Docker Base Images & JDKs: Optimize Shutdown, Memory, and DNS

System Selection

For the most basic underlying images we usually have three choices: Alpine, Debian, and CentOS. CentOS is familiar to many operators but its stable releases are discontinued, making its stability uncertain.

Excluding CentOS, we discuss Alpine vs Debian. Alpine wins on image size, but it uses the musl C library, which can cause compatibility issues for applications that deeply depend on glibc. In practice, the only glibc‑related problem encountered was a font‑related bug in the OpenJDK package on Alpine.

If your application heavily depends on glibc (e.g., contains JNI code), choose a Debian‑based image; otherwise, Alpine is fine for size concerns. The author prefers Debian‑based images.

JDK or JRE

Many people do not distinguish JDK from JRE. The definitions are:

JDK: Java Development Kit

JRE: Java Runtime Environment

The JDK includes development tools such as javac, jps, jstack, and jmap, and it bundles the JRE. The JRE only contains the runtime classes and commands, so it is smaller and lighter.

If you only need to run a jar, JRE is sufficient; if you need debugging capabilities, use the JDK. The author usually uses the JDK as the base image to avoid having to mount additional toolchains for production troubleshooting, unless image size is a strict concern.

JDK Selection

Oracle JDK vs OpenJDK

The choice depends on whether the code uses Oracle‑specific private APIs (e.g., classes under com.sun.*). If such APIs are used, only Oracle JDK can provide them.

Often these private APIs are not truly required and can be replaced with standard libraries (e.g., Apache Commons). Unused imports can be cleaned up with IDE shortcuts ( Option+Command+L to format, Control+Option+O to optimize imports).

Oracle JDK Rebuild Issue

When Oracle JDK must be used, download the tarball and build a custom Docker image, keeping the original package for future rebuilds because Oracle JDK does not provide historical versions.

OpenJDK Distributions

Popular OpenJDK‑based images include AdoptOpenJDK, Amazon Corretto, IBM Semeru Runtime, Azul Zulu, and Liberica JDK. AdoptOpenJDK (now Eclipse Adoptium) offers Alpine, Ubuntu, and CentOS variants. The author prefers AdoptOpenJDK (eclipse‑temurin) for community support.

JVM Selection

Any JVM that complies with the Java specification can be used in production. Common implementations are HotSpot, OpenJ9, TaobaoVM, LiquidVM, and Azul Zing. HotSpot is the most widely used; OpenJ9 offers faster startup and lower memory usage for containerized workloads.

Recommendation: use HotSpot if you are unfamiliar with JVM tuning; consider OpenJ9 for advanced tuning.

Signal Transmission (Graceful Shutdown)

When a container stops, the orchestrator sends a termination signal to PID 1. If the Java process receives the signal, frameworks like Spring Boot perform graceful shutdown. If the signal is not forwarded, Kubernetes may force‑kill the container, causing resource leaks.

The author created a Spring Boot sample project with several Dockerfile variants to test signal forwarding:

BeanTest.java : uses @PreDestroy to log shutdown.

Dockerfile.bad : runs a bash entrypoint, which blocks signal forwarding.

Dockerfile.direct : runs java -jar … directly via CMD.

Dockerfile.exec : uses an entrypoint script that ends with exec java ….

Dockerfile.bash‑c : runs bash -c "java -jar …".

Dockerfile.tini and Dockerfile.dumb‑init : demonstrate that these init tools do not guarantee graceful shutdown.

Key observations:

Running the Java command directly in CMD forwards signals correctly.

Using exec inside a script also forwards signals. bash -c works for simple commands but may fail with pipelines or redirects.

Init tools like tini or dumb‑init only reap zombies; they do not ensure the Java process shuts down gracefully.

Best Practices

Include tini or dumb‑init to reap zombie processes.

Use a simple CMD that runs the Java binary directly for reliable signal handling.

For complex startup logic, use an entrypoint script that ends with exec. bash -c can be used for simple cases but should be tested.

Memory Limits

Containerized Java applications must correctly detect the memory limit to avoid OOM kills. The author tested several OpenJDK versions with a 512 MiB container limit.

Adaptive Memory Without Configuration

Results:

OpenJDK 8u111: no container support, uses host‑based heap size.

OpenJDK 8u131: adds -XX:+UseCGroupMemoryLimitForHeap but still does not adapt by default.

OpenJDK 8u222: adds -XX:+UseContainerSupport (back‑ported) but still ineffective without the flag.

OpenJDK 11.0.15: -XX:+UseContainerSupport is enabled by default, yet the heap does not adapt.

OpenJDK 11.0.16 and OpenJDK 17: automatically adapt the heap when no flags are set (heap reduced from ~4 GiB to 120 MiB).

Adaptive Memory With Configuration

Enabling

-XX:+UnlockExperimentalVMOptions -XX:+UseCGroupMemoryLimitForHeap

on OpenJDK 8u131 has no effect in the author's environment. Enabling -XX:+UseContainerSupport on OpenJDK 8u222 also does not work.

From JDK 11 onward, -XX:+UseContainerSupport is enabled by default, and versions ≥ 11.0.15 adapt memory when the flag is active.

Analysis

On systems using cgroups v1, the following hold:

OpenJDK 8u131+ supports -XX:+UseCGroupMemoryLimitForHeap.

OpenJDK 8u191+ supports -XX:+UseContainerSupport.

OpenJDK 11+ enables -XX:+UseContainerSupport by default.

On cgroups v2, memory adaptation is only supported from OpenJDK 11.0.16 onward; earlier versions ignore the flags.

DNS Cache

Java’s DNS cache is controlled by the JVM. By default, successful lookups are cached for 30 seconds; with a Security Manager enabled, the cache is set to “forever” ( -1).

The author provides a script ( jvm-dns-ttl-policy.sh) that builds Docker images for OpenJDK 8, 11, and 17 and prints the DNS TTL policy. Results show the default TTL of 30 s, and -1 when the Security Manager is active.

To override the default, set the JVM flag -Dsun.net.inetaddr.ttl=SECONDS. This works regardless of the Security Manager. For advanced debugging, the Alibaba DCM tool can be used.

Native Compilation

GraalVM can compile Java code to a native binary, dramatically improving startup time. However, it requires code adjustments and framework upgrades, making it more suitable for new projects.

The sample project already includes GraalVM support; setting JAVA_HOME and PATH and running mvn clean package -Dmaven.test.skip=true -Pnative produces a native executable in target. Benchmarks show an order‑of‑magnitude faster startup compared to the regular JVM.

References

eclipse‑temurin: https://hub.docker.com/_/eclipse-temurin

ibm‑semeru‑runtimes: https://hub.docker.com/_/ibm-semeru-runtimes

GitHub project: https://github.com/mritd/SpringBootGracefulShutdownExample

StackExchange discussion on bash -c: https://unix.stackexchange.com/questions/466496/why-is-there-no-apparent-clone-or-fork-in-simple-bash-command-and-how-its-done

JDK‑8230305 bug: https://bugs.openjdk.org/browse/JDK-8230305

External DNS script source: https://gist.github.com/andystanton/958a9a87f5b5a4eae537f96f896a19bc

Alibaba DCM tool: https://github.com/alibaba/java-dns-cache-manipulator

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

JavaJVMDockergraalvmDNSGraceful Shutdown
Open Source Linux
Written by

Open Source Linux

Focused on sharing Linux/Unix content, covering fundamentals, system development, network programming, automation/operations, cloud computing, and related professional knowledge.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.