Dockerfile layer cache는 왜 중요할까: 빌드가 느려지는 순서를 바꾸는 기준

Dockerfile layer cache는 왜 중요할까: 빌드가 느려지는 순서를 바꾸는 기준
Dockerfile의 명령 순서는 캐시를 재사용할 수 있는 범위를 크게 바꿉니다.

Dockerfile layer cache를 이해하면 Docker 빌드가 왜 갑자기 느려지는지 훨씬 쉽게 보입니다.

핵심은 자주 바뀌는 파일을 뒤로 보내고, 오래 걸리는 설치 layer를 최대한 재사용하는 것입니다. 이 글은 Docker 공식 문서를 기준으로 cache invalidation, COPY 순서, .dockerignore를 예제로 정리합니다.

Dockerfile layer cache 판단 기준 요약 카드
자주 바뀌는 파일을 너무 일찍 COPY하면 뒤쪽 layer cache가 함께 깨집니다.

Dockerfile layer cache를 먼저 빌드 흐름으로 보자

Docker build는 Dockerfile의 명령을 순서대로 처리합니다. 각 단계의 결과는 다음 단계의 기반이 됩니다. 이전과 같은 명령, 같은 입력이라면 Docker는 결과를 다시 만들지 않고 cache를 재사용할 수 있습니다.

FROM node:22-alpine
WORKDIR /app
COPY package.json package-lock.json ./
RUN npm ci
COPY . .
RUN npm run build

이 구조에서는 의존성 파일이 바뀌지 않는 한 `npm ci` layer를 재사용할 가능성이 커집니다. 반대로 소스 전체를 먼저 COPY하면 작은 코드 수정도 의존성 설치 cache를 깨기 쉽습니다.


왜 COPY . . 를 너무 일찍 쓰면 느려질까

초보 Dockerfile에서 가장 흔한 패턴은 처음부터 `COPY . .`를 실행한 뒤 의존성을 설치하는 것입니다. 문제는 프로젝트의 어떤 파일이든 바뀌면 그 COPY 단계의 입력이 바뀐다는 점입니다.

# 느려지기 쉬운 예
FROM node:22-alpine
WORKDIR /app
COPY . .
RUN npm ci
RUN npm run build

README, 테스트 파일, 소스 한 줄만 바뀌어도 `COPY . .` 이후의 단계가 다시 실행될 수 있습니다. 의존성 설치처럼 오래 걸리는 작업은 바뀌는 빈도가 낮은 파일 뒤에 두는 편이 유리합니다.


.dockerignore는 build context를 줄이는 도구

Docker build는 현재 디렉터리의 파일들을 build context로 보냅니다. 필요 없는 파일이 context에 들어가면 전송도 느려지고 cache 판단에도 불리해질 수 있습니다.

node_modules
.git
dist
coverage
.env

`.dockerignore`는 단순 정리 파일이 아닙니다. 이미지에 들어가면 안 되는 파일을 줄이고, 빌드 입력을 작게 유지하는 안전장치입니다.


언어별로 자주 쓰는 순서 감각

언어마다 파일 이름은 다르지만 원리는 비슷합니다. 의존성 선언 파일을 먼저 복사하고 설치한 뒤, 자주 바뀌는 소스 코드를 나중에 복사합니다.

  • Node.js: package.json, package-lock.json 먼저 COPY 후 npm ci
  • Python: pyproject.toml 또는 requirements.txt 먼저 COPY 후 pip install
  • Java/Gradle: build.gradle, settings.gradle, gradle wrapper 파일을 먼저 고려
  • Go: go.mod, go.sum 먼저 COPY 후 go mod download

cache만 보고 Dockerfile을 망치면 안 되는 이유

cache 최적화가 목적이더라도 보안과 재현성을 해치면 안 됩니다. secret을 이미지 layer에 남기거나, latest tag만 믿거나, 빌드 결과가 환경마다 달라지는 구조는 피해야 합니다.

  • secret은 Dockerfile에 직접 쓰지 않는다
  • base image tag는 프로젝트 정책에 맞게 고정한다
  • 설치 명령은 가능한 한 재현 가능하게 둔다
  • 캐시 최적화보다 이미지에 들어가는 파일 범위를 먼저 확인한다

실무 체크리스트

  1. 자주 바뀌지 않는 의존성 파일을 먼저 COPY한다
  2. 오래 걸리는 설치 명령은 최대한 cache가 살아남는 위치에 둔다
  3. 소스 전체 COPY는 의존성 설치 뒤로 미룬다
  4. .dockerignore로 불필요한 context와 민감 파일을 제외한다
  5. 빌드 속도와 이미지 안전성을 함께 점검한다

정리

Dockerfile layer cache를 이해할 때는 용어부터 외우기보다 이 도구가 어떤 경계를 나누려는지 먼저 보는 편이 좋습니다. 오늘 글의 기준은 후보를 좁히는 흐름, 반복 상태의 이동, 입력 검증의 책임, 빌드 입력의 변경 빈도, 읽기와 쓰기의 복잡도 차이를 구분하는 것입니다.

함께 보면 좋은 내부 글은 git rebase와 merge 차이, Spring Boot profile은 언제 나눠야 할까, C 프로젝트에서 Makefile은 왜 필요할까입니다. 외부 기준은 Docker Docs – Build cache, Docker Docs – Optimize cache usage in builds, Docker Docs – Dockerfile reference를 확인했습니다.

함께보면 좋은 글