일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
31 |
- docker
- 인프라
- IntelliJ
- 프로그래머스
- bfs
- 스프링
- 자료구조
- Java
- 백엔드
- Linux
- dfs
- HashMap
- HTTP
- 스프링 부트
- spring
- 구현
- 해시맵
- 도커
- 배열
- 스타트업
- 코딩테스트
- 해결
- 문자열
- 인텔리제이
- 이직
- 구름LEVEL
- 개발자
- 스프링부트
- spring boot
- 주니어
- Today
- Total
마이의 개발 블로그
[Docker] 도커 멀티스테이지(multi-stage) 빌드, 왜 필요할까? 본문
배경
도커를 사용해 이미지를 빌드하다보면 "내 작고 소중한 프로그램에 비해 이미지 용량이 왜이렇게 크지?"라는 의문을 품는 경우가 발생합니다. 분명 내 프로그램은 'Hello, World' 출력 하나 해줄 뿐인데, 이미지 용량이 1GB를 가뿐히 넘긴다는 건 용납하기 어렵죠. 이럴 때 멀티스테이지 빌드를 활용하면 용량 최적화뿐만 아니라 다양한 이점을 가져갈 수 있는데요. 오늘은 멀티스테이지 빌드를 하는 방법과 멀티스테이지 빌드가 왜 필요한지에 대해 알아보도록 하겠습니다.
멀티스테이지 빌드(multi-stage build)란?
이름대로 빌드를 여러 단계로 나누어 하는 빌드 방식을 말합니다. 아래는 기본적인 도커 빌드 예시인데요:
FROM openjdk:21-ea-jdk-slim
WORKDIR ...
COPY ...
RUN ...
이런 식으로 싱글스테이지 빌드를 수행하게 되면 결국 이미지(openjdk:21-ea-jdk-slim)의 한계를 벗어날 수 없다는 단점이 발생합니다. 멀티스테이지 빌드는 빌드용 이미지와 실행용 이미지를 분리시켜 최종 이미지에는 필요한 파일만 남기는 것을 목표로 합니다. 예를 들어, 스프링 프레임워크의 빌드 단계에서는 jdk와 gradle 또는 maven이 포함된 이미지를 사용하여 빌드를 수행하고, 그 결과물인 jar/war파일만 jre 실행용 이미지에 복사하여 프로그램을 구동시킬 수 있습니다.
멀티스테이지 빌드의 장단점
장점
1. 이미지 용량 감소
- 빌드에서만 필요한 각종 도구, 의존성, 캐시등이 제외되어 최종 이미지 용량을 감소시킬 수 있습니다.
2. 보안성 향상
- 프로그램 구동에 필요없는 파일이나 스크립트를 제거하여 잠재적인 보안 취약점을 줄일 수 있습니다.
3. 빌드 환경 안정성 확보
- 빌드 환경과 실행 환경을 명확하게 나눔으로써 로컬 환경 의존도를 줄일 수 있습니다.
- 환경 변수, 로케일, 타임존, 캐시 등을 일관되게 유지할 수 있습니다.
4. 커스텀 이미지 적용 가능
- 기업에 따라 커스텀 이미지 기반 빌드가 필요한 경우가 있습니다. 예를 들어 CI/CD 파이프라인에 Tomcat 버전 + Maven 버전 + 특수 라이브러리 등의 조건들이 갖춰져야만 하는 경우, 여기에 맞는 빌드스테이지용 커스텀 이미지를 CI 파이프라인에 적용할 수 있을 것입니다.
단점
1. 도커 파일이 명령어가 싱글스테이지 빌드 방식보다는 길어집니다.
2. 런타임 스테이지에서 운영에 필요한 디버깅 도구(bash, curl 등)의 별도 설치 작업이 필요할 수 있습니다.
멀티스테이지 빌드 방법 예시
# build stage
FROM openjdk:21-ea-jdk-slim AS build
WORKDIR /app
COPY . .
# 윈도우 개행문자 관련 처리
RUN apt-get update && apt-get install -y dos2unix
RUN dos2unix gradlew
RUN ./gradlew bootJar
# runtime stage
FROM alpine/java:21-jre AS runtime
WORKDIR /app
# 필수패키지 설치
RUN apk add --no-cache libc6-compat libstdc++ && \
rm -rf /var/cache/apk/*
COPY --from=build /app/build/libs/demo.jar /app/demo.jar
COPY --from=build /app/extra /app/extra
EXPOSE 8080
CMD ["java", "-jar", "demo.jar"]
- 빌드 스테이지: openjdk 이미지를 기반으로 "./gradlew bootJar"를 수행하여 demo.jar 파일을 생성합니다.
- 런타임 스테이지: alpine jre 이미지를 기반으로 빌드 스테이지 이미지 'build'에서 빌드 결과물 demo.jar 등을 복사해옵니다.
Note
- 윈도우 gradlew를 멀티스테이지 빌드에 활용할 경우 CRLF 문제가 발생할 수 있어 별도 처리가 필요합니다(상단 예시 참조).
'개발지식 > 인프라' 카테고리의 다른 글
[Nginx] 서버 버전 정보 미노출, 필요한 이유와 적용 방법 (4) | 2025.08.14 |
---|---|
[Linux] cgroups를 사용해 도커 사용 자원 제한하기 (0) | 2024.12.10 |
[Network] Docker Compose와 Nginx를 이용한 수평 스케일(scale-out)과 로드 밸런싱(Load Balancing) (2) | 2024.12.10 |
[Docker] 도커(Docker) 삭제 후 도커 네트워크 인터페이스를 삭제해야하는 경우 명령어(RHEL 8.8) (0) | 2024.11.22 |
[Linux] 도커(Docker) 동작 중 firewalld를 켜면 서비스가 동작하지 않는 현상(RHEL 8.8) (0) | 2024.11.22 |