DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Please enter at least three characters to search
Refcards Trend Reports
Events Video Library
Refcards
Trend Reports

Events

View Events Video Library

Zones

Culture and Methodologies Agile Career Development Methodologies Team Management
Data Engineering AI/ML Big Data Data Databases IoT
Software Design and Architecture Cloud Architecture Containers Integration Microservices Performance Security
Coding Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Culture and Methodologies
Agile Career Development Methodologies Team Management
Data Engineering
AI/ML Big Data Data Databases IoT
Software Design and Architecture
Cloud Architecture Containers Integration Microservices Performance Security
Coding
Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance
Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks

The software you build is only as secure as the code that powers it. Learn how malicious code creeps into your software supply chain.

Apache Cassandra combines the benefits of major NoSQL databases to support data management needs not covered by traditional RDBMS vendors.

Generative AI has transformed nearly every industry. How can you leverage GenAI to improve your productivity and efficiency?

Modernize your data layer. Learn how to design cloud-native database architectures to meet the evolving demands of AI and GenAI workloads.

Related

  • Building a Reverse Image Search System Based on Milvus and VGG
  • Buildpacks: An Open-Source Alternative to Chainguard
  • Setting Up a Local Development Environment With IntelliJ, DevContainers, and Amazon Linux 2023
  • Getting Started With NCache Java Edition (Using Docker)

Trending

  • Contextual AI Integration for Agile Product Teams
  • Building Custom Tools With Model Context Protocol
  • Cloud Cost Optimization for ML Workloads With NVIDIA DCGM
  • Navigating the LLM Landscape: A Comparative Analysis of Leading Large Language Models
  1. DZone
  2. Software Design and Architecture
  3. Cloud Architecture
  4. Multi-Stage Docker Image Build for Java Apps

Multi-Stage Docker Image Build for Java Apps

No longer do you have to manage multiple Dockerfiles and use the Builder Pattern. Now, you can save time by creating a multi-stage build process for your Java apps.

By 
Shekhar Gulati user avatar
Shekhar Gulati
·
May. 26, 17 · Tutorial
Likes (3)
Comment
Save
Tweet
Share
37.0K Views

Join the DZone community and get the full member experience.

Join For Free

A few days back, I discovered a new Docker feature — multi-stage builds. The multi-stage build feature helps you create thin Docker images by making it possible to divide the image building process into multiple stages. Artifacts produced in one stage can be reused by another stage. This is very beneficial for languages like Java as multiple steps are required to build the Docker image. The main advantage of the multi-stage build feature is that it can help you create smaller size images. This feature is not yet available in stable versions of Docker. It will become available in Docker 17.05. To use this feature, you have to use the edge version of Docker CE.

To build a Docker image for a Java application, you first need to build the Java project. Java build process needs a JDK and a build tool like Maven, Gradle, or Ant. Once a Java binary artifact is produced, you can package the binary in a Docker image. For running a Java binary, you only need JRE, so you don’t have to pay the cost of bundling the whole JDK.

One of the ways people have handled the multiple staging builds is by using the Builder pattern. This pattern requires you to have two Dockerfile files — Dockerfile and Dockerfile_build. The Dockerfile_build file will be used to build the Java binary, and Dockerfile will be used to create the final runtime image. Below is the content of the  Dockerfile_build file for a Spring Boot Gradle project.

FROM openjdk:8
ENV APP_HOME=/root/dev/myapp/
RUN mkdir -p $APP_HOME/src/main/java
WORKDIR $APP_HOME
COPY build.gradle gradlew gradlew.bat $APP_HOME
COPY gradle $APP_HOME/gradle
# download dependencies
RUN ./gradlew build -x :bootRepackage -x test --continue
COPY . .
RUN ./gradlew build


The above Dockerfile first downloads all the dependencies and then builds the project. Please note that we are copying source code after downloading the dependencies. This allows Docker to reuse the layer that downloaded Gradle dependencies. We will be changing the source code more often so we have kept it later in the Dockerfile.

To create the Java artifact, we will first build a Docker image and then create the container using the commands mentioned below.

$ docker build -t myapp_build -f Dockerfile_build .
$ docker create --name myapp-build-container myapp_build


Now, you have to copy the artifact from the myapp-build-container using the docker cp command and create the final image that will be used for execution.

As you’ll see, it is a tedious process requiring you to maintain multiple Dockerfiles.

Docker Multi-Build Feature to the Rescue

With multi-stage builds, a Dockerfile can contain multiple FROM directives. The last FROM directive output is the resultant image. So, now you have to maintain a single Dockerfile that will build the Java artifact in the first stage and then create the final image in the second stage using the artifact produced in the first stage.

FROM openjdk:8 AS BUILD_IMAGE
ENV APP_HOME=/root/dev/myapp/
RUN mkdir -p $APP_HOME/src/main/java
WORKDIR $APP_HOME
COPY build.gradle gradlew gradlew.bat $APP_HOME
COPY gradle $APP_HOME/gradle
# download dependencies
RUN ./gradlew build -x :bootRepackage -x test --continue
COPY . .
RUN ./gradlew build

FROM openjdk:8-jre
WORKDIR /root/
COPY --from=BUILD_IMAGE /root/dev/myapp/build/libs/myapp.jar .
EXPOSE 8080
CMD ["java","-jar","myapp.jar"]


In the Dockerfile shown above,

  1. We have two FROM commands. FROM command can also take an alias name so that you can reference the name later. If you don’t provide an alias, then you can refer using the index starting from 0. There can be more than two stages. The example above uses two stages.
  2. The first FROM command uses openjdk:8 image as the base image as it needs to build the project. The second FROM command uses openjdk:8-jre as it needs to run the binary.
  3. We used the from option of the COPY command to copy the artifact produced by the first image into the second image. The from option can either use the alias name that you can mention with FROM command or it can be an index starting from 0. For example, if we remove AS BUILD_IMAGE in the first FROM commandm then we can write COPY command as COPY –from=0 /root/dev/myapp/build/libs/myapp.jar .

To build the image and run the application, you can use standard commands as shown below.

$ docker build -t myapp .
$ docker run -d -p 8080:8080 myapp


The size of the image is drastically small compared to the image used for building the Java binary as shown below.

$ docker images
myapp               latest              45f3dfc8c0bc        10 minutes ago   
325MB
myapp_build         latest              b2115749abff        32 minutes ago    857MB

Conclusion

You should certainly give Docker multi-stage build feature a try for your applications. It can streamline your Docker image building process, helping you maintain fewer Dockerfiles and smaller Docker images.

Docker (software) Build (game engine) Java (programming language)

Published at DZone with permission of Shekhar Gulati. See the original article here.

Opinions expressed by DZone contributors are their own.

Related

  • Building a Reverse Image Search System Based on Milvus and VGG
  • Buildpacks: An Open-Source Alternative to Chainguard
  • Setting Up a Local Development Environment With IntelliJ, DevContainers, and Amazon Linux 2023
  • Getting Started With NCache Java Edition (Using Docker)

Partner Resources

×

Comments
Oops! Something Went Wrong

The likes didn't load as expected. Please refresh the page and try again.

ABOUT US

  • About DZone
  • Support and feedback
  • Community research
  • Sitemap

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Core Program
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 3343 Perimeter Hill Drive
  • Suite 100
  • Nashville, TN 37211
  • support@dzone.com

Let's be friends:

Likes
There are no likes...yet! 👀
Be the first to like this post!
It looks like you're not logged in.
Sign in to see who liked this post!