: 하나의 Dockerfile 내에서 여러 개의 FROM을 사용하여 빌드 환경과 실행 환경을 분리하는 기법
빌드 과정과 실행 과정 분리
→ 빌드용 이미지에는 많은 개발 도구가 필요하지만, 실행용 이미지는 최대한 가벼운 것이 좋음.
컨테이너 크기 최적화
→ 빌드가 끝난 후 불필요한 파일(예: 소스코드, 빌드 도구)을 제외하여 작고 빠른 컨테이너를 만들 수 있음.
Docker는 레이어(layer) 기반으로 이미지를 빌드하며, 각 RUN, COPY, ADD 등의 명령어가 새로운 레이어를 생성한다.
이미 캐시된 레이어가 있으면 다시 실행하지 않고 그대로 재사용하여 빌드 속도를 단축할 수 있다.
FROM openjdk:23 AS builder
# 1️⃣ 애플리케이션 소스 코드 복사 (자주 변경됨)
COPY . /app
WORKDIR /app
# 2️⃣ 패키지 설치 및 빌드 (자주 변경되지 않음)
RUN ./gradlew build
❌ 문제점
소스 코드(COPY . /app)가 위쪽에 배치되어 있기 때문에, 코드가 변경될 때마다 모든 이후 레이어가 다시 빌드된다.
즉, gradlew build가 매번 실행되어 비효율적이다.
FROM openjdk:23 AS builder
# 1️⃣ 의존성 설치 (자주 변경되지 않음)
WORKDIR /app
COPY build.gradle settings.gradle ./
RUN ./gradlew dependencies
# 2️⃣ 애플리케이션 소스 코드 복사 (자주 변경됨)
COPY src ./src
RUN ./gradlew build
✔ gradlew dependencies 실행 결과가 캐시되므로 소스 코드만 변경되었을 때 전체를 다시 빌드하지 않는다.
✔ COPY src ./src가 가장 아래쪽에 위치하여, 코드 변경 시 최소한의 레이어만 다시 빌드된다.
변하지 않는 코드(의존성 설치, 환경 설정)는 위쪽, 자주 변경되는 코드(소스 코드, 설정 파일)는 아래쪽에 배치해야 한다.
이 원칙을 따르면 빌드 속도를 크게 단축할 수 있다. 🚀