Cache Gradle dependent files to speed up docker build

Abstract

--By performing gradlew build with only Gradle related files COPY, create a cache layer for downloading dependent files. --The build time of Docker image has been reduced by about 70% (* There are differences depending on the environment and project.)

Motivation

It took more than 5 minutes to build the Docker image for the Spring Boot application. Therefore, it takes time to build and deploy to the inspection environment. There was a problem that it took time for trial and error, which can only be done in the inspection environment.

Sample Dockerfile

FROM openjdk:11.0.8-jre-slim as builder

WORKDIR /app

# build.Add only files that depend on gradle,
#Idle gradle build to cache dependent files
COPY *.gradle gradle.* gradlew /app/
COPY gradle/ /app/gradle/
RUN ./gradlew build -x test --parallel --continue > /dev/null 2>&1 || true

#Incorporate and build code changes after the following lines
COPY . /app
RUN ./gradlew build -x test --parallel

FROM openjdk:11.0.8-jre-slim

COPY --from=builder /app/build/libs/app.jar /app/app.jar
CMD ["java", "-jar", "/app/app.jar"]

Tips: We use multi-stage builds to separate the build container and the execution container.

Detailed explanation

General Dockerfile example

I think that the Dockerfile that does a common Gradle build is as follows.

FROM openjdk:11.0.8-jre-slim as builder
WORKDIR /app
COPY . /app
RUN ./gradlew build -x test --parallel

The problem with this Dockerfile is that it takes a long time to build because the gradle binaries and dependent files are downloaded every time you build. This time, we will speed up by caching the download of this gradle binary and dependent files in the image layer.

There is no command to download dependent files in Gradle

Unfortunately, there are no Gradle commands that only download binaries and dependent files. However, the download is done at the beginning of the build runtime. Therefore, even if the build fails, the build is idled to perform pre-download.

$ ./gradlew build --continue > /dev/null 2>&1 || true

By adding the --continue option, even a build with multiple projects can be executed to the end and the dependent files can be downloaded.

Cache characteristics of the COPY command

The COPY command checks whether the cache can be used based on the checksum of the file. (* It is not the last update date or access date and time) Therefore, you can create a layer that downloads dependent files by COPY the minimum required files for gradle build and idle build. Since build.gradle etc. are rarely changed, the cache can be used at many builds, and the build time can be reduced.

COPY *.gradle gradle.* gradlew /app/
COPY gradle/ /app/gradle/

Reduction effect

By using the above Gradle-dependent file cache, you can reduce the image build time of Docker. Regarding the reduction effect, it depends on the environment and Java project, but I will share my application result.

Before application: 4min 56sec After application: 1min 42sec

By applying this method, we were able to reduce the build time by about 70%.

Finally

We hope that the above method will reduce the image build time of Docker using Gradle in the world as much as possible. If you find any mistakes in the description, please let us know in the comments.

Recommended Posts

Cache Gradle dependent files to speed up docker build
How to build docker environment with Gradle for intelliJ
Set up Gradle multi-project in IntelliJ to build JAR file
[Rails] How to speed up docker-compose
[Docker] Operation up to container creation # 2
How to build CloudStack using Docker
Spring Boot gradle build with Docker
Enable Docker build cache on GitHub Action and deploy to Amazon ECS
How to share files with Docker Toolbox
Run Embulk on Docker to convert files
Build Spring Boot + Docker image in Gradle
[Docker] Copy files from docker container to host
Docker container build fails to install php-radis
How to build Rails 6 environment with Docker
Copy files from docker container to host (docker cp)
Build Java x Spring x VSCode x Gradle on Docker (1)
How to update pre-built files in docker container
[Rails] How to build an environment with Docker
How to build parquet-tools and merge Parquet files
3 Tips to Improve Lead Time for Docker Build