- 출처: https://docs.docker.com/build/guide/multi-stage/
- Multi stage
Docker는 multi-stage라는 기능을 제공한다. 왜 Multi-stage를 사용해야할까?
- build를 병렬로 수행할 수 있다.
- 마지막 이미지 크기를 더 작게 만들 수 있다.
- Add stages
그렇다면 build stage란 무엇인가? build stage는 Dockerfile에서 FROM 지시어에 해당한다. 이전 Section(https://ocwokocw.tistory.com/302) 의 Dockerfile은 단일 stage에 해당하는데 최종 image가 프로그램을 컴파일하는데 사용되는 resource 때문에 용량이 큰것을 확인할 수 있다.
% docker images | grep buildme
buildme 5 c5650458b890 24 hours ago 410MB
buildme 4 9f43dd927be3 24 hours ago 410MB
buildme 3 9260d12d7690 24 hours ago 410MB
buildme 2 ad54f8e8cc3c 24 hours ago 410MB
buildme latest ad54f8e8cc3c 24 hours ago 410MB
Multi-stage build를 사용하면 build와 runtime 환경에 따라 서로 다른 기본 image를 선택할 수 있다. Build stage에서 최종 산출물만 runtime stage로 복사하면 된다.
아래와 같이 Dockerfile을 수정해보자.
% cat Dockerfile
# syntax=docker/dockerfile:1
FROM golang:1.20-alpine
WORKDIR /src
COPY go.mod go.sum .
RUN go mod download
COPY . .
RUN go build -o /bin/client ./cmd/client
RUN go build -o /bin/server ./cmd/server
FROM scratch
COPY --from=0 /bin/client /bin/server /bin
ENTRYPOINT [ "/bin/server" ]
추가된 stage (FROM 절) 에서 기본 image를 초소형인 scratch image로 변경하였다. scratch stage 에서는 이전 stage 에서 build된 binary 들만 복사해왔다.
% docker build -t buildme .
[+] Building 9.3s (19/19) FINISHED
...
% docker images | grep buildme
buildme latest 09db1cefa293 7 seconds ago 7.45MB
buildme 5 c5650458b890 24 hours ago 410MB
buildme 4 9f43dd927be3 24 hours ago 410MB
buildme 3 9260d12d7690 24 hours ago 410MB
buildme 2 ad54f8e8cc3c 24 hours ago 410MB
Docker build를 수행해보면 410MB -> 7MB 가량으로 줄어든것을 확인할 수 있다.
- Parallelism
Image의 크기를 줄였으니 multi-stage의 병렬성을 활용하여 build 속도를 향상시켜보도록 하자. 현재는 binary를 순차적으로 생성한다. 하지만 사실 client, server binary 생성시에 순서를 지켜야할 필요는 없다. 이 부분을 별도 stage로 분리하여 build 한 뒤 마지막 scratch stage 에서 각 stage의 binary 들을 복사해주면 된다. 이때 각 stage 들을 병렬로 실행시킬 수 있다.
client, server binary를 생성할 때 Go 의 compile 도구와 application 의존성이 필요하다. 이 부분은 공통된 image로 정의해서 재활용하면된다. 설명을 하는게 더 어려우니 곧바로 예제를 보도록 하자.
% cat Dockerfile
# syntax=docker/dockerfile:1
FROM golang:1.20-alpine as base
WORKDIR /src
COPY go.mod go.sum .
RUN go mod download
COPY . .
FROM base as build-client
RUN go build -o /bin/client ./cmd/client
FROM base as build-server
RUN go build -o /bin/server ./cmd/server
FROM scratch
COPY --from=build-client /bin/client /bin/
COPY --from=build-server /bin/server /bin/
ENTRYPOINT [ "/bin/server" ]
FROM base as build-client 부분과 FROM base as build-server 부분이 동시에 build 되는것을 확인할 수 있을것이다.
- Build targets
stage 추가로 image의 크기를 줄이고 parallelism 으로 속도도 향상 시켰다. 그런데 일반적으로 server와 client binary가 하나의 image에 있는게 맞는가?
하나의 Dockerfile 에서 여러 개의 image를 만들 수 있다. --target flag를 이용하면 build의 target stage를 지정할 수 있다. Dockerfile 은 이름이 붙지 않은 FROM scratch 절을 client와 server라는 이름이 붙은 stage로 수정하면 된다.
% cat Dockerfile
# syntax=docker/dockerfile:1
FROM golang:1.20-alpine as base
WORKDIR /src
COPY go.mod go.sum .
RUN go mod download
COPY . .
FROM base as build-client
RUN go build -o /bin/client ./cmd/client
FROM base as build-server
RUN go build -o /bin/server ./cmd/server
FROM scratch as client
COPY --from=build-client /bin/client /bin/
ENTRYPOINT ["/bin/client"]
FROM scratch as server
COPY --from=build-server /bin/server /bin/
ENTRYPOINT [ "/bin/server" ]
--target flag를 이용해서 build 해보자. --target을 client로 지정하고 build 하면 docker는 build-sever와 server stage가 필요하지 않으므로 건너뛴다.
% docker build -t buildme-client --target=client .
[+] Building 8.0s (18/18) FINISHED
... 0.0s
% docker build -t buildme-server --target=server .
[+] Building 6.6s (16/16) FINISHED
...
% docker images | grep buildme-
buildme-server latest 350b924e9acb 2 minutes ago 7.45MB
buildme-client latest ae5d71cc2e65 8 minutes ago 7.58MB
'Framework and Tool > Docker' 카테고리의 다른 글
Docker - build arguments (0) | 2023.06.28 |
---|---|
Docker - Mounts (0) | 2023.06.21 |
Docker image and layer (0) | 2023.06.18 |
Docker resource constraints (0) | 2023.06.18 |
Docker logging (0) | 2023.06.17 |
댓글