
멀티스테이지 빌드란?#
DockerFile 내에서 여러 단계를 정의한 후, 각 단계마다 따로 작업을 수행하고 최종 이미지에 최소한의 파일만 포함시키는 방식
예시#
실제 썼던 파일
원래 DockerFile#
FROM golang:1.23-alpine
WORKDIR /app
# go.mod와 go.sum 복사 후 의존성 다운로드
COPY go.mod go.sum ./
RUN go mod download
# 소스 코드 전체 복사 및 빌드
COPY . ./
RUN go build -o crawler .
# 실행 명령어
CMD ["./crawler"]혹시나 golang을 처음 보는 사람을 위해 설명하자면, go.mod ,go.sum은 package.json, build.gradle 등과 같이 라이브러리를 관리하는 파일이다.
멀티스테이지 빌드 DockerFile#
# 빌드 스테이지
FROM golang:1.23-alpine AS build
WORKDIR /app
# go.mod와 go.sum 복사 후 의존성 다운로드 및 빌드
COPY go.mod go.sum ./
RUN go mod download
# 소스 코드 전체 복사 및 빌드
COPY . .
RUN go build -o crawler .
#########################################################
#실제 도커파일❗❗
FROM alpine:latest
WORKDIR /app
# 빌드된 바이너리 복사
COPY --from=build /app/crawler /app/crawler
CMD ["/app/crawler"]멀티스테이징 빌드에서는 첫 스태이지에서 의존성을 다운받고 파일을 빌드, 두번째 스테이지에서 첫 스태이지의 결과물(실행파일)을 가져와 사용한다. 왜 귀찮게 이러는걸까?
최종 이미지 크기가 줄어든다 go를 예시로 들자면, 이미 라이브러리를 사용해서 빌드한 후, 라이브러리 파일은 더이상 필요하지 않다. 따라서, 꼭 필요한 결과물만 최종 단계로 가져올 수 있다. (+보안)
실험 결과 한번에 했을때 354MB, 멀티 스태이징 빌드시 18MB로 용량이 엄청 줄어들었다.
캐싱(이는 꼭 멀티 스테이징지 이점은 아님) 소스 코드는 개발 도중 계속 바뀌지만, 의존성은 드물게 바뀐다. 이미지 빌드시 의존성이 바뀌지 않았다면, 의존성을 가져오는 단계를 이전에 빌드했던 캐시를 통해 사용해 빌드 속도를 높일 수 있다.
명령어,입력 파일,환경이 완전히 동일하면, 캐시를 사용한다 따라서 자주 변경될수록 아래쪽에 위치하는 것이 효율적이다.
캐싱 예시#
첫번째 빌드시에는 모든 과정을 다 수행한다.
=> [stage-1 2/3] WORKDIR /app 0.0s
=> [build 2/6] WORKDIR /app 0.2s
=> [build 3/6] COPY go.mod go.sum ./ 0.0s
=> [build 4/6] RUN go mod download 1.0s
=> [build 5/6] COPY . . 0.0s
=> [build 6/6] RUN go build -o crawler . 4.2s
=> [stage-1 3/3] COPY --from=build /app/crawler /app/crawler 0.0s
=> exporting to image두번째 빌드부터는, 의존성을 가져오는 과정이 캐시를 통해 생략된다.
=> CACHED [build 2/6] WORKDIR /app #cahced
=> CACHED [build 3/6] COPY go.mod go.sum ./ #cached
=> CACHED [build 4/6] RUN go mod download #cahced
=> [build 5/6] COPY . .
=> [build 6/6] RUN go build -o crawler .
=> CACHED [stage-1 2/3] WORKDIR /app # 단순 설정이라 캐시사용
=> [stage-1 3/3] COPY --from=build /app/crawler /app/crawler
=> exporting to image
=> => exporting layer이 예제는 아주 간단한 경우지만, 만약 프론트는 node, 백엔드는 spring 등으로 이미지가 여러 단계를 거치게 되면 더 효율적일 것이다.👍
이거랑 커밋시 도커허브에 push하는 워크플로우 테스트하다보니 깃허브에서 메일이 30개정도 와있었다