본문 바로가기
공부 기록

[Docker] Layered jar를 이용한 스프링 부트 Docker build 최적화

by 타태 2022. 2. 22.

스프링 부트 메이븐 플러그인 공식 문서

 

Spring Boot Maven Plugin Documentation

While you may start your Spring Boot application very easily from your test (or test suite) itself, it may be desirable to handle that in the build itself. To make sure that the lifecycle of your Spring Boot application is properly managed around your inte

docs.spring.io

스프링부트를 활용한 도커 이미지 생성 공식 문서

 

Creating Docker images with Spring Boot 2.3.0.M1

<div class="paragraph"> <p>Spring Boot 2.3.0.M1 has just been released and it brings with it some interesting new features that can help you package up your Spring Boot application into Docker images. In this blog post we’ll take a look at the typical wa

spring.io

 

입사 이후 처음으로 놀랐던 것은 도커를 이용한 배포가 매번 30분 이상이 소요된다는 것이었다.

배포 방식이나 의존성에 대한 파악이 되지 않았기 때문에 매번 30분씩, 에러라도 발생하면 또 다시 30분씩 걸리는 배포를 반복했다.

때문에 자칫 잘못 걸리면 배포하느라 몇시간씩 집에 못가고 야근을 하곤 했다.

 

때문에 도커를 잘 모르는 상태에서 할 수 있던 최선의 방법은 자동화였다.

백그라운드에서 미리 빌드를 돌려두고 완성 되었을 경우 기존 컨테이너 종료와 함께 새로운 컨테이너를 띄우는 스크립트를 작성했다.

 

2021.12.02 - [실전 공부/AWS&Docker&Linux] - [Docker] 도커 빌드 및 실행 자동화 스크립트

 

 

그러다 코드 분석도 어느 정도 되고 조금이나마 도커에 대한 감이 생겼을 때 다시 보니 jdk 이미지만 있으면 될일을 리눅스를 통째로 만들어서 필요한 의존성을 전부 설치하고 있었다.

음..? 이게 무슨 일이지 개발 환경 구축용인건가? 그러기엔 jar를 묶어둬서 매번 빌드해야하는데..?

 

이러던 중 오픈 카톡 방에서 "jar를 찢어라"라는 말을 보고 찾아보게 된 Layered jar 방식을 공유한다.

 

이 방식을 적용한 이후 빌드 시간은 10~20초 남짓으로 줄었다.

 

Pom.xml 메이븐 플러그인 설정 추가

<project>
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <layers>
                        <enabled>true</enabled>
                        <configuration>${project.basedir}/src/layers.xml</configuration>
                    </layers>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>

 

위 설정에 추가한 경로에 layers.xml 작성

<layers xmlns="http://www.springframework.org/schema/boot/layers"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://www.springframework.org/schema/boot/layers
                          https://www.springframework.org/schema/boot/layers/layers-2.6.xsd">
    <application>
        <into layer="spring-boot-loader">
            <include>org/springframework/boot/loader/**</include>
        </into>
        <into layer="application" />
    </application>
    <dependencies>
        <into layer="application">
            <includeModuleDependencies />
        </into>
        <into layer="snapshot-dependencies">
            <include>*:*:*SNAPSHOT</include>
        </into>
        <into layer="dependencies" />
    </dependencies>
    <layerOrder>
        <layer>dependencies</layer>
        <layer>spring-boot-loader</layer>
        <layer>snapshot-dependencies</layer>
        <layer>application</layer>
    </layerOrder>
</layers>

. dependencies : 버전에 스냅샷이 포함되어 있지 않은 모든 dependency
. spring-boot-loader : jar loader classes
. snapshot-dependencies : 버전에 스냅샷이 포함되어 있는 모든 dependency
. application : 어플리케이션 클래스와 리소스 <- 변경이 가장 빈번하게 일어나고 재빌드의 원인이 되는 부분

 

Dockerfile

FROM adoptopenjdk:11-jre-hotspot as builder
WORKDIR application
ARG JAR_FILE=target/*.jar
COPY ${JAR_FILE} application.jar
RUN java -Djarmode=layertools -jar application.jar extract

FROM adoptopenjdk:11-jre-hotspot
WORKDIR application
COPY --from=builder application/dependencies/ ./
COPY --from=builder application/snapshot-dependencies/ ./
COPY --from=builder application/resources/ ./
COPY --from=builder application/application/ ./
ENTRYPOINT ["java", "org.springframework.boot.loader.JarLauncher"]

Jar 파일을 4개의 레이어로 추출한 뒤 이를 각 레이어별로 복사하여 가져오는 방식이다.

 

어플리케이션 클래스와 리소스를 가장 마지막에 가져옴으로써 직전까지의 빌드 항목은 캐싱을 이용하여 재 빌드 없이 최적화가 가능하다.

 

 

 

**

추천 블로그

설명도 잘되어 있고, 스프링부트에서 자체적으로 도커 파일 없이 도커 이미지를 생성해주는 방법이 소개되어 있다. 

반응형

댓글