https://docs.docker.com/build/building/cache/ 다음 링크를 통해서 캐시 관리로 빌드를 최적화 하는 방법을 알아볼 수 있다.
RUN echo "the first command"
RUN echo "the second command"
RUN echo "the first command" && echo "the second command"
# or to split to multiple lines
RUN echo "the first command" && \
echo "the second command"
논리적 으로 순서를 배치하자.
코드 변경으로 인해 다운스트림 레이어의 캐시를 무효화하며 다시 빌드하게 될 때, 종속성이 계속 다시 설치 된다면 비효율적일 것이다. 따라서 가장 먼저, copy 명령어를 통해서 종속성에 영향을 주는 패키지 관리 파일을 먼저 복사하면 좋을 것이다.
Copy . .
Run npm install
Run npm build
를 하게 된다면 프로젝트의 패키지 파일은 동일하지만 코드가 변경되었을 때, 계속해서 copy를 다시 하게 되기에 install, build가 반복된다.
COPY package.json yarn.lock . # Copy package management files
RUN npm install # Install dependencies
COPY . . # Copy over project files
RUN npm build # Run build
따라서, Copy 명령어를 통해서 패키지 파일을 먼저 설치하고 Run 명령어를 통해서 install을 진행한다. 이후, Copy . . 명령어를 프로젝트 코드를 복사하고 Run 명령어로 build를 진행히야한다.
진행했던 프로젝트에서도 copy를 한번에하고 패키지 파일을 다운로드하고 빌드하게 되어있었다.
# before
# COPY ./ .
# RUN go mod download && go mod verify
# after
COPY ./go.mod .
COPY ./go.sum .
RUN go mod download
Muli-Stage build
https://docs.docker.com/build/building/multi-stage/ 해당 링크를 참고해 mutistage build를 작성해보자.
dockerfile을 여러 개별 단계로 분할하여 빌드를 진행할 수 있습니다. 각 단계는 차례로 빌드되며 서로 연결되어 이미지를 생성하는데, 단계간의 종속성을 해결하여 효율적인 필드전략을 가져갑니다.
저의 경우, builder와 runner로 stage를 2개로 나눠서 dockerfile을 진행했지만 더 쪼갤 수 있습니다. 멀티스테이지 빌드는 From 명령어를 통해서 구분 지을 수 있다.
# stage 1
FROM alpine as git
RUN apk add git
# stage 2
FROM git as fetch
WORKDIR /repo
RUN git clone https://github.com/your/repository.git .
# stage 3
FROM nginx as site
COPY --from=fetch /repo/docs/ /usr/share/nginx/html
다음과 같이 git, fetch, site 이렇게 3가지 단계가 존재한다. 3단계가 진행될때 git은 최종 단계의 이미지의 결과에 포함되지 않아서 이미지를 작고 안전하게 유지할 수 있다.
FROM golang:1.19-alpine as builder
WORKDIR /report
COPY ./go.mod ./go.sum ./
RUN go mod download
COPY ./ .
RUN GOARCH=amd64 GOOS=linux go build -o report-project-linux cmd/main.go
FROM alpine:latest as runner
RUN apk --no-cache add tzdata
WORKDIR /app
COPY --from=builder /report/report-project-linux /report/static /report/template ./
EXPOSE 1323
CMD ["./report-project-linux"]
상황)
golang, echo framework를 사용해서 report-project를 만들었다.
1. cmd/main.go 명령어를 통해서 build 되는 프로젝트를 만들었다.
2. 컨테이너에서 사용할 포트를 1323으로 설정해서 사용하고 싶다.
3. CMD에 build한 binary file을 입력해서 docker image를 실행시키면 바로 binary로 build한 프로젝트가 떠지도록 만들고싶다.
size를 줄이며 dockerfile 만들기)
Builder : mulistage 중 stage 1
1. debian base image로 Linux base image alpine을 사용한다.
2. /report로 cloud workdir를 설정한다. (workdir에서 copy, run 명령어가 이루어진다)
3. 패키지 파일을 먼저 다운로드한다.
go.mod와 go.sum을 workdir로부터 ./ 경로에 넣는다
go mod를 download 받아서 패키지 파일을 다른 코드와 상관없이 미리 다운로드 받도록한다.
4. 빌드파일을 만든다.
빌드에 필요한 모든 코드를 복사하고 go binary build 명령어를 run을 통해 실행시켜 빌드파일을 만든다.
Runner : mulistage 중 stage 2
1. debian base image로 Linux base image alpine을 사용한다.
2. base image에 포함 되어있지 않던 패키지를 설치한다.
3. /app으로 cloud workdir를 설정한다.
4. builder image에 저장해놓은 binary build 파일과 static file, template file을 모두 app의 ./ 경로에 복사한다.
5. 1323 포트로 expose한다.
6. cmd에 image 실행시 바로 적용될 수 있는 명령어를 입력한다.
중간중간 기록한 것에 의하면,
사실 마지막 단계에서 yaml file을 copy해서 사용해서 runner의 4번 과정에서 copy하는 file이 더 있었지만, 없애고 docker-compose.yaml에서 volume으로 카피하려던 파일을 처리해서 저장하지 않도록 하였다.
따라서 현재는 29.1MB의 용량을 차지한다.