Docker BuildKit cache mount, 빌드를 어떻게 빠르게 하나

BuildKit cache mount(RUN --mount=type=cache)는 이미지 레이어 캐시와 별도로, 패키지 매니저·컴파일러용 디렉터리를 빌드 간에 누적 유지합니다. 레이어가 깨져도 이미 받은 패키지를 다시 받지 않아도 됩니다.

이 글은 공식 Dockerfile RUN --mount=type=cache와 Optimize cache 문서의 cache mount만 다룹니다. 레이어 순서·.dockerignore 입문은 다루지 않습니다.

type=cache는 어디에 쓰나?

한 줄 답: RUN--mount=type=cache,target=<패키지 캐시 경로>를 붙여 npm·Go·pip·apt 설치 단계에 씁니다.

공식 예:

# syntax=docker/dockerfile:1
FROM node:latest
WORKDIR /app
COPY package.json package-lock.json ./
RUN --mount=type=cache,target=/root/.npm \
    npm ci
COPY . .

Go:

RUN --mount=type=cache,target=/go/pkg/mod \
    --mount=type=cache,target=/root/.cache/go-build \
    go build -o /app/hello

Apt(배타 접근 필요):

RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \
    --mount=type=cache,target=/var/lib/apt,sharing=locked \
    apt-get update && apt-get --no-install-recommends install -y gcc

캐시 디렉터리 내용은 빌더 호출 사이에 남지만 명령 캐시를 무효화하지 않습니다. GC가 지우거나 다른 빌드가 덮어쓸 수 있으므로, 캐시가 비어 있어도 빌드가 성공해야 합니다. 최종 이미지에는 mount 내용이 들어가지 않습니다.

id/sharing은?

한 줄 답: id로 서로 다른 캐시 버킷을 나누고, sharingshared(기본)·private·locked 중 고릅니다.

옵션의미
id캐시 식별자. 생략 시 target 값. 같은 target이라도 스테이지·언어별로 나누려면 id=gomod처럼 지정
target컨테이너 안 마운트 경로(필수)
sharing=shared여러 작성자가 동시에 사용(기본). npm/Go에 흔함
sharing=locked두 번째 작성자는 첫 작성이 끝날 때까지 대기. apt처럼 락 파일이 있는 도구
sharing=private동시 작성 시 새 마운트를 만듦
ro / readonly읽기 전용
uid / gid / mode새 캐시 디렉터리 소유·권한

같은 target을 쓰더라도 Go 모듈과 npm을 한 버킷에 섞지 않도록 id를 분리하는 편이 안전합니다. 멀티 스테이지에서 apt를 병렬로 돌리면 sharing=shared일 때 lock 충돌이 나므로 공식 예처럼 sharing=locked를 씁니다.

CI에서 주의점은?

한 줄 답: 로컬 BuildKit 캐시 마운트는 ephemeral 러너에 남지 않으니, 필요하면 --cache-from/--cache-to 외부 캐시와 병행하고, apt는 locked·클린 옵션을 맞춥니다.

주의점:

  1. 러너가 매번 새 VM이면 type=cache 마운트도 빌더와 함께 사라질 수 있습니다. GitHub Actions 등에서는 registry/GHA 백엔드로 레이어 캐시를 내보내고(cache-from / cache-to), Dockerfile 안에서는 여전히 cache mount로 패키지 다운로드를 줄입니다.
  2. 병렬 잡이 같은 id를 쓰면 apt는 sharing=locked로 직렬화하거나 id를 잡마다 나눕니다.
  3. 빌드는 캐시 없이도 통과해야 합니다. 문서: “another build may overwrite the files or GC may clean it”.
  4. 시크릿을 cache mount에 쓰지 않습니다. 토큰은 type=secret mount를 씁니다.
  5. # syntax=docker/dockerfile:1로 프론트엔드를 고정하면 --mount 문법을 안정적으로 씁니다.

로컬에서 효과를 보려면 BuildKit이 켜져 있어야 합니다(DOCKER_BUILDKIT=1 또는 buildx).

마무리

빌드를 빠르게 하려면 RUN --mount=type=cache,target=… → ② id/sharing 선택(apt=locked) → ③ CI는 외부 캐시와 병행하면 됩니다. 상세는 RUN —mount=type=cache·Optimize cache usage를 참고하시기 바랍니다.

출처