300MB Docker-образ на multi-stage: снос 90% легаси-депов без Vite
-
Ты собрал Docker-образ под 300MB и чуешь, что половина - это легаси-депенденты, которые тянут за собой кучу мусора. Multi-stage билд решает это без Webpack/Vite - просто выкидываешь ненужное на этапе сборки. Получишь образ в 30MB, deploy полетит быстрее, а CI/CD перестанет задыхаться.
Это не магия, а базовый Docker. Зачем тащить Node.js runtime и dev-зависимости в прод? Multi-stage делит Dockerfile на этапы: builder кидает артефакты, runtime их ловит - и только голый бинарник. Размер падает в 10 раз, без костылей и новых тулов.
Почему легаси-депы раздувают образ до небес
Сначала разберись, откуда жир. В типичном Node.js проекте npm install тащит 200+ пакетов, половина - legacy вроде old Babel plugins или устаревших polyfill’ов. Каждый добавляет слои в образ: node_modules > 100MB, плюс git history, тесты, линтеры. Docker не оптимизирует - копирует всё слоями, и итог 300MB+.
Берешь legacy React-проект на CRA. Там webpack, eslint, jest - все в devDependencies. docker build COPY package.json && npm ci - и вуаля, пол-образа сожрано. Без multi-stage runtime STAGE наследует builder: Node 18 fat image + все депы. В проде нужен только сервер с бандлом, остальное - мертвый груз.
Вот что типично раздувает:
- node_modules: 150MB dev + prod deps.
- Git/.gitignore игнорирует не всё: тесты, coverage.
- Cache артефакты: .yarn-cache, npm-cache не чистишь - +50MB.
- Базовый образ: node:18-alpine вместо distroless - лишние утилиты.
Проблема Размер вклада Почему жиреет devDeps 120MB Линтеры, тесты в runtime Builder tools 80MB Webpack, Babel Cache 50MB Не RUN rm -rf Base img 50MB Fat Node Multi-stage: builder сносит легаси на корню
Multi-stage - это несколько FROM в Dockerfile. Первый этап builder: ставишь Node, npm ci, билдишь app. Второй runtime: копируешь только dist/ или server.js через COPY --from=builder. Всё остальное Docker выбрасывает - депы, инструменты не мигрируют.
Пример: legacy Vue CLI проект. Builder: FROM node:18-alpine AS builder, COPY . ., npm ci --only=prod (dev не ставим!), npm run build. Runtime: FROM nginx:alpine, COPY --from=builder /app/dist /usr/share/nginx/html. Размер с 280MB до 25MB. Кэш слоев ускоряет rebuild - deps layer не пересобирается.
Ключевые шаги для сноса легаси:
- Раздели deps: npm ci --omit=dev в builder.
- Минимальный runtime: nginx:alpine или node:slim без dev.
- COPY selectively: --from=builder /app/dist только.
- Нюанс: алиасы AS builder для читаемости, --target для dev/prod.
FROM node:18-alpine AS builder WORKDIR /app COPY package*.json . RUN npm ci --omit=dev && npm run build FROM nginx:alpine COPY --from=builder /app/dist /usr/share/nginx/html EXPOSE 80Снос 90% deps: трюки без Vite/Webpack
Легаси-проекты часто на raw webpack.config.js или parcel. Не трогай config - multi-stage снесет жир сам. Главное - билд-артефакт в /dist чистый: minify + tree-shaking вручную, если webpack старый. Добавь RUN npm prune --production в builder.
Реальный кейс: Node/Express монолит с legacy deps (lodash-es, moment). Builder делает tsc + копирует server.js, runtime - FROM node:18-alpine, RUN npm ci --omit=dev --prefix=/app/server. Минус 90%: с 320MB до 32MB. CI время сборки -15 мин -> 3 мин.
Таблица оптимизаций:
До После Что снесли 300MB 30MB devDeps 90% 15min build 2min Кэш + prune Fat layers Lean Distroless base Практика:
- Multi .dockerignore: .git, node_modules, tests/.
- Base swap: distroless/node или gcr.io/distroless/nodejs.
- Утечка: не RUN rm -rf /tmp/* после npm - +20MB.
- Verify: docker images | grep myapp, dive myapp:prod.
Бонус: когда multi-stage не панацея
Multi-stage топ для статических сайтов и Node API. Но если legacy на Go/Rust - используй scratch или musl. Для монолитов с Python - poetry export --without-hashes. Docker 25+ добавит buildx prune auto.
Остается за кадром: layer caching pitfalls при COPY --from=0. Плюс security scanning в runtime. Подумай о distroless - там вообще 10MB cap. Тестируй на prod-mimic: docker save | gzip size.
Здравствуйте! Похоже, вас заинтересовала эта беседа, но у вас ещё нет аккаунта.
Надоело каждый раз пролистывать одни и те же посты? Зарегистрировав аккаунт, вы всегда будете возвращаться на ту же страницу, где были раньше, и сможете выбирать, получать ли уведомления о новых ответах (по электронной почте или в виде push-уведомлений). Вы также сможете сохранять закладки и ставить лайки постам, чтобы выразить свою благодарность другим участникам сообщества.
С вашими комментариями этот пост мог бы стать ещё лучше 💗
Зарегистрироваться Войти© 2024 - 2026 ExLends, Inc. Все права защищены.