Java,Spring,Spring boot,Azure Container Apps by info.odysseyx@gmail.com November 4, 2024 written by info.odysseyx@gmail.com November 4, 2024 0 comment 1 views 1 introduction In the cloud-native era, the need for rapid application launch and automated scaling has become more important. This is especially true for Java applications that require enhanced solutions to effectively meet these requirements. In a previous blog post Accelerate Java applications on Azure Kubernetes Service using CRaCWe explored ways to address these issues using CRaC technology. CRaC promotes efficient scaling operations by speeding up application startup and reducing recovery times. In this blog post, we’ll take a closer look at how to optimize container images in particular. Azure container apps (ACA) Multi-step build, spring boot layer toolsand Class Data Sharing (CDS) Create highly optimized Docker images. Combining these techniques improves both the image footprint and startup performance of Java applications on ACA. These improvements make Java applications more agile and responsive for frequent cloud-native deployments, helping them meet modern operational requirements. Key Takeaways After testing various Docker optimization techniques, we observed the following improvements in Azure Container Apps: A multi-stage build reduces image size by 33%, allowing you to import images faster. Spring Boot Layer Tools further optimize the build process by reducing unnecessary rebuilds and slightly improve image fetch and startup times. Class Data Sharing (CDS) provided the strongest benefit, reducing application startup time by 27% and significantly improving runtime performance. These optimizations not only reduce the size and import time of images, but also make deployment more efficient, saving both time and resources. Optimization technology overview Multi-step build Multi-stage builds are a powerful Docker feature that allows you to create more compact images by reducing the layers required for the final build. The first step allows you to do all the heavy lifting, including compiling code and downloading dependencies. In the final step, only the required artifacts are copied, excluding any dependencies, at build time. Leveraging multi-stage builds significantly reduces overall image size, resulting in faster pooling times and more efficient use of resources. spring boot layer tools The Spring Boot tiering tool further optimizes the tiering process for Docker images by logically partitioning your application into tiers. Each layer consists of different components of a Spring Boot application, including dependencies, the Spring Boot framework, and the application code itself. This reduces build times and improves performance when pushing updates because Docker rebuilds and caches only the layers that have changed. This also improves startup times, as unchanged layers can be loaded from cache more quickly. Class Data Sharing (CDS) CDS is a Java feature that allows class metadata to be shared between different Java processes. Application Class Data Sharing (AppCDS) allows you to further optimize startup times by archiving your application classes during the build process. This reduces class loading overhead at runtime, improving startup speed by avoiding redundant class loading operations. When integrated with Docker, CDS can be used to store shared class metadata that is reused when container restarts, significantly improving startup performance. Technology application: step-by-step optimization Now let’s look at how these techniques can be applied incrementally to optimize Docker images and improve startup times. The blog uses a repository. Spring Pet Clinic Step 0: Starting point: Base Docker image Before we look at optimizations, let’s look at a typical Dockerfile that can be used without optimizations. This base Docker image contains only the essential elements needed to run a Spring Boot application. FROM mcr.microsoft.com/openjdk/jdk:17-ubuntu WORKDIR /home/app ADD . /home/app/spring-petclinic-main RUN cd spring-petclinic-main && ./mvnw -Dmaven.test.skip=true clean package && cp ./target/*.jar /home/app/petclinic.jar EXPOSE 8080 ENTRYPOINT ["java", "-jar", "petclinic.jar"] This Dockerfile simply builds and copies the packaged JAR file and runs it using the default java -jar command. Although functional, it lacks optimization for image size and startup speed. The entire application along with all dependencies is bundled in a single layer. This means that any changes to your application require a rebuild of the entire image. Additionally, no optimizations are applied at runtime to reduce class loading overhead. The startup time reflects the JVM’s default class loading behavior. Basic image metrics for comparison optimization step Image size (MB) Image retrieval time (seconds) Start time (seconds) Base image (no optimization) 734 8.017 7,649 Additionally, base Docker images often need to include various build tools (e.g. Maven, JDK) to successfully compile your code. This not only increases the image size, but also creates more potential vulnerabilities due to: Including additional packages makes you more vulnerable to Common Vulnerability and Exposures (CVE). Step 1: Use a multi-stage build Multi-stage builds help reduce image size by separating the build environment from the runtime environment. A multi-stage Dockerfile first compiles the application in a build phase, then copies only the necessary runtime artifacts into a much thinner runtime phase. # Stage 1: Build Stage FROM mcr.microsoft.com/openjdk/jdk:17-ubuntu AS builder WORKDIR /home/app ADD . /home/app/spring-petclinic-main RUN cd spring-petclinic-main && ./mvnw -Dmaven.test.skip=true clean package # Stage 2: Final Stage FROM mcr.microsoft.com/openjdk/jdk:17-mariner WORKDIR /home/app EXPOSE 8080 COPY --from=builder /home/app/spring-petclinic-main/target/*.jar petclinic.jar ENTRYPOINT ["java", "-jar", "petclinic.jar"] Multi-stage build metrics optimization step Image size (MB) Image retrieval time (seconds) Start time (seconds) Base image (no optimization) 734 8.017 7,649 Multi-level construction 492 7.145 7.932 With a multi-stage build, the resulting image contains only the compiled application and its dependencies, excluding heavy build tools such as Maven. Using a multi-stage build reduces image size by 33% and slightly improves image fetch times, while keeping startup times close to the base image. Step 2: Optimization using Spring Boot Layer tools Next, we add Spring Boot layer tools to optimize the structure of our application layer. # Stage 1: Build Stage FROM mcr.microsoft.com/openjdk/jdk:17-ubuntu AS builder WORKDIR /home/app ADD . /home/app/spring-petclinic-main RUN cd spring-petclinic-main && ./mvnw -Dmaven.test.skip=true clean package # Stage 2: Layer Tool Stage FROM mcr.microsoft.com/openjdk/jdk:17-ubuntu AS optimizer WORKDIR /home/app COPY --from=builder /home/app/spring-petclinic-main/target/*.jar petclinic.jar RUN java -Djarmode=layertools -jar petclinic.jar extract # Stage 3: Final Stage FROM mcr.microsoft.com/openjdk/jdk:17-mariner ENTRYPOINT ["java", "org.springframework.boot.loader.JarLauncher"] COPY --from=optimizer /home/app/dependencies/ ./ COPY --from=optimizer /home/app/spring-boot-loader/ ./ COPY --from=optimizer /home/app/snapshot-dependencies/ ./ COPY --from=optimizer /home/app/application/ ./ layer tool metrics Optimization step Image size (MB) Image retrieval time (seconds) Start time (seconds) Base image (no optimization) 734 8.017 7,649 Multi-level construction 492 6.987 7.932 spring boot layer tools 493 7.104 7.805 Typically, the Spring framework itself and its dependencies are much larger than application-specific classes. The Layers tool allows you to place these large, rarely changing components (such as the Spring framework and external libraries) in lower layers of your image, while application-specific code resides in the top layer. Constructing images in this way not only optimizes build times, but also reduces bandwidth usage when transferring images. This ensures that only changed layers are updated, improving build efficiency and faster startup for subsequent updates. Step 3: Class Data Sharing (CDS) Integration Finally, we integrate CDS for class loading optimization. # Stage 1: Build Stage FROM mcr.microsoft.com/openjdk/jdk:17-ubuntu AS builder WORKDIR /home/app ADD . /home/app/spring-petclinic-main RUN cd spring-petclinic-main && ./mvnw -Dmaven.test.skip=true clean package # Stage 2: Layer Tool Stage FROM mcr.microsoft.com/openjdk/jdk:17-ubuntu AS optimizer WORKDIR /app COPY --from=builder /home/app/spring-petclinic-main/target/*.jar petclinic.jar RUN java -Djarmode=tools -jar petclinic.jar extract --layers --launcher # Stage 3: Optimize with CDS Stage FROM mcr.microsoft.com/openjdk/jdk:17-mariner COPY --from=optimizer /app/petclinic/dependencies/ ./ COPY --from=optimizer /app/petclinic/spring-boot-loader/ ./ COPY --from=optimizer /app/petclinic/snapshot-dependencies/ ./ COPY --from=optimizer /app/petclinic/application/ ./ RUN java -XX:ArchiveClassesAtExit=./application.jsa -Dspring.context.exit=onRefresh org.springframework.boot.loader.launch.JarLauncher ENTRYPOINT ["java", "-XX:SharedArchiveFile=application.jsa", "org.springframework.boot.loader.launch.JarLauncher"] This setting significantly reduces class loading time, making application startup faster. Optimization through Class Data Sharing (CDS) Optimization step Image size (MB) Image retrieval time (seconds) Start time (seconds) Base image (no optimization) 734 8.017 7,649 Multi-level construction 492 6.987 7.932 spring boot layer tools 493 7.104 7.805 CDS 560 7.145 5.562 conclusion By integrating multi-stage builds, Spring Boot Layer tooling, and class data sharing into your Docker images, you can optimize both the size and performance of your Java applications in Azure Container Apps. Each technique addresses a different aspect of optimization, including reducing image bloat, improving layer caching, and improving class loading efficiency. Together they create a powerful solution for building and deploying highly optimized Java applications in Docker containers. ACA is an ideal managed platform for running Java applications, providing features tailored to Java workloads, including built-in JVM metrics, diagnostics, and middleware support. These features enable Java applications to perform optimally while simplifying management and scaling in cloud-native environments. For more information, please visit: Azure container app Java overview. Source link Share 0 FacebookTwitterPinterestEmail info.odysseyx@gmail.com previous post Innovate with Microsoft Management Customer Connection Program next post Windows Scoping: The Secret Sauce to Squashing Windows Gremlins Faster! You may also like A New Dawn of Software Defined Networking (SDN) in Windows Server 2025 November 5, 2024 Get AI ready: Empowering developers in the era of AI November 5, 2024 Announcing the General Availability of Windows Server IoT 2025! November 5, 2024 America’s Partner Blog | Partners Make More Possible: Education November 4, 2024 Turn Microsoft Copilot into a personal assistant with Scheduled Prompts November 4, 2024 Sync identities from Rippling to Microsoft Entra ID November 4, 2024 Leave a Comment Cancel Reply Save my name, email, and website in this browser for the next time I comment.