Cloud Native 20 min read

Optimizing Spring Boot Docker Image Build, Push, and Pull with Layer Caching

This article explains how to efficiently build, push, and pull Docker images for Spring Boot applications by leveraging Docker's layered cache, separating dependency JARs from the application JAR, and measuring the performance improvements in a Kubernetes micro‑service environment.

Java Captain
Java Captain
Java Captain
Optimizing Spring Boot Docker Image Build, Push, and Pull with Layer Caching

In the era of Spring Cloud micro‑services, the deployment model has shifted from packaging each service as a JAR to packaging each service as a Docker image managed by Kubernetes. This article explores how to write an optimal Dockerfile for a Spring Boot project, measure build, push, and pull times, and improve performance using Docker's layer caching.

System Environment

Docker version: 18.09.3

Base image: openjdk:8u212-b04-jre-slim

Test registry: Alibaba Cloud Docker Hub

Project source: GitHub

1. Building a Standard Spring Boot Docker Image

Prepare a Maven‑built Spring Boot JAR (≈70 MB) and place it in the Docker build context.

FROM openjdk:8u212-b04-jre-slim
VOLUME /tmp
ADD target/*.jar app.jar
RUN sh -c 'touch /app.jar'
ENV JAVA_OPTS="-Duser.timezone=Asia/Shanghai"
ENV APP_OPTS=""
ENTRYPOINT ["sh", "-c", "java $JAVA_OPTS -Djava.security.egd=file:/dev/./urandom -jar /app.jar $APP_OPTS"]

Build the image:

$ time docker build -t registry.cn-beijing.aliyuncs.com/mydlq/springboot:0.0.1 .

The build completes in about 14 seconds. Push the image:

$ time docker push registry.cn-beijing.aliyuncs.com/mydlq/springboot:0.0.1

Push finishes in roughly 25 seconds. Pull the image on another host:

$ time docker pull registry.cn-beijing.aliyuncs.com/mydlq/springboot:0.0.1

Pull takes about 28 seconds.

2. Docker Layer Caching and Its Impact

Docker stores each instruction in a Dockerfile as a separate layer. If a layer’s command and its inputs do not change, Docker reuses the cached layer, dramatically reducing build time and network traffic.

Key commands that affect caching are RUN , ADD , and COPY . Understanding their behavior is essential for optimizing image builds.

3. Reducing Image Bloat by Splitting Dependencies

The Spring Boot JAR contains a BOOT-INF/lib directory with many dependency JARs (≈74 MB). By configuring Maven to keep dependencies outside the executable JAR and only include compiled classes, the application JAR shrinks to a few hundred kilobytes.

<build>
    <plugins>
        <!-- Maven JAR plugin to add classpath pointing to external lib folder -->
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-jar-plugin</artifactId>
            <configuration>
                <archive>
                    <manifest>
                        <addClasspath>true</addClasspath>
                        <classpathPrefix>lib/</classpathPrefix>
                    </manifest>
                </archive>
            </configuration>
        </plugin>
        <!-- Spring Boot plugin configured to exclude all dependencies from the fat JAR -->
        <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
            <configuration>
                <includes>
                    <include>
                        <groupId>nothing</groupId>
                        <artifactId>nothing</artifactId>
                    </include>
                </includes>
            </configuration>
        </plugin>
        <!-- Maven Dependency plugin to copy all external JARs to target/lib -->
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-dependency-plugin</artifactId>
            <executions>
                <execution>
                    <id>copy-dependencies</id>
                    <phase>prepare-package</phase>
                    <goals>
                        <goal>copy-dependencies</goal>
                    </goals>
                    <configuration>
                        <outputDirectory>${project.build.directory}/lib</outputDirectory>
                    </configuration>
                </execution>
            </executions>
        </plugin>
    </plugins>
</build>

After rebuilding, the application JAR is tiny, while the lib folder holds the large dependencies.

4. Modified Dockerfile Using Separate lib Layer

FROM openjdk:8u212-b04-jre-slim
VOLUME /tmp
COPY target/lib/ ./lib/
ADD target/*.jar app.jar
RUN sh -c 'touch /app.jar'
ENV JAVA_OPTS="-Duser.timezone=Asia/Shanghai"
ENV APP_OPTS=""
ENTRYPOINT ["sh", "-c", "java $JAVA_OPTS -Djava.security.egd=file:/dev/./urandom -jar /app.jar $APP_OPTS"]

Placing the COPY target/lib/ ./lib/ instruction before adding the application JAR ensures the dependency layer is cached across builds when dependencies do not change.

5. Performance Results

First build (no cache) takes ~23 seconds. Subsequent builds after only changing the application code reuse the cached dependency layer and finish in ~2.5 seconds. Push of the unchanged layers completes in ~0.2 seconds, and pull of the new image takes ~2 seconds, demonstrating the dramatic speedup.

The approach shows that separating rarely‑changed dependencies from frequently‑changed application code can reduce network traffic from dozens of megabytes to a few hundred kilobytes, making Docker image workflows much more efficient for Spring Boot micro‑services.

In production, where image versions change slowly, this method can be adopted after thorough validation to ensure compatibility with existing deployment pipelines.

javaDockerKubernetesSpring BootDockerfileImage Caching
Java Captain
Written by

Java Captain

Focused on Java technologies: SSM, the Spring ecosystem, microservices, MySQL, MyCat, clustering, distributed systems, middleware, Linux, networking, multithreading; occasionally covers DevOps tools like Jenkins, Nexus, Docker, ELK; shares practical tech insights and is dedicated to full‑stack Java development.

0 followers
Reader feedback

How this landed with the community

login 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.