Multi-stage build
Тема дорожной карты · Node.js
Многоэтапные сборки — это функция Docker, позволяющая одному Dockerfile определять несколько этапов FROM, что даёт возможность проектам Node.js компилировать TypeScript или собирать ресурсы на тяжёлом этапе сборки, а затем копировать только продакшн-артефакты в минимальный итоговый образ. Типичная многоэтапная сборка Node.js использует образ node:20 на этапе сборки для выполнения npm ci и tsc, затем переключается на node:20-alpine для этапа выполнения, что обычно даёт образы на 70–80% меньше, чем однoэтапные варианты. Многоэтапные сборки являются лучшей практикой для серверной разработки Node.js, поскольку разделяют зависимости времени сборки (компилятор TypeScript, dev-зависимости) от зависимостей времени выполнения, уменьшая поверхность атаки и повышая производительность контейнерных развёртываний. Инструкция COPY --from=builder является ключевым механизмом, переносящим в компактный финальный этап только скомпилированную директорию dist/ и продакшн-модули node_modules.
Как это работает
Multi-stage build оборачивает Node-приложение в контейнер для воспроизводимых деплоев. Выбор базового образа важен: node:22-alpine (маленький, musl libc, иногда проблемы с нативными модулями), node:22-slim (на debian, лучше совместимость), node:22-bookworm (полный debian, самый большой). Multi-stage сборки компилируют + чистят: builder ставит deps и npm run build; runner копирует только dist/ + production-node_modules. Запускайте под non-root (USER node). Добавьте healthcheck.
Когда применять
Контейнеризуйте каждое production Node-приложение — воспроизводимость + deployment-пайплайн перевешивают цену. Slim или alpine для размера; bookworm — если упрётесь в native-модули. Всегда multi-stage. Кешируйте npm ci/pnpm install, копируя package*.json первым. Не ставьте dev-deps в runner. NODE_ENV=production. node (не npm start) как PID 1 — сигналы тогда работают.
Типичные ошибки
Ловушки Multi-stage build: копирование node_modules с хоста (несовпадение архитектуры, native-модули не пересобраны); npm install вместо npm ci (дрейф lockfile); проигнорированный .dockerignore (огромный build context); npm start как CMD (PID 1 — это npm, SIGTERM не доходит до Node); build-deps в runner-образе (раздутие + поверхность атаки). Один node Dockerfile даст 80% — копируйте его вперёд.