본문 바로가기
개발 잡담

Multi Stage Build 로 스프링 프로젝트 이미지 축소해보기

by 휴일이 2024. 8. 26.

문제

  • 문제까지는 아니지만 multi-stage-build 방식으로 이미지 사이즈 축소 가능
  • 스프링 이미지 축소를 해보고자 함.
  • 참고로 모든 테스트는 “로컬”에서 진행함.

Multi-Stage build

기존 Dockerfile

FROM openjdk:17-jdk-slim

COPY . .

EXPOSE 8003

CMD ["java", "-Duser.timezone=Asia/Seoul", "-jar", "*.jar"]
  • 단순히 project 파일을 이미지로 복사하고 *.jar 파일을 실행시킴.
  • 프로젝트의 모든 파일을 전부 복사하기 때문에

  • COPY . . 한 후 로그를 찍어보면 WORKDIR 에 project 파일이 전부 복사되는 것을 확인 가능.
    • 서버 빌드에 필요 없는 파일도 복사 중..

개선 Dockerfile

FROM gradle:7.6-jdk as builder

WORKDIR /builder
COPY /src/main /builder/src/main
COPY build.gradle settings.gradle /builder/

RUN gradle clean build

FROM eclipse-temurin:17.0.12_7-jre-noble AS runner

WORKDIR /app

COPY --from=builder /builder/build/libs/*.jar /app/test.jar
#RUN echo "Listing all files:" && ls / && echo "Done listing files."

EXPOSE 8003

# 컨테이너가 시작될 때 실행될 명령 지정(jar 파일의 이름을 적어준다.)
CMD ["java", "-jar", "/app/test.jar"]

builder , runner 단계로 나눠서 이미지 작성

  • builder
    • gradle 로 필요한 프로젝트 파일만 가지고와서 빌드
  • runner
    • builder 에서 빌드했던 아티팩트 복사
    • java -jar *.jar 명령어로 서버 실행

복사한 파일 로그를 찍어볼 경우

  • WORDIR 인 /app 외에는 전부 FROM 이미지 관련 파일들

  • 이렇게 /app 으로 찍어보면 딱 *.jar 파일만 복사된 것을 확인 가능

.dockerignore 추가

.idea/
*.iml
*.iws
  • 어차피 최종 이미지에는 아티팩트만 있으니까 상관없지만
  • 처음 빌드에서도 필요없는 파일은 COPY 를 피하기 위해 이같이 선택

다만…

멀티스테이지 빌드를 적용 시킨 전 / 후 차이

  • 463MB → 458MB단 5MB 밖에 차이나지 않는다.프로젝트 소스 파일이 5MB 밖에 되지 않음
    • -t: origin → multi-stage 차이
  • node 기반 이미지에 멀티스테이지 빌드를 적용했을 때만큼 드라마틱한 변화는 없었음 (2.22GB → 215MB)
    • 여기는 정적파일도 포함되어있고 종속성을 설치 중복을 제거한 것도 크게 작용한듯
    • 프로젝트 소스 파일 자체가 클 때 훨씬 더 유효하게 작용할 것 같다.

기반 이미지를 바꾼 차이

openjdk:17-jdk-slim → eclipse-temurin:17.0.12_7-jre-noble

  • 458MB 338MB120MB 축소했다.
  • arm64 로는 openjdkj:alpine 이미지가 없어서 찾다가 발견한, arm64에서도 사용 가능한 jdk17 (알파인 기반)
    • alpine 기반 : 알파인 리눅스를 기반으로 한 이미지. Alpine Linux는 가볍고 보안에 중점을 둔 Linux 배포판으로, 작은 크기, 단순성, 효율성으로 유명.
  • -t: multi-stage → multi-stage-7 차이
    • 그 이전엔 계속 다른 이미지로 바꿔봄

결과

  • 원래 이미지 용량 463MB → 개선 이미지 용량 338MB
  • 약 125MB 축소

결론 (?)

  • 로컬에서 프로젝트 위에서 바로 복사할때는 크게 중요하지 않을듯(지금은)
    • 프로젝트 사이즈 자체가 커지면 더 의미있게 작용할 수도..
    • 사실 운영서버에서는 어차피 빌드는 도커에서가 아니라 아예 따로 하고 아티팩트만 복사함
  • 다만 운영 서버에서는 Dockerfile 과 아티팩트와 관련 파일들이 한꺼번에 있어서 COPY . . 를 할 경우 필요없는 파일까지 복사될듯
    • 스프링에서는 multi-stage-build 보다는 “필요한 아티팩트만 골라서 COPY” 하는 것이 더 중요할 것 같다.
    • 운영서버에서는 이미지 용량이 520MB -> 338MB  >> 약 200MB 축소
728x90