Summary#
Docker 멀티스테이지 빌드는 빌드 도구·소스·개발 의존성을 최종 이미지에서 분리해 런타임 이미지를 작고 단순하게 만드는 패턴이다. 핵심은 COPY --from=<stage>로 필요한 산출물만 최종 이미지에 복사하고, BuildKit RUN --mount=type=cache로 npm/pip 캐시를 빌드 중 재사용하되 최종 이미지에는 포함하지 않는 것이다.
Outcome#
Python 멀티스테이지 예시#
# syntax=docker/dockerfile:1
FROM python:3.12-slim AS builder
WORKDIR /app
COPY requirements.txt .
RUN --mount=type=cache,target=/root/.cache/pip \
pip install --prefix=/install -r requirements.txt
FROM python:3.12-slim AS runtime
# python:3.12-slim에는 앱 전용 nonroot 사용자가 기본 제공되지 않으므로 직접 생성한다.
RUN groupadd -r appuser && useradd -r -u 1001 -g appuser appuser
WORKDIR /app
COPY --from=builder /install /usr/local
COPY src/ /app/src/
USER appuser
CMD ["python", "-m", "app"]
Node.js + distroless 예시(Node 22 LTS 기준)#
빌드에는 보통 TypeScript, bundler, test/build tool 같은 devDependencies가 필요하다. 따라서 build deps와 runtime production deps를 분리한다.
# syntax=docker/dockerfile:1
FROM node:22-slim AS deps
WORKDIR /app
COPY package*.json ./
# 빌드 단계용: devDependencies 포함
RUN --mount=type=cache,target=/root/.npm npm ci
FROM node:22-slim AS builder
WORKDIR /app
COPY --from=deps /app/node_modules ./node_modules
COPY . .
RUN npm run build
FROM node:22-slim AS prod-deps
WORKDIR /app
COPY package*.json ./
# 런타임 단계용: production dependencies만
RUN --mount=type=cache,target=/root/.npm npm ci --omit=dev && npm cache clean --force
FROM gcr.io/distroless/nodejs22-debian12 AS runtime
WORKDIR /app
COPY --from=prod-deps /app/node_modules ./node_modules
COPY --from=builder /app/dist ./dist
COPY package*.json ./
# distroless 계열은 shell/package manager가 없고 nonroot 태그/사용자 제공 방식이 이미지별로 다를 수 있다.
# 기본 USER를 단정하지 말고 실제 태그 문서를 확인한 뒤 nonroot 실행을 명시한다.
USER nonroot:nonroot
CMD ["dist/index.js"]
번들러가 모든 런타임 의존성을 단일 산출물에 포함하는 구조라면 node_modules 복사를 생략할 수 있다. 반대로 SSR 서버나 런타임 import가 남는 구조라면 production node_modules를 별도 단계에서 복사해야 한다.
Key Points#
COPY --from=builder: 빌드 스테이지의 결과물만 최종 이미지로 추출해 gcc·make·git·소스·devDependencies 등 불필요한 파일을 런타임에서 제거한다.--mount=type=cache: BuildKit 기능. pip/npm 캐시를 빌드 중 재사용해 재빌드를 빠르게 하지만 최종 이미지에는 포함하지 않는다.- Python slim 계열은 앱 전용 nonroot 사용자를 직접 생성한 뒤
USER로 전환하는 편이 안전하다. - Distroless는 shell/package manager가 없어 공격 표면이 작지만 디버깅이 어렵다. nonroot 실행은 기본값으로 단정하지 말고
USER nonroot:nonroot또는 nonroot 태그 사용을 명시한다. npm ci --omit=dev는 런타임 의존성만 설치할 때 사용한다. 빌드에 devDependencies가 필요하면 build 단계에서는 전체npm ci를 사용하고, runtime 단계에서는 production deps를 별도로 설치하거나 빌드 산출물만 복사한다..dockerignore와 COPY 순서(lock 파일 → 의존성 설치 → 소스 COPY)를 함께 적용해야 캐시 효과가 크고 secret/불필요 파일의 빌드 컨텍스트 유입을 줄일 수 있다.
Caveats#
- distroless(no shell)는
sh,bash, 패키지 관리자, 일반 디버깅 도구가 없다. 개발·장애 분석에는 debug 태그 또는 별도 디버그 이미지를 사용한다. - 멀티아키텍처 빌드는
docker buildx build --platform linux/amd64,linux/arm64로 수행한다. COPY --from=builder경로가 틀리면 빌드 단계에서 실패하거나 런타임 파일 누락으로 이어질 수 있으므로 산출물 경로를 명확히 검증한다.- 이미지 크기 감소 폭은 언어, 베이스 이미지, native dependency 여부에 따라 달라진다. 1/5~1/10은 일반적인 기대치이지 보장값은 아니다.
- Node.js 예시는 활성 LTS 라인을 기준으로 주기적으로 갱신한다. 2026-05 기준 Node 22 계열을 우선 사용한다.
Related#
- Docker & Compose Practical Reference — Dockerfile 구조, BuildKit cache, Compose 운영 패턴
- Docker & 컨테이너 고급 실전 Capsule — 멀티스테이지/Compose/보안 플래그 종합 정리
- Docker & Compose Practical Reference Capsule — Node 22 기반 Dockerfile 예시와 Compose 운영 패턴
Sagwan Revalidation 2026-05-15#
- verdict:
revise - note: 이전 Node 예시는
npm ci --omit=dev결과를 builder가 그대로 사용해 devDependencies가 필요한npm run build에서 실패할 수 있었다. build deps와 production deps를 분리하는 예시로 보정했다.
Sagwan Revalidation 2026-05-16T11:30:17Z#
- verdict:
ok - note: Node 22 LTS·BuildKit·멀티스테이지 권장 패턴 모두 여전히 유효함
Sagwan Revalidation 2026-05-17T11:55:37Z#
- verdict:
ok - note: 멀티스테이지·BuildKit 캐시·distroless 권장안이 현재도 유효함
Sagwan Revalidation 2026-05-18T12:19:52Z#
- verdict:
ok - note: Docker/BuildKit 멀티스테이지 권장 패턴과 버전 전제가 여전히 유효함
Sagwan Revalidation 2026-05-19T12:48:21Z#
- verdict:
ok - note: Node 22·Python 3.12·BuildKit 멀티스테이지 권장안이 여전히 유효함
Sagwan Revalidation 2026-05-20T13:12:25Z#
- verdict:
ok - note: 멀티스테이지·BuildKit 캐시·Node 22 LTS 기준 모두 여전히 유효함
Sagwan Revalidation 2026-05-21T13:48:04Z#
- verdict:
ok - note: 멀티스테이지·BuildKit 캐시·distroless 권장안이 여전히 유효하다.
Sagwan Revalidation 2026-05-22T14:20:15Z#
- verdict:
ok - note: 멀티스테이지·BuildKit cache·distroless 패턴과 버전 전제가 여전히 유효함
Sagwan Revalidation 2026-05-23T14:58:26Z#
- verdict:
ok - note: 멀티스테이지·BuildKit 캐시·distroless 예시 모두 현재도 유효함
Sagwan Revalidation 2026-05-24T15:11:28Z#
- verdict:
ok - note: Node 22 LTS·BuildKit cache·distroless 패턴 모두 현재도 유효함
Sagwan Revalidation 2026-05-25T15:28:44Z#
- verdict:
ok - note: 패턴·버전·BuildKit 캐시 권장안 모두 현재도 유효하다.
Sagwan Revalidation 2026-05-26T15:38:22Z#
- verdict:
ok - note: [chatgpt 오류] The read operation timed out
Sagwan Revalidation 2026-05-27T16:25:43Z#
- verdict:
ok - note: 멀티스테이지·BuildKit 캐시·Node 22/distroless 예시는 여전히 유효함
Sagwan Revalidation 2026-05-28T17:25:41Z#
- verdict:
ok - note: 멀티스테이지·BuildKit 캐시·Node 22/distroless 권장안이 여전히 유효함
Sagwan Revalidation 2026-05-29T17:59:20Z#
- verdict:
ok - note: Docker/BuildKit, Python 3.12, Node 22 distroless 관행 모두 현재 유효함
Sagwan Revalidation 2026-05-30T18:36:16Z#
- verdict:
ok - note: 멀티스테이지·BuildKit 캐시·Node 22/distroless 권장안이 여전히 유효함
Sagwan Revalidation 2026-05-31T18:40:07Z#
- verdict:
ok - note: 멀티스테이지·BuildKit 캐시·Node 22 distroless 패턴 모두 여전히 유효함
Sagwan Revalidation 2026-06-01T18:40:37Z#
- verdict:
ok - note: [chatgpt HTTP 401] {
Sagwan Revalidation 2026-06-02T22:06:15Z#
- verdict:
ok - note: 예시와 권장안 모두 현재 Docker/BuildKit 관행에 부합함
Sagwan Revalidation 2026-06-03T22:56:26Z#
- verdict:
ok - note: 멀티스테이지·BuildKit 캐시·distroless 권장안은 현재도 유효함
Sagwan Revalidation 2026-06-04T23:28:24Z#
- verdict:
ok - note: Python 3.12·Node 22·BuildKit·distroless 권장 패턴이 여전히 유효함