컨테이너 용어 사전
이미지cache invalidation · 레이어 캐시 · cache mount

빌드 캐시

COPY/ADD는 파일 메타데이터 체크섬, RUN은 명령 문자열만 본다. 한 번 깨지면 아래 전부 재실행된다.

빌드가 빨랐다 느렸다 하는 이유. 명령 종류마다 판정 기준이 다르다.

  • COPY · ADD — 파일 메타데이터로 체크섬을 계산해 비교한다

    • mtime(수정 시각)은 계산에 넣지 않는다
    • touch 만 해서는 캐시가 깨지지 않는다
  • RUN — '명령 문자열' 만 본다

    • RUN apt-get update 로 실제 무엇이 바뀌었는지는 보지 않는다
    • 문자열이 같으면 몇 달 전 캐시를 그대로 쓴다
  • 그리고 캐시가 한 번 깨지면 그 아래 모든 레이어가 다시 실행된다

그래서 순서가 전부다

# ✗ 소스가 한 줄만 바뀌어도 의존성을 다시 받는다
COPY . .
RUN npm ci

# ✓ 의존성 목록이 바뀔 때만 다시 받는다
COPY package.json package-lock.json ./
RUN npm ci
COPY . .

원칙 — 자주 바뀌는 것을 뒤에 둔다

거의 안 바뀜베이스 이미지 · 시스템 패키지
가끔 바뀜의존성 목록 (package.json · pom.xml · go.mod)
자주 바뀜애플리케이션 소스

apt-get update 의 함정

# ✗ update 가 캐시되면 낡은 인덱스로 install 한다
RUN apt-get update
RUN apt-get install -y curl

# ✓ 한 레이어로 묶는다
RUN apt-get update && apt-get install -y --no-install-recommends curl \
 && rm -rf /var/lib/apt/lists/*

update 와 install 이 다른 레이어면

  • install 줄만 바뀔 때 update 는 캐시를 쓴다
  • 몇 달 전 패키지 인덱스로 설치를 시도한다 → 404 나 낡은 버전

정리(rm -rf)도 같은 레이어에서 해야 크기가 준다

캐시 마운트 — 레이어에 굽지 않는다

# syntax=docker/dockerfile:1
RUN --mount=type=cache,target=/root/.m2 \
    ./mvnw -B package -DskipTests

의존성 캐시를 '빌드 사이에 유지되는 별도 저장소' 에 둔다

  • 이미지가 커지지 않는다
  • COPY 순서로 캐시를 지켜야 하는 부담이 줄어든다

대상 예 — /root/.m2 · /root/.gradle · ~/.npm · /go/pkg/mod · ~/.cache/pip

CI 에서 캐시가 안 먹을 때

  • 러너가 매번 새 머신이면 로컬 캐시가 없다

  • 레지스트리 캐시를 쓴다

    • docker buildx build \
      • --cache-from type=registry,ref=myrepo/cache \
      • --cache-to type=registry,ref=myrepo/cache,mode=max

또 하나 — 빌드 컨텍스트에 매번 바뀌는 파일이 들어가면 캐시가 깨진다 (타임스탬프 파일 · 빌드 번호) → .dockerignore 로 제외

캐시가 깨졌는지 확인하는 법

BuildKit 은 각 단계에 CACHED 를 표시한다

  #8 [4/6] RUN npm ci
  #8 CACHED                    ← 캐시 적중
  #9 [5/6] COPY . .
  #9 DONE 0.3s                 ← 여기서 깨졌다

어느 단계부터 CACHED 가 사라지는지 보면 원인이 바로 나온다 빌드가 느릴 때 로그를 먼저 읽는 이유다

캐시가 오히려 문제가 될 때

  • 베이스 이미지의 보안 패치가 반영되지 않는다

    • FROM 은 태그가 같으면 로컬 캐시를 쓴다
    • 주기적으로 docker build --pull 로 베이스를 다시 받는다
    • CI 는 --pull 을 기본으로 두는 편이 안전하다
  • 캐시가 디스크를 먹는다

    • docker system df -v 의 Build Cache 항목
    • docker builder prune --filter until=168h

면접 함정

  • "파일을 안 바꿨으니 캐시가 유지된다" → 앞 레이어가 깨지면 아래는 전부 재실행이다.
  • "RUN도 결과를 비교한다" → 명령 문자열만 본다. 그래서 apt-get update가 낡는다.

함께 보면 좋은 용어

노트에서 맥락과 함께 보기 — 이미지와 레이어 — 빌드가 빨랐다 느렸다 하는 이유