[docker] build image size 줄이기

sujin·2022년 12월 10일
0

docker

목록 보기
1/3

docker size를 줄이는 방법

https://docs.docker.com/build/building/cache/ 다음 링크를 통해서 캐시 관리로 빌드를 최적화 하는 방법을 알아볼 수 있다.

  1. 가장 단순한 base image를 선택하기
    우리는 가장 처음으로 docker image를 만들기 위해서 dockerfile에 base image를 선택해서 등록한다. 이때 용량이 가장 적은 debian image를 선택해야한다. base image로 많은 기능을 포함하는 이미지를 선택했지만 그것을 거의 사용하지 않는다면 docker size만 들어나고 build 속도가 느려진다.
  • 리눅스 base iamge 중에서 alpine이 가장 용량이 작기 때문에 추천된다.
  1. size에 영향을 주는 명령을 결합하자.
    dockerfile이 build되는 과정을 이해했다면 layer가 기억되고 수정사항이 있을 때 캐시가 삭제되며 layer가 재생성 된다는 것을 알 것이다. 이때, run, add, copy 명령어를 수정하면 캐시가 삭제되며 다운스트림 레이어도 다시 build해야한다. 따라서 같은 명령어를 사용한다면, 한 줄에 모아서 작성할 필요가 있다.
     RUN echo "the first command"
     RUN echo "the second command"
  • 두개의 layer로 만들어져 서로 다른 캐시를 가지는 것보다 단일 명령으로 두 명령을 실행함으로써, 캐시를 하나로 공유해야한다.
    RUN echo "the first command" && echo "the second command"
    # or to split to multiple lines
    RUN echo "the first command" && \
       echo "the second command"
  1. 논리적 으로 순서를 배치하자.
    코드 변경으로 인해 다운스트림 레이어의 캐시를 무효화하며 다시 빌드하게 될 때, 종속성이 계속 다시 설치 된다면 비효율적일 것이다. 따라서 가장 먼저, 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 
  2. 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은 최종 단계의 이미지의 결과에 포함되지 않아서 이미지를 작고 안전하게 유지할 수 있다.

dockerfile에 적용해보기

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 실행시 바로 적용될 수 있는 명령어를 입력한다.

중간중간 기록한 것에 의하면,

  • 처음에는 golang:1.19를 base로함 ⇒ 1.62GB
  • 두번째는 golang:1.19를 base로한 builder ⇒ alpine:latest를 builder로 ⇒ and 650MB
  • 마지막 golang:1.19-alpine as builder ⇒ alpine:latest as runner로 ⇒ 27.3MB
    인것을 알 수 있었다.

사실 마지막 단계에서 yaml file을 copy해서 사용해서 runner의 4번 과정에서 copy하는 file이 더 있었지만, 없애고 docker-compose.yaml에서 volume으로 카피하려던 파일을 처리해서 저장하지 않도록 하였다.

docker image size
따라서 현재는 29.1MB의 용량을 차지한다.

0개의 댓글