멀티모듈에서의 Dockerfile 최적화하기

twonezero·2024년 11월 16일
0
post-thumbnail

기존 프로젝트에서 작성했던 Dockerfile을 통해 이미지를 빌드하면 속도 저하 및 많은 용량에 대한 문제가 있어, 그에 대한 해결을 공유하고자 합니다.

프로젝트 구성

프로젝트에 대한 구성은 아래의 글에서 확인할 수 있습니다.

기존 Dockerfile

아래는 기존의 Dockerfile 입니다. 루트 컨텍스트에서 Dockerfile 의 빌드가 실행되게 하여, 각 서비스 모듈이 의존하는 다른 모듈들을 참조하기 위해 모든 파일을 복사하여 빌드를 수행합니다.

# Stage 1: Build the application
FROM gradle:8.10.1-jdk17 AS build

WORKDIR /app

# ARG로 전달된 파일 디렉터리 설정
ARG FILE_DIRECTORY

# 파일 복사
COPY $FILE_DIRECTORY /app

# Reservation 모듈만 빌드
RUN ./gradlew :reservation:clean :reservation:build -x test --no-daemon

FROM openjdk:17-jdk-slim

COPY --from=build /app/reservation/build/libs/*SNAPSHOT.jar /app.jar

# JAR 파일 실행
CMD ["java", "-jar", "/app.jar"]

문제점

현재 Dockerfile 의 문제점은 아래와 같습니다.

1. 모든 파일을 복사

  • FILE_DIRECTORY 는 루트 컨텍스트의 docker-compose.yml 에서 넘겨준 인자로, 루트 위치를 넘겨줍니다.
  • COPY $FILE_DIRECTORY /app 를 통해 루트 내의 하위 파일들을 모두 복사하므로 매우 비효율적입니다.

2. JDK 베이스 이미지 사용

  • jar를 실행하기 위한 런타임 환경만 있으면 되는데, 불필요하게 Jdk 를 사용하고 있습니다. 이는 이미지를 무겁게 만듭니다.

개선된 Dockerfile

아래는 reservation 모듈의 Dockerfile 예시입니다.

# Stage 1: Build the application
FROM gradle:8.10.1-jdk17 AS build

WORKDIR /app

# ARG로 전달된 파일 디렉터리 설정
ARG FILE_DIRECTORY

# 필요한 모듈만 복사
COPY $FILE_DIRECTORY/settings.gradle /app/settings.gradle
COPY $FILE_DIRECTORY/gradle /app/gradle
COPY $FILE_DIRECTORY/gradlew /app/gradlew
COPY $FILE_DIRECTORY/reservation /app/reservation
COPY $FILE_DIRECTORY/build.gradle /app/build.gradle

COPY $FILE_DIRECTORY/GlowGrow-common/build.gradle /app/GlowGrow-common/build.gradle
COPY $FILE_DIRECTORY/GlowGrow-common/src /app/GlowGrow-common/src

COPY $FILE_DIRECTORY/GlowGrow-security/build.gradle /app/GlowGrow-security/build.gradle
COPY $FILE_DIRECTORY/GlowGrow-security/src /app/GlowGrow-security/src

COPY $FILE_DIRECTORY/GlowGrow-kafka/build.gradle /app/GlowGrow-kafka/build.gradle
COPY $FILE_DIRECTORY/GlowGrow-kafka/src /app/GlowGrow-kafka/src

# Gradle 빌드 캐시 사용을 위한 외부 의존성 다운로드
RUN ./gradlew :reservation:dependencies --no-daemon

# Reservation 모듈만 빌드
RUN ./gradlew :reservation:clean :reservation:build -x test --no-daemon

# Stage 2: Run the application
FROM eclipse-temurin:17-jre-alpine

# 빌드된 JAR 파일 복사
COPY --from=build /app/reservation/build/libs/*SNAPSHOT.jar /app.jar

# JAR 파일 실행
CMD ["java", "-jar", "/app.jar"]

1. 필요한 모듈만 복사하기

  • 필요한 모듈들만 복사하도록 하여 빌드 시간을 단축시키고 이미지 크기를 줄일 수 있습니다.

2. JDK 대신 JRE 사용

  • JAR 파일만 실행할 거라면 JRE 이미지를 사용하는 것이 더 적합합니다.
  • JRE 이미지는 JDK보다 훨씬 가벼우므로 Docker 이미지 크기를 줄일 수 있습니다.

3. 멀티스테이지 빌드 최적화

  • Gradle 빌드에서 종속성 모듈을 처리할 때 전체 프로젝트를 복사하기보다 필요한 부분만 복사하여 빌드를 진행할 수 있습니다.
  • 이 부분은 Gradle의 캐시를 활용하는 방식으로 최적화할 수 있습니다.

비교

개선 전 크기

개선 후 크기

개선 전과 후가 거의 1.7 배의 차이를 보이므로 유의미한 수정이라고 할 수 있겠습니다.

사실 속도에 있어서는, 기존 빌드 속도가 느린 편은 아니며 현재 GithubActions 를 통해 Docker 빌드 스테이징을 수행하므로, 로컬 캐싱을 사용할 수 없고, GithubActions에서 캐싱을 진행해야 합니다. 이를 위해 Docker에서 제공하는 플러그인을 사용할 수 있습니다. 아래의 글을 참고하여 각자 구현해 보면 좋을 것 같습니다.

profile
소소한 행복을 즐기는 백엔드 개발자입니다😉

0개의 댓글