spring boot docker image 빌드 최적화하는 것에 대해 테스트한 것을 적어보려고 한다.
최적화를 하려는 이유는 패키지가 커지고 파일이 커졌을때 빌드하는 속도에서 많은 차이가 발생하기 떄문이다.
이를 docker cache를 활용해서 최적화를 해두면 패키지가 새로 추가되지 않는 이상 빌드 속도가 느려지지 않게 할 수 있기 때문이다.
FROM eclipse-temurin:11-jdk-jammy as build
WORKDIR /workspace/app
COPY . .
RUN ./gradlew clean build -x test
ENTRYPOINT [ "java","-jar","build/libs/*-0.0.1-SNAPSHOT.jar" ]
이렇게 작성해서 사용하면 아래와 같이 50초가 걸리는 것을 확인할 수 있었다.
추가적으로도커 파일에 만들어서 사용된 코드는 내가 예전에 프로젝트를 했을 때 사용했던 코드이다.
해당 코드의 사이즈는 704B 정도 된다.

cache처리가 될 수 있는지 확인하기 위해 다시 한번 더 빌드를 진행해보았다.

약간 빨라진거 같지만 build 시 dependency를 install 하는 불필요한 과정이 있는 것을 확인했기에 최적화가 필요하다.
FROM eclipse-temurin:11-jdk-jammy as builds
WORKDIR /workspace/app
COPY . .
RUN --mount=type=cache,target=/root/.gradle \
./gradlew clean build -x test
RUN mkdir -p build/dependency && (cd build/dependency; jar -xf ../libs/*-SNAPSHOT.jar)
FROM eclipse-temurin:11-jdk-jammy
VOLUME /tmp
ARG DEPENDENCY=/workspace/app/build/dependency
COPY --from=builds ${DEPENDENCY}/BOOT-INF/lib /app/lib
COPY --from=builds ${DEPENDENCY}/META-INF /app/META-INF
COPY --from=builds ${DEPENDENCY}/BOOT-INF/classes /app
ENTRYPOINT ["java","-cp","app:app/lib/*","hello.Application"]
아래 이미지의 결과를 보면 5초 정도 단축이 된것으로 보인다. 처음 dependency를 install 하기 떄문에 오랜 걸린것으로 보인다.
여기서 한번 더 빌드를 진행해보았다.
모든게 cached 되면서 1.8초만에 빌드가 되는 것을 확인됬었다. 하지만 이 결과로는 dependency만 cache 처리가 된게 아니어서 알 수가 없다.
이를 위해서 main메소드 위에 아래 코드를 추가했다.
System.out.println("start12311");
결과는 아래와 같다.

이 결과를 통해서 dependency가 cache 처리가 되었다는 것을 알 수 있었고 속도도 30초 정도 개선되었다.
나는 여기서 COPY를 하는 것을 좋아하지 않는다. 그래서 readonly로 사용못하는 것들은 제외하고 다음 테스트를 진행했다.
FROM eclipse-temurin:11-jdk-jammy as build
WORKDIR /workspace/app
RUN --mount=type=cache,target=/root/.gradle \
--mount=type=bind,source=gradlew,target=gradlew \
--mount=type=bind,source=build.gradle,target=build.gradle \
--mount=type=bind,source=settings.gradle,target=settings.gradle \
--mount=type=bind,source=lombok.config,target=lombok.config \
--mount=type=bind,source=gradle,target=gradle \
--mount=type=bind,source=src,target=src \
./gradlew clean build -x test
RUN mkdir -p build/dependency && (cd build/dependency; jar -xf ../libs/*-SNAPSHOT.jar)
FROM eclipse-temurin:11-jdk-jammy
VOLUME /tmp
ARG DEPENDENCY=/workspace/app/build/dependency
COPY --from=build ${DEPENDENCY}/BOOT-INF/lib /app/lib
COPY --from=build ${DEPENDENCY}/META-INF /app/META-INF
COPY --from=build ${DEPENDENCY}/BOOT-INF/classes /app
ENTRYPOINT ["java","-cp","app:app/lib/*","hello.Application"]

위 결과를 통해서 1초 정도 단축이 되었다. 테스트한 결과로는 뚜렷한 차이를 볼 수 없었다. 다만, src 파일이 1GB 이상 넘게 된다면
뚜렷한 차이를 볼 수 있을거라 생각한다. 이유는 COPY를 하게 되면 image에 복사하는 과정이 되기에 오래걸리게 된다.
하지만 --mount=bind에 경우 볼륨을 붙여서 사용하기에 copy하는 과정이 없어서 더 빠르게 빌드를 할 수 있기 때문이다.
dependency install 하는 과정을 줄이므로써 빌드 속도를 많이 최적화할 수 있다는 것을 확인했다.
나중에 회사에서 사용해보면 좋을거 같다.
ENTRYPOINT ["java","-cp","app:app/lib/*","hello.Application"]
부분에서 왜 hello.Application인지 알 수 있을까요?