본문 바로가기
Framework and Tool/Docker

Docker - Mounts

by ocwokocw 2023. 6. 21.

- 출처: https://docs.docker.com/build/guide/mounts/

- Mounts

Cache mounts는 build 동안 사용될 영속 package cache를 지정할 수 있도록 해준다. 영속 cache는 특히 package manager를 사용해서 package들을 설치하는 경우 유용하다. Package를 위한 영속 cache를 갖고 있으면 layer를 다시 build 하더라도 신규 혹은 변경된 package 들만 download 하면 된다.

 

Cache mounts는 Dockerfile의 RUN 지시어와 함께 --mount flag를 사용하면 생성된다. Cache mount를 사용하기 위해서는 --mount=type=cache,target=<path> 형식으로 사용하면 되는데, <path>에 container에 mount할 cache directory 경로를 지정한다.


- Add a cache mount

Cache mount를 위해 사용할 target path는 사용하는 package manager에 의존한다. 이번 예제에서는 Go module 들을 사용한다. 이럴 경우 cache mount를 위한 target directory는 Go module cache가 기록되는 directory가 된다. Go module reference에 따르면 module cache의 기본경로는 $GOPATH/pkg/mod 이다. 

 

GOPATH는 사용자마다 다를 수 있기 때문에 환경변수를 확인해주도록 하자.

buildme % go env | grep GOPATH
GOPATH="/Users/user/go"

buildme % ls /Users/user/go/pkg/mod
cache							go.starlark.net@v0.0.0-20200821142938-949cc6f4b097
cloud.google.com					go.starlark.net@v0.0.0-20220328144851-d1966c6b9fcd
code.dny.dev						go.starlark.net@v0.0.0-20220816155156-cfacd8902214
...

 

cache mount 로 /Users/user/go/pkg/mod directory를 mount 하기 위해 프로그램을 컴파일하고 다운로드 하기 위해서 Dockerfile을 수정해주자.

buildme % cat Dockerfile
# syntax=docker/dockerfile:1
FROM golang:1.20-alpine as base
WORKDIR /src
COPY go.mod go.sum .
RUN --mount=type=cache,target=/Users/user/go/pkg/mod \
  go mod download -x
COPY . .

FROM base as build-client
RUN --mount=type=cache,target=/Users/user/go/pkg/mod \
  go build -o /bin/client ./cmd/client

FROM base as build-server
RUN --mount=type=cache,target=/Users/user/go/pkg/mod \
  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" ]

go mod download에 붙은 x flag는 download 실행 내역을 출력해주는데 cache mount가 어떻게 사용되는지 확인하기 위해서 추가하였다.


- Rebuild the image

image를 다시 빌드하기 전에 build cache를 제거해주자.

docker builder prune -af

아래 명령어로 image를 build 해주자. build가 끝난 후 log1.txt 파일 내역을 cat 해보면 go module download 내역을 확인할 수 있다.

buildme % docker build --target=client --progress=plain . 2> log1.txt

...

buildme % cat log1.txt
#1 [internal] load build definition from Dockerfile
#1 sha256:9f6b9d07702de9fe2f2b3042f0a52be299f5d236934e2cf924afaaf4661938b0
#1 transferring dockerfile: 624B done
#1 DONE 0.0s

...

#14 [base 4/5] RUN --mount=type=cache,target=/Users/user/go/pkg/mod   go mod download -x
#14 sha256:d66c3da08a74184711c5bbeeb0eaf94c0c4c7bcf5b19f1ca63812b6f01de4db3
#14 0.227 # get https://proxy.golang.org/github.com/containerd/console/@v/v1.0.3.mod
#14 0.227 # get https://proxy.golang.org/github.com/charmbracelet/bubbles/@v/v0.14.0.mod
#14 0.227 # get https://proxy.golang.org/github.com/charmbracelet/bubbletea/@v/v0.23.1.mod
#14 0.228 # get https://proxy.golang.org/github.com/atotto/clipboard/@v/v0.1.4.mod
#14 0.228 # get https://proxy.golang.org/github.com/charmbracelet/lipgloss/@v/v0.6.0.mod
#14 0.228 # get https://proxy.golang.org/github.com/aymanbagabas/go-osc52/@v/v1.0.3.mod
#14 0.487 # get https://proxy.golang.org/github.com/containerd/console/@v/v1.0.3.mod: 200 OK (0.260s)
#14 0.488 # get https://proxy.golang.org/github.com/go-chi/chi/v5/@v/v5.0.0.mod

