Docker
Docker 이미지 용량 제한을 두는 이유와 방법
배포 환경에서 Docker 이미지가 과도하게 커지는 것을 방지하는 방법을 정리했다.
Docker 이미지의 용량이 크면 빌드 시간이 길어지고, 이미지 저장소(registry)에 많은 공간을 차지하며, 배포 속도가 느려진다. 그래서 프로덕션 배포 환경에서는 이미지 용량을 제한하는 게 좋다.
특히 Node.js나 Python 프로젝트는 의존성 때문에 쉽게 이미지가 커진다.
현재 이미지 크기 확인
docker images | grep my-app
# 더 자세한 정보
docker image ls --format "table {{.Repository}}\t{{.Size}}"
이미지가 예상보다 크다면, Dockerfile을 최적화할 시간이다.
멀티 스테이지 빌드 사용
빌드 단계와 런타임 단계를 분리해서 불필요한 파일을 제외한다.
# 빌드 스테이지
FROM node:20-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production
COPY . .
RUN npm run build
# 런타임 스테이지 (이미지 최종 크기는 이것만 포함)
FROM node:20-alpine
WORKDIR /app
COPY --from=builder /app/node_modules ./node_modules
COPY --from=builder /app/.next ./.next
COPY package*.json ./
CMD ["npm", "start"]
이렇게 하면 빌드에 필요한 컴파일러와 개발 의존성이 최종 이미지에 포함되지 않는다.
경량 베이스 이미지 선택
# 무거움
FROM node:20
# 가벼움
FROM node:20-alpine
# 더 가벼움
FROM node:20-alpine3.20
Alpine은 일반적인 Node.js 이미지보다 300~400MB 더 작다.
불필요한 파일 제외
.dockerignore 파일을 사용해서 COPY 단계에서 제외할 파일들을 지정한다.
node_modules
npm-debug.log
.git
.gitignore
.env
.env.local
.next/cache
dist
build
.vscode
.idea
레이어 캐싱 최대화
Dockerfile에서 자주 변경되는 부분을 뒤에 배치해야 캐싱이 효과적이다.
# 좋은 순서
FROM node:20-alpine
WORKDIR /app
# 의존성 (거의 변경 안 됨) - 먼저
COPY package*.json ./
RUN npm ci --only=production
# 소스 코드 (자주 변경됨) - 나중에
COPY . .
RUN npm run build
이미지 용량 확인
# 빌드 후 크기 확인
docker build -t my-app:latest .
docker images my-app
# 레이어별 크기 확인
docker history my-app:latest
각 레이어가 얼마나 공간을 차지하는지 보면, 최적화할 부분을 찾을 수 있다.
배포 환경에서의 용량 제한
일부 CI/CD 시스템이나 container registry는 이미지 용량을 제한할 수 있다. 예를 들어:
# GitHub Actions에서 이미지 용량 체크
if [ $(docker images my-app:latest --format "{{.Size}}" | numfmt --from=auto --to=none) -gt 500000000 ]; then
echo "Error: Image exceeds 500MB"
exit 1
fi
최종 체크리스트
- 멀티 스테이지 빌드를 사용하는가?
- Alpine 같은 경량 베이스 이미지를 선택했는가?
- .dockerignore에 불필요한 파일을 지정했는가?
- 최종 이미지 크기가 합리적인가? (보통 200~500MB)
이미지 용량을 줄이는 것은 배포 속도와 비용 절감으로 직결된다.