이거 모르는 분 꽤 많더라. RUN --mount=type=cache 한 줄로 npm/pip install 시간을 절반 이하로 줄일 수 있다. 그런데 실무에서 제대로 세팅한 걸 보기는 의외로 드물다.
뭐가 문제냐
기본 Dockerfile로 이미지 빌드하면, COPY package*.json ./ 다음에 RUN npm ci 하는 패턴을 쓸 거다. 여기서 lock 파일이 바뀌면 그 아래 레이어 캐시가 전부 무효화되고, npm ci가 처음부터 다시 돈다. 패키지 하나 추가했을 뿐인데 400개 다운로드를 다시 하는 셈이다.
우리 팀은 프론트 모노레포에 workspace 20개가 물려 있는데, 어떤 워크스페이스 하나만 라이브러리 하나 올려도 CI 이미지 빌드가 3분 넘게 걸렸다. 노드 하나 이슈면 그러려니 하는데 매번 그러니 좀 짜증이 났다.
이 한 줄이면 된다
Dockerfile 맨 위에 syntax 지시자 하나, RUN 라인 하나 바꿔주면 끝이다.
# syntax=docker/dockerfile:1.7
FROM node:20-alpine
WORKDIR /app
COPY package*.json ./
RUN --mount=type=cache,target=/root/.npm,sharing=locked \
npm ci --prefer-offline --no-audit
COPY . .
RUN npm run build
핵심은 --mount=type=cache. /root/.npm은 npm이 다운로드한 tarball을 캐시하는 위치인데, 이 mount는 최종 이미지에는 포함되지 않고 빌드 사이에만 남는다. --prefer-offline 플래그를 붙여야 npm이 캐시를 최우선으로 쓴다.
pip도 똑같다.
RUN --mount=type=cache,target=/root/.cache/pip,sharing=locked \
pip install -r requirements.txt
Go나 Rust는 target을 각각 /root/.cache/go-build, /usr/local/cargo/registry로 맞추면 된다.
CI에서 캐시가 날아가는 문제
이게 로컬에선 잘 도는데 CI에선 헛돌 때가 있다. 이유는 단순한데, ephemeral runner는 매번 새 컨테이너로 뜨니까 이전 빌드의 cache mount가 없다. 그래서 --mount=type=cache만 붙여놓고 "왜 안 빨라지지?" 하는 케이스가 많다.
해결은 buildx의 --cache-to/--cache-from으로 레지스트리에 별도 캐시를 export/import 하는 것. GitHub Actions면 이렇게:
- uses: docker/build-push-action@v5
with:
cache-from: type=registry,ref=myrepo/app:buildcache
cache-to: type=registry,ref=myrepo/app:buildcache,mode=max
mode=max가 중요하다. 기본값 min은 최종 stage만 push하는데, cache mount 내용을 살리려면 max로 모든 중간 레이어를 export 해야 한다.
실제로 얼마나 빨라지나
우리 파이프라인 기준으로:
- 프론트 이미지 빌드: 3분 20초 → 1분 5초
- Python 서비스 이미지: 45초 → 8초 (deps 변경 없을 때)
- deps 변경 시에도 새 패키지만 다운로드해서 시간 차이 크게 안 남
--cache-to 세팅 안 되어 있으면 이런 효과 못 본다는 게 함정이다. 로컬 dev에서 반복 빌드할 때는 자동으로 이득이지만, CI 이득 보려면 registry cache 세팅까지 같이 가야 한다.
몇 가지 주의점
sharing=locked 옵션은 병렬 빌드 시 캐시 lock을 잡는 옵션이다. 기본값이 shared인데, 이 경우 두 빌드가 같은 캐시에 동시에 쓰면 깨질 수 있다. 안전하게 가려면 locked. 속도 조금 손해 보지만 재현성이 낫다.
그리고 # syntax=docker/dockerfile:1.7 이 지시자는 반드시 파일 첫 줄에 있어야 한다. 주석이라도 그 위에 있으면 파싱이 안 된다. 1.7 대신 그냥 1로 해도 최신 지원되는 버전을 알아서 잡는다.
혹시 Kaniko나 Buildah 같은 rootless 빌더 쓰는 분들, cache mount 지원 여부는 각 도구 문서 확인하시길. Kaniko는 최근에 지원 들어갔는데 syntax가 살짝 다르다.
--mount=type=cache 한 줄로 CI 파이프라인이 눈에 띄게 조용해진다. 아직 안 붙이신 분은 오늘 커밋 하나 만들어 두시길.
'IT > 컨테이너' 카테고리의 다른 글
| Dockerfile COPY --link, 다들 쓴다는데 진짜 좋을까 (0) | 2026.06.28 |
|---|---|
| containerd config_path, 이거 모르는 분 꽤 많더라 (0) | 2026.06.21 |
| BuildKit cache mount으로 CI 빌드 시간 7분 -> 40초 만든 가이드 (0) | 2026.06.21 |
| containerd NRI, 사실 내부적으로는 이렇게 돌아간다 (1) | 2026.06.11 |
| BuildKit cache mount 제대로 쓰는 법 — Rust/Node CI 빌드 시간을 절반으로 (0) | 2026.06.08 |