BuildKit이란?
Docker BuildKit은 Docker 18.09에서 도입된 차세대 빌드 엔진으로, 기존 빌드 엔진 대비 병렬 빌드, 캐시 마운트, 시크릿 마운트 등 강력한 최적화 기능을 제공합니다. Docker 23.0부터 기본 빌드 엔진으로 채택되었으며, CI/CD 파이프라인에서 빌드 시간을 50~80% 단축할 수 있는 핵심 기술입니다.
이 글에서는 BuildKit의 캐시 전략, 시크릿 관리, 병렬 빌드 패턴, 그리고 CI 환경에서의 원격 캐시 활용까지 깊이 있게 다루겠습니다.
BuildKit 활성화
# 환경 변수로 활성화 (Docker 23.0 미만)
export DOCKER_BUILDKIT=1
docker build -t myapp .
# Docker 23.0+에서는 기본 활성화
# docker buildx를 사용하면 BuildKit 자동 사용
docker buildx build -t myapp .
# daemon.json으로 영구 설정
{
"features": {
"buildkit": true
}
}
RUN –mount=type=cache: 게임 체인저
--mount=type=cache는 BuildKit의 가장 강력한 기능입니다. 패키지 매니저의 캐시 디렉토리를 빌드 간에 유지하여 의존성 재다운로드를 완전히 제거합니다.
# syntax=docker/dockerfile:1
# ❌ 기존 방식: 레이어 캐시 미스 시 전체 재설치
FROM node:20-alpine
WORKDIR /app
COPY package*.json ./
RUN npm ci # 캐시 미스 → 전체 다운로드 (~60초)
COPY . .
RUN npm run build
# ✅ BuildKit 캐시 마운트: 패키지 캐시 영구 유지
FROM node:20-alpine
WORKDIR /app
COPY package*.json ./
RUN --mount=type=cache,target=/root/.npm
npm ci # npm 캐시 재사용 (~5초)
COPY . .
RUN --mount=type=cache,target=/app/.next/cache
npm run build # Next.js 빌드 캐시도 유지
언어별 캐시 마운트 설정
| 언어/도구 | 캐시 경로 | 마운트 설정 |
|---|---|---|
| npm | /root/.npm | --mount=type=cache,target=/root/.npm |
| pnpm | /root/.local/share/pnpm/store | --mount=type=cache,target=/root/.local/share/pnpm/store |
| Maven | /root/.m2/repository | --mount=type=cache,target=/root/.m2/repository |
| Gradle | /root/.gradle/caches | --mount=type=cache,target=/root/.gradle/caches |
| pip | /root/.cache/pip | --mount=type=cache,target=/root/.cache/pip |
| Go | /go/pkg/mod | --mount=type=cache,target=/go/pkg/mod |
실전 Dockerfile: Spring Boot + Gradle
# syntax=docker/dockerfile:1
# 1단계: 의존성 해석 (캐시 최대 활용)
FROM eclipse-temurin:21-jdk-alpine AS deps
WORKDIR /app
COPY build.gradle.kts settings.gradle.kts gradle.properties ./
COPY gradle ./gradle
RUN --mount=type=cache,target=/root/.gradle/caches
--mount=type=cache,target=/root/.gradle/wrapper
./gradlew dependencies --no-daemon
# 2단계: 빌드 (소스 변경 시에만 재실행)
FROM deps AS build
COPY src ./src
RUN --mount=type=cache,target=/root/.gradle/caches
--mount=type=cache,target=/root/.gradle/wrapper
--mount=type=cache,target=/app/build
./gradlew bootJar --no-daemon -x test
# 3단계: 런타임 (최소 이미지)
FROM eclipse-temurin:21-jre-alpine
WORKDIR /app
COPY --from=build /app/build/libs/*.jar app.jar
EXPOSE 8080
ENTRYPOINT ["java", "-jar", "app.jar"]
Secret 마운트: 빌드 시 민감 정보
# 프라이빗 레지스트리 접근, API 키 등을
# 이미지 레이어에 남기지 않고 안전하게 사용
# Dockerfile
FROM node:20-alpine
WORKDIR /app
COPY package*.json ./
# .npmrc에 프라이빗 레지스트리 토큰이 필요한 경우
RUN --mount=type=secret,id=npmrc,target=/root/.npmrc
npm ci
COPY . .
RUN npm run build
# 빌드 명령
docker buildx build
--secret id=npmrc,src=$HOME/.npmrc
-t myapp .
# SSH 키가 필요한 경우 (프라이빗 Git 의존성)
RUN --mount=type=ssh
git clone git@github.com:company/private-lib.git
docker buildx build
--ssh default=$SSH_AUTH_SOCK
-t myapp .
병렬 빌드: Multi-Stage 최적화
BuildKit은 Multi-Stage Build에서 독립적인 스테이지를 자동으로 병렬 실행합니다.
# syntax=docker/dockerfile:1
# 이 3개 스테이지는 서로 의존하지 않으므로 병렬 실행!
FROM node:20-alpine AS frontend
WORKDIR /app/frontend
COPY frontend/package*.json ./
RUN --mount=type=cache,target=/root/.npm npm ci
COPY frontend/ .
RUN npm run build
FROM eclipse-temurin:21-jdk-alpine AS backend
WORKDIR /app
COPY build.gradle.kts settings.gradle.kts ./
RUN --mount=type=cache,target=/root/.gradle/caches
./gradlew dependencies --no-daemon
COPY src ./src
RUN --mount=type=cache,target=/root/.gradle/caches
./gradlew bootJar --no-daemon
FROM nginx:alpine AS docs
COPY docs/ /tmp/docs/
RUN apk add --no-cache hugo && hugo -s /tmp/docs -d /out
# 최종 이미지: 3개 스테이지 결과 합침
FROM eclipse-temurin:21-jre-alpine
COPY --from=backend /app/build/libs/*.jar app.jar
COPY --from=frontend /app/frontend/dist /static
COPY --from=docs /out /docs
ENTRYPOINT ["java", "-jar", "app.jar"]
# 빌드 시간: 순차 ~180초 → 병렬 ~80초
원격 캐시: CI/CD 파이프라인
# GitHub Actions에서 레지스트리 캐시 활용
# 로컬 캐시는 CI에서 사라지지만, 원격 캐시는 영구 유지
# 1. 레지스트리 캐시 (가장 범용적)
docker buildx build
--cache-from type=registry,ref=ghcr.io/myorg/myapp:cache
--cache-to type=registry,ref=ghcr.io/myorg/myapp:cache,mode=max
-t ghcr.io/myorg/myapp:latest
--push .
# 2. GitHub Actions 캐시
docker buildx build
--cache-from type=gha
--cache-to type=gha,mode=max
-t myapp .
# 3. S3 캐시 (대용량)
docker buildx build
--cache-from type=s3,region=ap-northeast-2,bucket=my-cache
--cache-to type=s3,region=ap-northeast-2,bucket=my-cache,mode=max
-t myapp .
# mode=max: 중간 레이어까지 모두 캐시 (권장)
# mode=min: 최종 레이어만 캐시 (기본)
GitHub Actions 실전 워크플로우
# .github/workflows/build.yml
name: Build and Push
on:
push:
branches: [main]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: docker/setup-buildx-action@v3
- uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- uses: docker/build-push-action@v5
with:
context: .
push: true
tags: ghcr.io/${{ github.repository }}:latest
cache-from: type=gha
cache-to: type=gha,mode=max
secrets: |
npmrc=${{ secrets.NPMRC }}
캐시 디버깅
# 빌드 캐시 현황 확인
docker buildx du
# 캐시 정리
docker buildx prune --all
# 빌드 과정 상세 로그 (캐시 히트/미스 확인)
docker buildx build --progress=plain -t myapp .
# 특정 스테이지만 빌드 (디버깅용)
docker buildx build --target=deps -t myapp:deps .
운영 주의사항
| 항목 | 주의 | 대응 |
|---|---|---|
| 캐시 크기 | cache mount 무한 증가 가능 | 정기적 docker buildx prune |
| 캐시 무효화 | COPY 순서가 캐시에 영향 | 변경 빈도 낮은 파일 먼저 COPY |
| 보안 | 원격 캐시에 민감 레이어 포함 가능 | secret mount 사용, mode=min 검토 |
| CI 호환성 | 일부 CI에서 buildx 미지원 | setup-buildx-action 추가 |
마무리
Docker BuildKit의 캐시 마운트와 원격 캐시는 CI/CD 파이프라인의 빌드 시간을 획기적으로 단축합니다. --mount=type=cache 하나만 추가해도 의존성 설치 시간을 90% 이상 줄일 수 있으며, 레지스트리 캐시와 조합하면 CI 환경에서도 로컬 빌드 수준의 속도를 달성할 수 있습니다. Dockerfile을 작성할 때 BuildKit 기능을 적극 활용하세요.