빌드 캐시 무효화

빌드 캐시 무효화 — 캐시가 언제 깨지고, 어떻게 살리는지

이미지를 빌드할 때 도커는 Dockerfile의 지시어를 적힌 순서대로 하나씩 실행해요. 그런데 매번 모든 레이어를 처음부터 만들면 느릴 수밖에요. 그래서 각 지시어마다 빌더는 이전에 캐시한 결과를 재사용할 수 있는지 먼저 확인해요. 이때 언제 캐시가 유효하고 언제 깨지는지 이해하면 빌드를 훨씬 빠르게 만들 수 있어요.

출처: Build cache invalidation | Docker Documentation

본문

기본 규칙

캐시 무효화의 기본 규칙은 생각보다 단순해요. 빌더는 먼저 베이스 이미지가 이미 캐시되어 있는지 확인하고, 그다음 지시어 하나하나를 캐시된 레이어와 비교해요. 어떤 캐시 레이어도 지시어와 정확히 일치하지 않으면 그 지점에서 캐시가 무효화돼요.

대부분 지시어는 Dockerfile 지시어와 대응하는 캐시 레이어를 비교하는 것만으로 충분해요. 다만 몇몇 지시어는 추가 확인이 필요해요.

  • ADDCOPY, 그리고 바인드 마운트가 포함된 RUN(RUN --mount=type=bind) 지시어는 파일 메타데이터로 캐시 체크섬을 계산해요. 캐시 조회 시 관련 파일 중 하나라도 메타데이터가 바뀌었으면 캐시가 무효화돼요.
  • 단, 파일의 수정 시각(mtime)은 캐시 체크섬 계산에 들어가지 않아요. 복사한 파일의 mtime만 바뀐 경우에는 캐시가 무효화되지 않아요.
  • ADD/COPY를 제외한 명령은 캐시 매칭을 결정할 때 컨테이너 안의 파일을 보지 않아요. 예를 들어 RUN apt-get -y update를 처리할 때 업데이트로 바뀐 파일을 확인하는 게 아니라, 명령 문자열 자체로 캐시 히트를 판단해요.

캐시가 한 번 무효화되면 그 뒤의 모든 Dockerfile 명령은 새 이미지를 만들고 캐시는 더 이상 쓰이지 않아요.

레이어가 여러 개인 빌드라면, 자주 바뀌지 않는 지시어부터 자주 바뀌는 지시어 순으로 배치하는 게 캐시 재사용에 유리해요.

WORKDIR과 SOURCE_DATE_EPOCH

WORKDIR 지시어는 캐시 유효성을 판정할 때 SOURCE_DATE_EPOCH 빌드 인자를 존중해요. 빌드 사이에 SOURCE_DATE_EPOCH를 바꾸면 WORKDIR과 그 뒤의 모든 지시어에서 캐시가 무효화돼요.

SOURCE_DATE_EPOCH는 빌드 중 생성되는 파일의 타임스탬프를 정해줘요. 만약 이 값을 Git 커밋 타임스탬프처럼 계속 변하는 값으로 두면 커밋할 때마다 캐시가 깨져요. 빌드 출처(provenance)를 추적하려는 목적이라면 이는 의도된 동작이에요. 하지만 재현 가능한 빌드를 만들면서 캐시가 자주 깨지는 걸 피하려면 고정된 타임스탬프를 쓰는 게 좋아요.

RUN 지시어

RUN 지시어의 캐시는 빌드 사이에 자동으로 무효화되지 않아요. Dockerfile에 curl을 설치하는 단계가 있다고 해볼게요.

RUN apt-get update && apt-get install -y curl

여기서 주의할 점이 있어요. 이렇게 해도 이미지의 curl 버전이 항상 최신이라는 뜻은 아니에요. 일주일 뒤 다시 빌드해도 같은 패키지를 얻게 돼요. RUN 지시어를 강제로 다시 실행하려면 다음 방법을 쓸 수 있어요.

  • 그 앞의 레이어가 바뀌도록 만들기
  • 빌드 전에 docker builder prune으로 빌드 캐시 비우기
  • --no-cache 또는 --no-cache-filter 옵션 쓰기

--no-cache-filter 옵션은 특정 빌드 스테이지만 골라 캐시를 무효화하고 싶을 때 써요. 스테이지명을 지정해서 그 스테이지만 다시 빌드하게 만들 수 있죠.

빌드 시크릿

빌드 시크릿의 내용물은 빌드 캐시에 포함되지 않아요. 따라서 시크릿 값을 바꿔도 캐시는 무효화되지 않아요.

시크릿 값을 바꾼 뒤 캐시를 강제로 깨고 싶다면, 시크릿과 함께 바꾸는 임의의 값을 가진 빌드 인자를 넘기면 돼요. 빌드 인자는 캐시 무효화에 영향을 주니까요. 그리고 시크릿의 ID나 마운트 경로 같은 속성은 캐시 체크섬에 참여해서, 바뀌면 캐시가 무효화돼요.

더 알아보기