11. Multi-stage сборки
Multi-stage builds (многоэтапные сборки) — одна из мощнейших возможностей Docker. Они позволяют создавать минимальные production-образы, используя несколько FROM инструкций в одном Dockerfile. Инструменты сборки остаются только на промежуточных этапах, не попадая в финальный образ.
Проблема: большие образы
Заголовок раздела «Проблема: большие образы»Без multi-stage builds у вас два варианта: огромный образ со всеми инструментами сборки, или несколько Dockerfile с ручным управлением артефактами.
# ❌ Один этап — всё в одном образеFROM node:20 # 1.1 GB!WORKDIR /appCOPY package*.json ./RUN npm install # devDependencies тоже!COPY . .RUN npm run build# Финальный образ: ~1.5 GB# Содержит: npm, node_modules с devDep, исходный код, тестыРешение: Multi-Stage Build
Заголовок раздела «Решение: Multi-Stage Build»# ✅ Multi-stage — минимальный финальный образ
# Этап 1: BuilderFROM node:20-alpine AS builderWORKDIR /appCOPY package*.json ./RUN npm ci # включая devDependenciesCOPY . .RUN npm run build # компиляция TypeScript, webpack
# Этап 2: ProductionFROM node:20-alpine AS productionWORKDIR /appCOPY package*.json ./RUN npm ci --only=production # только production depsCOPY --from=builder /app/dist ./dist # только результат сборки!ENV NODE_ENV=productionEXPOSE 3000CMD ["node", "dist/server.js"]# Финальный образ: ~200 MBAS именование этапов
Заголовок раздела «AS именование этапов»FROM node:20-alpine AS baseWORKDIR /appCOPY package*.json ./
FROM base AS depsRUN npm ci
FROM base AS dev-depsRUN npm ci # включая devDependencies
FROM dev-deps AS builderCOPY . .RUN npm run build
FROM dev-deps AS testerCOPY . .RUN npm test
FROM base AS productionCOPY --from=deps /app/node_modules ./node_modulesCOPY --from=builder /app/dist ./distCMD ["node", "dist/server.js"]COPY —from: копировать из другого этапа
Заголовок раздела «COPY —from: копировать из другого этапа»# Копировать из именованного этапаCOPY --from=builder /app/dist ./dist
# Копировать из конкретного образаCOPY --from=nginx:alpine /etc/nginx/nginx.conf /etc/nginx/nginx.conf
# Копировать по номеру этапа (0-based)COPY --from=0 /app/dist ./distПример: React приложение
Заголовок раздела «Пример: React приложение»# Этап 1: Сборка ReactFROM node:20-alpine AS buildWORKDIR /appCOPY package*.json ./RUN npm ciCOPY . .RUN npm run build# /app/build содержит статические файлы
# Этап 2: Nginx для раздачи статикиFROM nginx:alpine AS productionCOPY --from=build /app/build /usr/share/nginx/htmlCOPY nginx.conf /etc/nginx/conf.d/default.confEXPOSE 80CMD ["nginx", "-g", "daemon off;"]# Финальный образ: ~25 MB вместо ~1.5 GB!Пример: Go приложение
Заголовок раздела «Пример: Go приложение»# Этап 1: КомпиляцияFROM golang:1.21-alpine AS builderWORKDIR /appCOPY go.mod go.sum ./RUN go mod downloadCOPY . .RUN CGO_ENABLED=0 GOOS=linux go build -o server ./cmd/server
# Этап 2: Минимальный образFROM scratch AS productionCOPY --from=builder /app/server /serverEXPOSE 8080ENTRYPOINT ["/server"]# Финальный образ: только бинарник! ~8 MBСборка конкретного этапа
Заголовок раздела «Сборка конкретного этапа»# Собрать до конкретного этапа (полезно для дебага)docker build --target builder -t myapp:debug .docker build --target production -t myapp:prod .
# Запустить тесты на builder этапеdocker build --target tester -t myapp:test .docker run myapp:test