Practical Experience of Containerizing Java Applications: Docker, JVM Tuning, Multi‑Stage Builds, and Operational Tips
This article shares the 2019 cloud‑native migration experience of an e‑commerce team, covering Docker and Kubernetes basics, Java‑Docker compatibility, memory and CPU limits, log collection, JDK version choices, Dockerfile and multi‑stage build practices, health checks, graceful shutdown, and common pitfalls encountered during containerization.
Java Vs Docker
Low‑version Java does not automatically detect Docker memory/CPU limits, requiring explicit JVM options.
Memory Limits
Docker uses cgroups; without limits containers compete for resources. Example command:
docker run -m 1024M --cpuset-cpus="1,3"Pre‑Docker‑8u131 Java cannot see limits; need -Xmx and enable OutOfMemoryException .
CPU Limits
JVM may see host CPUs instead of Docker‑set CPUs, affecting thread pools and parallel GC.
Log Collection
Logs inside containers disappear on container removal; use bind mounts, volumes, filebeat, or nxlog to persist.
Technical Preparation
Choose appropriate JDK version and JVM flags:
Before 8u131 set -Xmx , ParallelGCThreads , CICompilerCount .
8u131+ recognize CPU limits; need -XX:+UnlockExperimentalVMOptions -XX:+UseCGroupMemoryLimitForHeap .
8u191 adds InitialRAMPercentage , MinRAMPercentage , MaxRAMPercentage .
Java 11 enables -XX:UseContainerSupport by default.
-Xmx=2G -XX:ParallelGCThreads=cpus -XX:CICompilerCount=cpus -XX:+UnlockExperimentalVMOptions -XX:+UseCGroupMemoryLimitForHeap -XX:UseContainerSupportImage Build
Base image selection avoids distroless/Alpine due to missing tools. Example Dockerfile:
FROM xxxx.autohome.com.cn/project/centos7-jdk8:full-nxlog
ADD skywalking-agent/6.4.0/ /skywalking-agent/
ADD arthas-3.1.4/ /arthas/
RUN echo 'Asia/Shanghai' > /etc/timezone && chown -R root:root "/var/run/nxlog"
MAINTAINER [email protected]Build and push commands:
docker build -t xxxx.autohome.com.cn/project/centos7-jdk8:v1
docker push xxx.autohome.com.cn/project/centos7-jdk8:v1Multi‑Stage Build
Standard Maven build example:
FROM maven:3.5-jdk-8 AS build
COPY src /usr/src/app/src
COPY pom.xml /usr/src/app
RUN mvn -f /usr/src/app/pom.xml clean package
FROM openjdk:8-jre
ARG DEPENDENCY=/usr/src/app/target/dependency
COPY --from=build ${DEPENDENCY}/BOOT-INF/lib /app/lib
COPY --from=build ${DEPENDENCY}/META-INF /app/META-INF
COPY --from=build ${DEPENDENCY}/BOOT-INF/classes /app
ENTRYPOINT ["java","-cp","app:app/lib/*","hello.Application"]Health Checks
Kubernetes Liveness and Readiness probes ensure container health; set appropriate probe logic based on service state.
Graceful Shutdown
Use preStop hook, enable Spring Boot shutdown endpoint, and run Java as PID 1 with exec‑form CMD:
CMD ["java","$JAVA_OPTS","-jar","/app.jar"]Additional tips on timezone, language settings, log conflicts, and downloading files from containers are provided.
HomeTech
HomeTech tech sharing
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.