План:
1) Введение
2) Проблемы первой версии сборки docker и ее решение
3) Различия между сборками для разработки и production
4) Выводы
Введение
Всем привет, меня зовут Александр, я являюсь фронтенд разработчиком более 4-х лет. В этой статье я хочу продолжить тему изучения docker и работы с контейнерами. С предыдущей статьи «Знакомство и настройка docker» уже прошло много времени. Я попользовался своей сборкой и заметил у нее проблем с работой, которые меня с течением времени все больше раздражают. В рамках этой статьи хотел бы рассказать, что конкретно меня не устраивало, и что я поменял, чтобы устранить возникшую проблему.
Проблемы первой версии сборки docker и ее решение
В моей сборке была самая главная проблема — работа с томами, volumes.
После того, как контейнер запускается и монтирует хостовую папку (папка с проектом), то через тома хостовая папка сопоставляется с папкой из контейнера. Так вот у меня после того, как контейнер поднялся, то рабочая папка сопоставляется, а вот папка с node_modules была пустая. Соответственно из-за этого я не мог вести разработку, потому что текстовый редактор не может работать с пустой папкой node_modules, либо модули подтирались в образе и из-за не запускался проект.
Почему возникала такая проблема? Вся проблема в алгоритме работы docker, которую обходят во всех курсах. Если почитать форум reddit, stack overflow и другие подобные сайты, то везде будет указан вопрос: в какой момент в контейнере добавляется, либо создается папка node_modules.
Давайте рассмотрим этот момент более подробней. Добавить папку node_modules можно разными путями:
- через команду run
- через команду cmd
В чем разница между этими командами? Да, обе они выполняют одну и туже функцию — добавляют папку node_modules в контейнер, но здесь важен контекст вопроса: когда добавляют?
Когда я составлял свой конфигурационный файл по docker, то тестировал разные сценарии. Задокументировал три из них:
Сценарий №1
Docker файл
Docker compose файл
Package.json
Сценарий №2
Docker файл
Docker compose файл
Package.json
В этих сценариях пакеты устанавливаются и потом по инструкции тома «/[путь до рабочей папки]/[рабочая папка]/node_modules» (рабочий путь может отличаться) папки из хоста и контейнера сопоставляются. Проблема заключается в следующем: на момент монтирования папка node_modules находится в образе, а в папку хоста передается пустая папка, потому что инструкция RUN добавляет данные в образ. В результате получается, что node_modules от RUN нельзя менять, и по этой причине в папке хоста создается пустая папка node_modules. Минус этой реализации в том, что если в корневой папке нет пакетов для node_modules, то контейнер не будет нормально работать. Это будет выражаться в том, что ваш редактор будет смотреть в папку с модулями и брать из нее конфигурационные файлы для линтеров и претиеров, а из-за того, что этих модулей нет — нельзя будет локально вести разработку.
В этих двух сценариях иногда возникает ошибка по выполнению инструкции RUN npm i. Единственное различие этих сценариев — это то, что в Сценарии №1 не прописана инструкция для томов (volumes в файле docker-compose) /app/node_modules, а во втором наоборот — прописана. Я в этих реализации ждал несколько раз по 1000 и более секунд. После сбрасывал, потому что понимал, что не может docker так нормально работать. Почему у меня на локальной машине у докера возникает такая ошибка я не смог разобраться.
Ожидания в 1000 секунд
Сценарий №3
Docker файл
Docker compose файл
Package.json
В этом сценарии я решил поменять момент, когда будут добавляться пакеты в сборку. Иными словами, я вынес их из образа. Теперь пакеты устанавливаются на уровне выполнения команды CMD, то есть при каждом запуске контейнера сначала будут устанавливаться пакеты, а потом подниматься приложение. На данный момент времени я остановился на этом решении. Оно удовлетворяет все мои потребности.
Итого, проблему с пакетами решили. Да, есть минус в виде того, что при каждом старте контейнера будут устанавливаться пакеты, но для меня это сносное решение, потому что они быстро устанавливаются. Плюсом я получил полностью автономный контейнер и мне теперь не нужен локально установленный node.js
Различия между сборками для разработки и production
На основе вышеописанных трех сценариев я теперь еще понял четкость различия между сборками для разработки и сборками для продакшн окружения. Их различие заключается в подходе, в какой момент времени переносить пакеты. То есть для сборки, которая будет использовать в разработке важно, чтобы была возможность сопоставлять файлы образа с файлами хостовой папки. Для сборки, которая будет использоваться в продакшене изменение файлов не нужно, поэтому ей достаточно просто развернуть проект без сопоставления. Если еще проще, то в продакшн сборке нельзя использовать тома (VOLUMES)
Выводы
В этой статье я более наглядно показал, что просто выучить docker — этого мало. Необходимо понимать, тонкости работы образа, чтобы использовать этот инструмент на полную мощь и извлекать из него максимальную выгоду. На своем примере я показал, что если не понимать этот нюанс, то толку от того, что ты выучил docker будет немного. Нужно после изучения практиковаться составлять сборки для своих проектов. Спасибо за внимание и до встречи в следующих статьях.