...

cache mount가 사용되었는지 확인하기 위해서 program이 import하는 Go module 들중 임의의 하나를 선택해서 version을 변경해보자. module version이 변경되면 다음번 build 시에 새로운 의존성 version을 download 받을것이다. 만약 cache mount를 사용하지 않았다면 system은 모든 module을 다시 download 받는다. 하지만 cache mount를 사용했기 때문에 Go는 대부분의 module들을 재사용하며, /Users/user/go/pkg/mod directory에 없는 package version만 download 받는다.

 

application이 사용하는 chi package의 version을 갱신해주자.

buildme % docker run -v $PWD:$PWD -w $PWD golang:1.20-alpine \
> go get github.com/go-chi/chi/v5@v5.0.8
Unable to find image 'golang:1.20-alpine' locally
1.20-alpine: Pulling from library/golang
8c6d1654570f: Already exists
5a768fa670f5: Already exists
04e93037748d: Already exists
3bb6809feae6: Already exists
Digest: sha256:fd9d9d7194ec40a9a6ae89fcaef3e47c47de7746dd5848ab5343695dbbd09f8c
Status: Downloaded newer image for golang:1.20-alpine
go: downloading github.com/go-chi/chi/v5 v5.0.8
go: upgraded github.com/go-chi/chi/v5 v5.0.0 => v5.0.8

그리고 다시 build를 수행해주면 chi 관련 module만 download 받는것을 확인할 수 있다.

buildme % docker build --target=client --progress=plain . 2> log2.txt

buildme % cat log2.txt

...

#11 [base 4/5] RUN --mount=type=cache,target=/Users/user/go/pkg/mod   go mod download -x
#11 sha256:0dc5fbdbfe91a1fccf92f6115ec5a46c699336952b9c7fe48ce8034e09a05946
#11 0.180 # get https://proxy.golang.org/github.com/go-chi/chi/v5/@v/v5.0.8.mod
#11 0.256 # get https://proxy.golang.org/github.com/go-chi/chi/v5/@v/v5.0.8.mod: 200 OK (0.076s)
#11 0.258 # get https://proxy.golang.org/github.com/go-chi/chi/v5/@v/v5.0.8.info
#11 0.264 # get https://proxy.golang.org/github.com/go-chi/chi/v5/@v/v5.0.8.info: 200 OK (0.006s)
#11 0.266 # get https://proxy.golang.org/github.com/go-chi/chi/v5/@v/v5.0.8.zip
#11 0.273 # get https://proxy.golang.org/github.com/go-chi/chi/v5/@v/v5.0.8.zip: 200 OK (0.006s)
#11 DONE 0.3s

...

- Add bind moonts

아직 약간의 최적화를 더 할 수 있는 방법이 있다. 현재 module을 download 하기전에 go.mod와 go.sum 파일들을 COPY 지시어를 통해 가져오고 있다. 이 파일들을 container 파일 시스템으로 복사하는 대신 bind mount를 사용할 수 있다. bind mount는 container가 특정 파일들을 host로부터 직접 사용할 수 있게 해준다. 이를 적용하면 추가적인 COPY 지시어들을 사용하지 않아도 된다.

 

buildme % cat Dockerfile
# syntax=docker/dockerfile:1
FROM golang:1.20-alpine as base
WORKDIR /src

RUN --mount=type=cache,target=/Users/user/go/pkg/mod \
  --mount=type=bind,source=go.sum,target=go.sum \
  --mount=type=bind,source=go.mod,target=go.mod \
  go mod download -x

FROM base as build-client
RUN --mount=type=cache,target=/Users/user/go/pkg/mod \
  --mount=type=bind,target=. \
  go build -o /bin/client ./cmd/client

FROM base as build-server
RUN --mount=type=cache,target=/Users/user/go/pkg/mod \
  --mount=type=bind,target=.
  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" ]

위의 수정된 Dockerfile에서 go.sum, go.mod를 곧바로 import 하였다. 또한 build-client, build-server stage에서 현재 working directory를 mount 하기 위해 bind mount를 사용했다.

'Framework and Tool > Docker' 카테고리의 다른 글

Build Context  (0) 2023.08.12
Docker - build arguments  (0) 2023.06.28
Docker - Multi stage  (0) 2023.06.20
Docker image and layer  (0) 2023.06.18
Docker resource constraints  (0) 2023.06.18

댓글