Docker 멀티 스테이지 빌드

박우영·2023년 6월 17일
1

자바/코틀린/스프링

목록 보기
28/35

멀티 스테이지 빌드란

여러번 빌드를 거쳐 도커 이미지의 용량을 최소화 하는 것이라 생각하면 편할 것같다.
만약 여러가지가 필요할때 그때그때 전부 넣으면 docker image 용량이 계속 커지게 된다. java 기준 최소 500mb 부터 기가 단위가 넘 을 수도 있다.

직접 infra 를 구축하고 개발을 진행하는 입장에선 이러한 용량 하나하나 최적화 시켜두면 나중에 편할것이라 생각든다. 후에 부족한 용량을 줄이기 위해서 여러가지 노력을 해야할테니

결과

먼저 결과를 공유 하면 다음 사진과 같다.

  • mult = 멀티 스테이지 빌드 진행
  • nomult = 일반 dockerfile

위 사진처럼 600MB 와 180MB 는 결코 작은차이가 아니다. 특히 hdd 의 용량에 따라서도 서버 구축비용의 차이가 있으니 최적화를 시켜두면 결국 돈을 아끼는 셈이다.

특히 MSA를 한다면 여러개의 image 가 존재할텐데 점점 차이는 심해질거다.

Docker Multi Stage Build


일반 Dockerfile

#FROM openjdk:17.0.1-jdk-slim
#ARG JAR_FILE=build/libs/*.jar
#COPY ${JAR_FILE} app.jar
#ENTRYPOINT ["sh", "-c", "java ${JAVA_OPTS} ${JAVA_ACTIVE} -jar /app.jar"]

Multi Stage Build

FROM gradle:7.6.1-jdk17 AS build
COPY . /home/gradle/src
WORKDIR /home/gradle/src
ARG JAR_FILE=build/libs/*.jar

FROM openjdk:jre-alpine
COPY --from=build /home/gradle/src/build/libs/*.jar /app.jar
ENTRYPOINT ["sh", "-c", "java ${JAVA_OPTS} ${JAVA_ACTIVE} -jar /app.jar"]

일반 dockerfile 을 보면 단순히 jdk로 빌드하고 실행을 하는데 prod 환경에서 jar 파일로 실행할땐 jre만 있다면 충분하다.
따라서 멀티 스테이지 빌드 과정에서 jre 로 jar 파일을 실행하는 과정을 나눠준다.

이렇게 진행하면 불필요한 gradle 을 분리하고 필요한 정보만 이미지에 담기게 된다.

좀더 나아가...

이번엔 크롤링을 했던 프로젝트에서 Chrome 과 Chrome driver 또한 설치해야 하는데 기존의 용량은 1.42gb이다. 적지 않은 용량인데 이를 최적화 시켜보자.

1차 시도

# 빌드 스테이지
FROM gradle:7.6.1-jdk17 AS build
COPY . /home/gradle/src
WORKDIR /home/gradle/src
RUN gradle build

# Chrome과 ChromeDriver 설치 스테이지
FROM ubuntu:20.04 AS chromestage
RUN apt-get update && apt-get install -y \
  wget \
  unzip \
  curl \
  libssl-dev \
  libnss3

RUN wget https://dl.google.com/linux/direct/google-chrome-stable_current_amd64.deb
RUN apt -y install ./google-chrome-stable_current_amd64.deb

RUN wget -O /tmp/chromedriver.zip https://chromedriver.storage.googleapis.com/`curl -sS chromedriver.storage.googleapis.com/LATEST_RELEASE`/chromedriver_linux64.zip
RUN unzip /tmp/chromedriver.zip chromedriver -d /usr/bin

# 실행 스테이지
FROM mcr.microsoft.com/java/jre:17-zulu-ubuntu
COPY --from=build /home/gradle/src/build/libs/*.jar /app.jar
COPY --from=chromestage /usr/bin/chromedriver /usr/bin/chromedriver
COPY --from=chromestage /opt/google/chrome/google-chrome /opt/google/chrome/google-chrome
EXPOSE 8080
ENTRYPOINT ["sh", "-c", "java ${JAVA_OPTS} ${JAVA_ACTIVE} -jar /app.jar"]

정확한 이슈 파악은 못했지만 chrome 을 설치하는 문장에서 몇번을 시도하고 몇십분을 기다려도 진행이 되지않는 이슈발생

RUN apt -y install ./google-chrome-stable_current_amd64.deb

2차 시도

기존의 ubuntu 를 20.04 -> 22.03 로 변경

FROM ubuntu:20.04 AS chromestage

진행은 되지만 파일이 받아와 지지않음.

3차 시도

어쩔수없이 jre 환경에서 크롬 과 드라이버 를 설치 해서 진행 해보기로 결정

  • 멀티스테이지 전

  • 멀티스테이지 후

멀티스테이지 후에 크롬 이랑 드라이버를 설치해서 그런지 드라마틱한 변화는 없었다..

최초 계획했던 내용은 chrome 과 driver 를 별도의 os 에서 받아오고 멀티 스테이지를 진행하려 했으나 인터넷 이슈등으로 실패함.. 호스트에 설치하여 마운트를 하는 방법을 선택을 해봐야겠다.

회고


개발자로써 개발만 신경쓰고 네트워크 환경에 집중하는것도 좋지만 약간의 디테일로 큰 효과를 얻을 수있다면 안배울 이유가 없다고 생각합니다. ROI 로써 생각을해도 이정도의 과정은 어려운 수준은 아니라고 생각들어 노력대비 리턴이 큰 학습 이었다고 생각합니다.

2개의 댓글

comment-user-thumbnail
2024년 3월 12일

마침 최적화가 필요했는데 깔쌈한 정보 감사합니다

1개의 답글