Below is an example Dockerfile
that we recommend at Depot for building images for Java applications with Gradle.
# syntax=docker/dockerfile:1
FROM eclipse-temurin:21-jdk AS build
ENV GRADLE_HOME=/opt/gradle \
GRADLE_USER_HOME=/cache/.gradle \
GRADLE_OPTS="-Dorg.gradle.daemon=false \
-Dorg.gradle.parallel=true \
-Dorg.gradle.caching=true \
-Xmx2g"
ARG GRADLE_VERSION=8.10
RUN apt-get update && apt-get install -y --no-install-recommends unzip \
&& wget -q https://services.gradle.org/distributions/gradle-${GRADLE_VERSION}-bin.zip \
&& unzip gradle-${GRADLE_VERSION}-bin.zip -d /opt \
&& ln -s /opt/gradle-${GRADLE_VERSION} /opt/gradle \
&& rm gradle-${GRADLE_VERSION}-bin.zip \
&& apt-get remove -y unzip \
&& rm -rf /var/lib/apt/lists/*
ENV PATH="${GRADLE_HOME}/bin:${PATH}"
WORKDIR /app
COPY build.gradle ./
RUN --mount=type=cache,target=/cache/.gradle \
gradle dependencies --no-daemon --stacktrace
COPY src/ src/
RUN --mount=type=cache,target=/cache/.gradle \
gradle build -x test --no-daemon --stacktrace --build-cache
FROM eclipse-temurin:21-jre AS runtime
RUN groupadd -g 1001 appgroup && \
useradd -u 1001 -g appgroup -m -d /app -s /bin/false appuser
WORKDIR /app
COPY --from=build --chown=appuser:appgroup /app/build/libs/*.jar app.jar
ENV JAVA_OPTS="-server \
-XX:+UseContainerSupport \
-XX:MaxRAMPercentage=75.0 \
-XX:+UseG1GC \
-Djava.security.egd=file:/dev/./urandom"
USER appuser
ENTRYPOINT ["sh", "-c", "java $JAVA_OPTS -jar app.jar"]
At a high level, here are the things we're optimizing in our Docker build for a Java application with Gradle:
FROM eclipse-temurin:21-jdk AS build
FROM eclipse-temurin:21-jdk AS build
ENV GRADLE_HOME=/opt/gradle \
GRADLE_USER_HOME=/cache/.gradle \
GRADLE_OPTS="-Dorg.gradle.daemon=false \
-Dorg.gradle.parallel=true \
-Dorg.gradle.caching=true \
-Xmx2g"
We use Eclipse Temurin 21 JDK and configure Gradle with optimized settings:
GRADLE_USER_HOME=/cache/.gradle
points to our cache mount locationgradle.daemon=false
disables the daemon (not beneficial in containers)gradle.parallel=true
enables parallel execution for faster buildsgradle.caching=true
enables Gradle's build cache-Xmx2g
sets maximum heap size for GradleARG GRADLE_VERSION=8.10
RUN apt-get update && apt-get install -y --no-install-recommends unzip \
&& wget -q https://services.gradle.org/distributions/gradle-${GRADLE_VERSION}-bin.zip \
&& unzip gradle-${GRADLE_VERSION}-bin.zip -d /opt \
&& ln -s /opt/gradle-${GRADLE_VERSION} /opt/gradle \
&& rm gradle-${GRADLE_VERSION}-bin.zip \
&& apt-get remove -y unzip \
&& rm -rf /var/lib/apt/lists/*
ENV PATH="${GRADLE_HOME}/bin:${PATH}"
We install a specific Gradle version for reproducible builds and clean up build tools afterward to keep the layer small.
WORKDIR /app
COPY build.gradle ./
RUN --mount=type=cache,target=/cache/.gradle \
gradle dependencies --no-daemon --stacktrace
We copy only the build.gradle
first to leverage Docker layer caching. The dependencies
task downloads all dependencies, with a cache mount to persist between builds.
COPY src/ src/
RUN --mount=type=cache,target=/cache/.gradle \
gradle build -x test --no-daemon --stacktrace --build-cache
After copying the source code, we build the application with the same cache mount. Key options:
-x test
excludes tests from the build (run in CI/CD pipeline)--no-daemon
ensures no daemon process is left running--build-cache
enables Gradle's build cache for faster incremental buildsFROM eclipse-temurin:21-jre AS runtime
FROM eclipse-temurin:21-jre AS runtime
RUN groupadd -g 1001 appgroup && \
useradd -u 1001 -g appgroup -m -d /app -s /bin/false appuser
WORKDIR /app
COPY --from=build --chown=appuser:appgroup /app/build/libs/*.jar app.jar
ENV JAVA_OPTS="-server \
-XX:+UseContainerSupport \
-XX:MaxRAMPercentage=75.0 \
-XX:+UseG1GC \
-Djava.security.egd=file:/dev/./urandom"
USER appuser
ENTRYPOINT ["sh", "-c", "java $JAVA_OPTS -jar app.jar"]
The runtime stage uses Eclipse Temurin 21 JRE for a reliable runtime environment. We create a non-root user for security and copy the built JAR file. The JVM is configured with production settings:
-server
enables server mode for better long-running performanceUseContainerSupport
and MaxRAMPercentage
for container-aware memory managementUseG1GC
enables the G1 garbage collector for better performancejava.security.egd
uses /dev/urandom
for faster startupCache mounts are one of the most powerful features for optimizing Docker builds with Depot. This Dockerfile uses the following cache mount syntax:
RUN --mount=type=cache,target=/cache/.gradle \
gradle dependencies --no-daemon --stacktrace
type=cache
: Specifies this is a cache mount that persists across builds.target=/cache/.gradle
: The mount point for Gradle's cache directory (configured via GRADLE_USER_HOME
).For more information regarding Gradle cache mounts, please visit the official Gradle documentation.