Docker build - Multi-stage builds(멀티 스테이지 빌드)
2024.11.28
목표
- **Multi-stage builds(멀티 스테이지 빌드)**가 무엇인지 알아본다.
- 멀티 스테이지 빌드를 사용해보고 적용 전/후의 이미지 크기를 비교해본다.
Multi-stage builds란?
Dockerfile 내에서 여러 개의 빌드 단계를 정의하여 이미지를 생성하는 방법이다. 빌드 단계에는 필요하지만 애플리케이션 구동에는 필요없는, 다시 말하면 애플리케이션 실행에 필요한 최소한의 구성만 포함하여 이미지 크기를 최소화할 수 있다.
왜 사용하나요?
Docker 이미지 크기 최소화
web-app-big은 멀티 스테이지를 사용하지 않았고 그 아래 web-app은 멀티 스테이지 빌드를 사용했다. 사이즈를 비교해보면 이미지 사이즈가 약 80.72%가 감소하였다. (참고로 두 앱 모두 next.js standalone을 적용했다)
- 비용 절감 효과
- 이미지 저장에 필요한 공간이 줄어들어 디스크 용량을 아낄 수 있다.
- 네트워크 대역폭 사용을 최소화하여 네트워크 비용을 줄인다.
- 보안 강화
- 불필요한 개발 종속성들이 제외되어 잠재적인 취약점이 감소하여 공격 표면이 줄어든다.
예제
Next.js
# syntax=docker.io/docker/dockerfile:1
FROM node:18-alpine AS base
# 1. Install dependencies only when needed
FROM base AS deps
# Check https://github.com/nodejs/docker-node/tree/b4117f9333da4138b03a546ec926ef50a31506c3#nodealpine to understand why libc6-compat might be needed.
RUN apk add --no-cache libc6-compat
WORKDIR /app
# Install dependencies based on the preferred package manager
COPY package.json yarn.lock* package-lock.json* pnpm-lock.yaml* .npmrc* ./
RUN \
if [ -f yarn.lock ]; then yarn --frozen-lockfile; \
elif [ -f package-lock.json ]; then npm ci; \
elif [ -f pnpm-lock.yaml ]; then corepack enable pnpm && pnpm i; \
else echo "Lockfile not found." && exit 1; \
fi
# 2. Rebuild the source code only when needed
FROM base AS builder
WORKDIR /app
COPY --from=deps /app/node_modules ./node_modules
COPY . .
# This will do the trick, use the corresponding env file for each environment.
COPY .env.staging.sample .env.production
RUN npm run build
# 3. Production image, copy all the files and run next
FROM base AS runner
WORKDIR /app
ENV NODE_ENV=production
RUN addgroup -g 1001 -S nodejs
RUN adduser -S nextjs -u 1001
COPY --from=builder /app/public ./public
# Automatically leverage output traces to reduce image size
# https://nextjs.org/docs/advanced-features/output-file-tracing
COPY --from=builder --chown=nextjs:nodejs /app/.next/standalone ./
COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static
USER nextjs
EXPOSE 3000
ENV PORT=3000
CMD HOSTNAME="0.0.0.0" node server.js
정리
멀티 스테이지 빌드는 Docker에서 이미지를 생성할 때 여러 단계의 빌드 과정을 거쳐 최종 이미지의 크기를 최소화하는 기술이다. 주요 장점은 다음과 같다:
- 효율적인 이미지 크기 관리: 빌드에만 필요한 도구와 의존성을 제외하고, 실행에 필요한 최소한의 구성만 포함하여 이미지 크기를 대폭 줄일 수 있다.
- 비용 절감: 이미지 저장 공간과 네트워크 대역폭 사용량이 감소하여 운영 비용이 절감된다.
- 보안 강화: 불필요한 개발 도구와 종속성이 제거되어 보안 취약점이 감소한다.
실제 Next.js 프로젝트에 멀티 스테이지 빌드를 적용한 결과, 이미지 크기가 약 80% 이상 감소하는 효과를 확인할 수 있었다.