1. 적절한 베이스 이미지 선택#
1
2
3
4
5
6
7
8
9
10
|
# ❌ 너무 큼
FROM ubuntu:22.04 # ~77MB
FROM python:3.11 # ~1GB
# ✅ 추천
FROM python:3.11-alpine # ~50MB
FROM python:3.11-slim # ~130MB
# ✅ 최소 크기
FROM gcr.io/distroless/python3 # ~20MB
|
| 베이스 이미지 |
크기 |
ubuntu:22.04 |
~77MB |
python:3.11 |
~1GB |
python:3.11-alpine |
~50MB |
distroless |
~20MB |
2. 멀티스테이지 빌드 사용#
가장 효과적인 최적화 방법: 컴파일 스테이지에서는 큰 이미지를 사용하고 실행 스테이지에서는 산출물만 복사합니다.
1
2
3
4
5
6
7
8
9
10
11
|
# 스테이지 1: 컴파일
FROM golang:1.21 AS builder
WORKDIR /app
COPY . .
RUN go build -o myapp
# 스테이지 2: 실행
FROM alpine:3.18
WORKDIR /app
COPY --from=builder /app/myapp .
CMD ["./myapp"]
|
Go 애플리케이션이 ~1GB에서 ~15MB로 축소됩니다.
3. RUN 명령어 병합#
1
2
3
4
5
6
7
8
9
10
11
12
|
# ❌ 여러 레이어
RUN apt-get update
RUN apt-get install -y curl
RUN apt-get install -y wget
RUN rm -rf /var/lib/apt/lists/*
# ✅ 하나의 레이어로 병합
RUN apt-get update && \
apt-get install -y --no-install-recommends \
curl \
wget && \
rm -rf /var/lib/apt/lists/*
|
4. 빌드 캐시 정리#
1
2
3
4
5
6
7
8
9
|
# Python - pip 캐시 비활성화
RUN pip install --no-cache-dir -r requirements.txt
# Node.js - npm 캐시 정리
RUN npm ci --only=production && \
npm cache clean --force
# Go - 디버그 정보 제거
RUN go build -ldflags="-s -w" -o myapp
|
5. .dockerignore 사용#
1
2
3
4
5
6
7
8
9
10
11
|
# .dockerignore
.git
node_modules
*.md
.env
.vscode
__pycache__
*.pyc
dist
build
coverage
|
1
2
|
# 컨텍스트 크기 확인
docker build --no-cache -t test . 2>&1 | grep "Sending build context"
|
6. 필요한 패키지만 설치#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
# ❌ 실행 이미지에 빌드 도구가 포함됨
FROM ubuntu:22.04
RUN apt-get install -y build-essential gcc make cmake
COPY . .
RUN make && make install
CMD ["./myapp"]
# ✅ 빌드와 실행 분리
FROM ubuntu:22.04 AS builder
RUN apt-get install -y build-essential gcc make
COPY . .
RUN make && make install
FROM ubuntu:22.04
COPY --from=builder /app/myapp .
CMD ["./myapp"]
|
7. –no-install-recommends 사용#
1
2
3
4
5
|
# ❌ 모든 추천 패키지 설치
RUN apt-get install -y curl
# ✅ 필수 패키지만 설치 (의존성 약 50% 감소)
RUN apt-get install -y --no-install-recommends curl
|
8. 정적 리소스 압축#
1
2
3
4
5
6
7
8
9
10
11
|
# JavaScript 압축
RUN uglifyjs app.js -o app.min.js
# CSS 압축
RUN cssnano app.css app.min.css
# 이미지 압축
RUN find . -name "*.png" -exec optipng {} \;
# Go 바이너리 디버그 정보 제거
RUN go build -ldflags="-s -w" -o myapp
|
9. Squash로 레이어 병합#
1
2
|
# 모든 레이어를 하나로 병합하여 중간 레이어의 중복 파일 제거
docker build --squash -t myapp:slim .
|
/etc/docker/daemon.json에서 experimental 기능을 활성화해야 합니다.
10. 이미지 레이어 분석#
1
2
3
4
5
6
7
|
# dive 도구로 각 레이어의 크기와 내용 분석
docker run --rm -it \
-v /var/run/docker.sock:/var/run/docker.sock \
wagoodman/dive myapp:latest
# 또는 docker history 사용
docker history myapp:latest
|
실전 사례: Python 애플리케이션#
1
2
3
4
5
6
|
# ❌ 최적화 전 (1.2GB)
FROM python:3.11
WORKDIR /app
COPY . .
RUN pip install -r requirements.txt
CMD ["python", "app.py"]
|
1
2
3
4
5
6
7
8
9
10
11
12
|
# ✅ 최적화 후 (150MB, 87% 감소)
FROM python:3.11-slim AS builder
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir --user -r requirements.txt
FROM python:3.11-slim
WORKDIR /app
COPY --from=builder /root/.local /root/.local
COPY . .
ENV PATH=/root/.local/bin:$PATH
CMD ["python", "app.py"]
|
실전 사례: Node.js 애플리케이션#
1
2
3
4
5
6
|
# ❌ 최적화 전 (1.1GB)
FROM node:18
WORKDIR /app
COPY . .
RUN npm install
CMD ["node", "server.js"]
|
1
2
3
4
5
6
7
8
9
10
11
12
|
# ✅ 최적화 후 (180MB, 84% 감소)
FROM node:18-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production
FROM node:18-alpine
WORKDIR /app
COPY --from=builder /app/node_modules ./node_modules
COPY . .
USER node
CMD ["node", "server.js"]
|
추천 도구#
| 도구 |
용도 |
dive |
이미지의 각 레이어 내용과 크기 분석 |
docker-slim |
이미지 자동 최적화 |
hadolint |
Dockerfile 정적 검사 |
trivy |
이미지 보안 스캔 |