Run Grunt/Gulp внутри контейнера Docker или снаружи?
Я пытаюсь определить хорошую практику для процесса сборки приложения nodejs с использованием grunt/ gulp для развертывания внутри контейнера докеров.
Я очень доволен следующей последовательностью:
- построить с помощью внешнего grunt (или gulp)
- добавить. /dist папку в контейнер
- запустить npm install (с флагом --production) внутри контейнера
Но в каждом примере, который я нахожу, я вижу другой подход:
- добавить. /src папку в контейнер
- запустить npm install (с зависимостями dev) внутри контейнера
- запустить bower install (если требуется) внутри контейнера
- запустить grunt (или gulp) внутри контейнера
IMO, первый подход создает более легкий и эффективный контейнер, но во всех примерах используется второй подход. Я что-то пропустил?
Ответы
Ответ 1
Единственное различие, которое я вижу, это то, что вы можете воспроизвести полную установку grunt во втором подходе.
В первом случае вы зависите от локального действия, которое может выполняться по-разному, в разных средах.
Контейнер должен быть основан на изображении, которое можно легко воспроизвести, а не в зависимости от папки хоста, которая содержит "что необходимо" (не зная, как эта часть была выполнена).
Если накладные расходы среды сборки, которые поставляются с установкой, слишком велики для изображения ворчания, вы можете:
- создайте образ "
app.tar
", предназначенный для установки (Я сделал это для Apache, что мне пришлось перекомпилировать, создав deb пакет в общем томе).
В вашем случае вы можете создать архив ( "tar" ) установленного приложения.
-
создание контейнера из базового изображения с использованием тома из этого первого контейнера
docker run --it --name=app.inst --volumes-from=app.tar ubuntu untar /shared/path/app.tar
docker commit app.inst app
Тогда конечный результат - это изображение с приложением, присутствующим в его файловой системе.
Это сочетание между вашим подходом 1 и 2.
Ответ 2
Я хотел бы предложить третий подход, который я сделал для статического сгенерированного сайта, отдельное изображение сборки.
В этом подходе ваш основной Dockerfile
(тот, что в корне проекта) становится образ построения и разработки, в основном делая все во втором подходе. Тем не менее, вы переопределяете CMD
во время выполнения, что должно деформировать встроенную папку dist
в dist.tar
или аналогичную.
Затем у вас есть другая папка (что-то вроде image
), у которой есть Dockerfile
. Роль этого изображения заключается только в обслуживании содержимого dist.tar
. Итак, мы делаем docker cp <container_id_from_tar_run> /dist
. Затем Dockerfile
просто устанавливает наш веб-сервер и имеет ADD dist.tar /var/www
.
Резюме - это что-то вроде:
- Создайте образ
builder
Docker (который получает рабочую среду без веб-сервера). В данный момент приложение построено. Мы могли бы запустить контейнер в разработке с помощью grunt serve
или что бы команда не запустила наш встроенный сервер разработки.
- Вместо того, чтобы запускать сервер, мы переопределяем команду по умолчанию, чтобы разгрузить нашу папку dist. Что-то вроде
tar -cf /dist.tar /myapp/dist
.
- Теперь у нас есть временный контейнер с артефактом
/dist.tar
. Скопируйте его в папку фактического развертывания Docker, которую мы назвали image
, используя docker cp <container_id_from_tar_run> /dist.tar ./image/
.
- Теперь мы можем создать небольшое изображение Docker без всех зависимостей разработки с
docker build ./image
.
Мне нравится этот подход, потому что он все еще докеры. Все команды в этом подходе - это команды Docker, и вы можете реально уменьшить изображение, которое вы в конечном итоге развертываете.
Если вы хотите проверить изображение с этим подходом в действии, посмотрите https://github.com/gliderlabs/docker-alpine, который использует образ строителя (в построителе ) для создания файлов tar.gz, которые затем копируются в их соответствующую папку Dockerfile
.
Ответ 3
Вариант решения 1 состоит в том, чтобы иметь "родительский → ребенок", который делает сборку проекта очень быстрым.
У меня был бы файл dockerfile:
FROM node
RUN mkdir app
COPY dist/package.json app/package.json
WORKDIR app
RUN npm install
Это обработает установку зависимостей node и добавит другой файл докеров, который будет обрабатывать приложение "установка", например:
FROM image-with-dependencies:v1
ENV NODE_ENV=prod
EXPOSE 9001
COPY dist .
ENTRYPOINT ["npm", "start"]
с этим вы можете продолжить свою разработку, а "сборка" изображения докеров будет быстрее того, что было бы, если вам нужно "переустановить" зависимости node. Если вы установите новые зависимости на node, просто заново создайте образ зависимостей.
Надеюсь, это поможет кому-то.
Привет