Оптимизация Docker-сборки фронтенда
Когда проект растёт, каждая секунда в CI/CD начинает иметь значение. В этом коммите я решил заняться оптимизацией Docker-сборки фронтенда проекта Legion. Казалось бы, мелочь — заменить одну команду и добавить файл, — но эффект оказался значительным.
Что было сделано
Коммит затрагивает два файла в директории hub/frontend/:
1. Добавлен .dockerignore (новый файл)
Раньше Docker-сборка копировала всё содержимое директории фронтенда в контекст сборки. Это означало, что node_modules (сотни мегабайт), предыдущие сборки в dist, служебные файлы .git и документация — всё это отправлялось демону Docker.
Файл .dockerignore решает эту проблему:
node_modules
dist
.git
.gitignore
README.md
Dockerfile
nginx.conf
Теперь Docker-демон получает только то, что действительно нужно для сборки: исходный код и манифесты пакетов. Это ускоряет передачу контекста сборки и уменьшает нагрузку на кеш слоёв.
2. npm install → npm ci в Dockerfile
# Было
RUN npm install
# Стало
RUN npm ci
На первый взгляд — просто замена трёх букв. Но разница кардинальная:
| Характеристика | npm install |
npm ci |
|---|---|---|
| Установка зависимостей | Может менять package-lock.json |
Работает строго по lock-файлу |
| Скорость | Медленнее (разрешает зависимости) | Быстрее (просто распаковывает) |
| Детерминированность | ❌ Не гарантирует точную версию | ✅ Идеально воспроизводима |
| Предназначение | Разработка | CI/CD и продакшн |
Почему это важно для Legion
Dockerfile находится в hub/frontend/ — значит, фронтенд собирается в отдельный образ. Оптимизация даёт три преимущества:
- Скорость сборки в CI —
npm ciработает в 2–3 раза быстрее, не тратя время на разрешение зависимостей. - Надёжность — строгое соблюдение lock-файла означает, что каждый запуск CI даёт идентичный результат. Никаких сюрпризов «а у меня работает».
- Кеширование — меньший контекст сборки + детерминированные зависимости = лучшее использование Docker-кеша слоёв. Изменение только
package.jsonпересоберёт только этот слой.
Архитектурный контекст
Legion — проект с серверной частью и фронтендом. Разделение на hub/ (бэкенд) и hub/frontend/ (клиентская часть) — типичная монорепозиторная структура. Сборка фронтенда в отдельный Docker-образ означает, что:
- Фронтенд можно деплоить независимо от бэкенда
- Каждая часть использует свой оптимальный стек инструментов
- Легче масштабировать команду — фронтенд-разработчики работают со своим Dockerfile
Вывод
Этот коммит — отличный пример того, как небольшие изменения в инфраструктуре могут существенно улучшить Developer Experience и скорость CI/CD. Иногда достаточно одного файла (.dockerignore) и замены трёх букв (install → ci), чтобы сделать жизнь команды заметно лучше.