У меня есть приложение со следующими услугами:
web/
- удерживает и запускает веб-сервер с питоном 3 на порту 5000. Использует sqlite3.worker/
- естьindex.js
файл, который является работником для очереди. веб-сервер взаимодействует с этой очередью, используя json API через порт9730
. Работник использует Redis для хранения. Рабочий также хранит данные локально в папкеworker/images/
Теперь этот вопрос касается только worker
.
worker/Dockerfile
FROM node:0.12
WORKDIR /worker
COPY package.json /worker/
RUN npm install
COPY . /worker/
docker-compose.yml
redis:
image: redis
worker:
build: ./worker
command: npm start
ports:
- "9730:9730"
volumes:
- worker/:/worker/
links:
- redis
Когда я запускаю docker-compose build
, все работает как положено, и все модули npm устанавливаются так, /worker/node_modules
как я ожидал.
npm WARN package.json unfold@1.0.0 No README data
> phantomjs@1.9.2-6 install /worker/node_modules/pageres/node_modules/screenshot-stream/node_modules/phantom-bridge/node_modules/phantomjs
> node install.js
<snip>
Но когда я это docker-compose up
вижу, я вижу эту ошибку:
worker_1 | Error: Cannot find module 'async'
worker_1 | at Function.Module._resolveFilename (module.js:336:15)
worker_1 | at Function.Module._load (module.js:278:25)
worker_1 | at Module.require (module.js:365:17)
worker_1 | at require (module.js:384:17)
worker_1 | at Object.<anonymous> (/worker/index.js:1:75)
worker_1 | at Module._compile (module.js:460:26)
worker_1 | at Object.Module._extensions..js (module.js:478:10)
worker_1 | at Module.load (module.js:355:32)
worker_1 | at Function.Module._load (module.js:310:12)
worker_1 | at Function.Module.runMain (module.js:501:10)
Оказывается, ни один из модулей не присутствует в /worker/node_modules
(на хосте или в контейнере).
Если на хосте я npm install
, то все работает просто отлично. Но я не хочу этого делать. Я хочу, чтобы контейнер обрабатывал зависимости.
Что здесь не так?
(Излишне говорить, что все пакеты в package.json
.)
volumes: - worker/:/worker/
блок изdocker-compose.yml
файла. Эта строка перезаписывает папку, созданную командой COPY.When I run docker-compose build, everything works as expected and all npm modules are installed in /worker/node_modules as I'd expect.
- Как ты это проверил?Ответы:
Это происходит потому, что вы добавили свой
worker
каталог в качестве тома в свойdocker-compose.yml
, так как том не смонтирован во время сборки.Когда docker создает образ,
node_modules
каталог создается внутриworker
каталога, и там устанавливаются все зависимости. Затем во время выполненияworker
каталог из внешнего докера монтируется в экземпляр докера (на котором нет установленногоnode_modules
), скрываяnode_modules
только что установленный вами. Вы можете проверить это, удалив подключенный том из вашегоdocker-compose.yml
.Обходной путь - использовать том данных для хранения всех
node_modules
данных, так как тома данных копируют данные из встроенного образа докера доworker
монтирования каталога. Это можно сделатьdocker-compose.yml
так:Я не совсем уверен, накладывает ли это какие-либо проблемы на переносимость образа, но, поскольку кажется, что вы в первую очередь используете docker для обеспечения среды выполнения, это не должно быть проблемой.
Если вы хотите узнать больше о томах, есть хорошее руководство пользователя, доступное здесь: https://docs.docker.com/userguide/dockervolumes/
РЕДАКТИРОВАТЬ: С тех пор Docker изменил свой синтаксис, требуя
./
указания для монтирования в файлах относительно файла docker-compose.yml.источник
/worker/node_modules
остался прежним (со старыми зависимостями). Есть ли хитрость, как использовать новый объем при восстановлении изображения?docker-compose rm
Судя по тому, что я пробовал, использование, кажется, решает эту проблему, но я считаю, что должно быть лучшее и более простое решение.rebuild --no-cache
каждый раз менять дек?node_modules
Папка перезаписывается по объему и не более доступными в контейнере. Я использую встроенную стратегию загрузки модулей, чтобы вынуть папку из тома:Dockerfile:
node_modules
Каталог не доступен снаружи контейнера , так как он входит в образ.источник
node_modules
недоступен снаружи контейнера, но на самом деле не является недостатком;)docker-compose run app npm install
вы создадите node_modules в текущем каталоге, и вам больше не нужно перестраивать образ.Решение, предоставленное @FrederikNS, работает, но я предпочитаю явно называть мой том node_modules.
Мой
project/docker-compose.yml
файл (docker-compose version 1.6+):моя файловая структура:
Он создает именованный том
project_node_modules
и использует его каждый раз, когда я запускаю свое приложение.Моя
docker volume ls
выглядит так:источник
У меня недавно была похожая проблема. Вы можете установить в
node_modules
другом месте и установитьNODE_PATH
переменную среды.В приведенном ниже примере я установил
node_modules
в/install
работник / Dockerfile
докер-compose.yml
источник
node_modules
основе этой статьи . Но это привело меня к проблеме . Это решение, заключающееся в создании отдельного каталога для копированияpackage.json
в него, его запускаnpm install
, а затем указанияNODE_PATH
переменной среды,docker-compose.yml
указывающей наnode_modules
папку этого каталога, работает и чувствует себя хорошо.npm install
на хосте? Похожеnode_modules
, появится на хосте и будет отражен в контейнере, принимая приоритет надNODE_PATH
. Таким образом, контейнер будет использовать node_modules от хоста.Есть элегантное решение:
Просто смонтируйте не весь каталог, а только каталог приложения. Таким образом, у вас не будет проблем с
npm_modules
.Пример:
Dockerfile.dev:
источник
ОБНОВЛЕНИЕ: используйте решение, предоставленное @FrederikNS.
Я столкнулся с той же проблемой. Когда папка
/worker
подключена к контейнеру - все ее содержимое будет синхронизировано (поэтому папка node_modules исчезнет, если у вас ее нет локально).Из-за несовместимых пакетов npm, основанных на ОС, я не мог просто установить модули локально - затем запустить контейнер, так что ..
Мое решение для этого было заключить в исходный код в
src
папку, а затем создать ссылкуnode_modules
на эту папку, используя этот файл index.js . Итак,index.js
файл теперь является отправной точкой моего приложения.Когда я запускаю контейнер, я монтировал
/app/src
папку в свой локальныйsrc
папку.Итак, папка контейнера выглядит примерно так:
Это некрасиво , но это работает ..
источник
Благодаря тому, как Node.js загружает модули , он
node_modules
может находиться где угодно на пути к вашему исходному коду. Например, поместите источник в/worker/src
и вашpackage.json
ин/worker
, так/worker/node_modules
, где они установлены.источник
Установка node_modules в контейнере, отличном от папки проекта, и установка NODE_PATH в папку node_modules мне помогают (вам нужно перестроить контейнер).
Я использую docker-compose. Структура моего проекта:
докер-compose.yml:
Dockerfile в папке nodejs:
источник
NODE_PATH
был ключом для меня.CMD npm start
не использует указанный NODE_PATH.Существует также простое решение без отображения
node_module
каталога в другой том. Это собирается перенести установку пакетов npm в последнюю команду CMD.работник / Dockerfile
докер-compose.yml
источник
Есть два отдельных требования, которые я вижу для сред разработки узлов: смонтируйте ваш исходный код в контейнер и смонтируйте node_modules FROM из контейнера (для вашей IDE). Чтобы выполнить первое, вы делаете обычное монтирование, но не все ... только то, что вам нужно
(причина не делать
- /worker/node_modules
том, что docker-compose сохранит этот объем между запусками, а это означает, что вы можете отличаться от того, что на самом деле находится в образе (отказываясь от цели не просто привязки к вашему хосту)).Второй на самом деле сложнее. Мое решение немного хакерское, но оно работает. У меня есть скрипт для установки папки node_modules на моем хост-компьютере, и я просто должен помнить, чтобы вызывать его всякий раз, когда обновляю package.json (или добавляю его в цель make, которая выполняет сборку docker-compose локально).
источник
На мой взгляд, мы не должны
RUN npm install
в Dockerfile. Вместо этого мы можем запустить контейнер, используя bash для установки зависимостей перед запуском службы формального узлаисточник
node_modules
стойкость даже после удаления контейнера, вы также должны знать, когда или когда не следует делать этоnpm install
вручную. ОП предлагает делать это при каждой сборке образа . Вы можете сделать это, но вам не нужно также использовать объем для этого. На каждой сборке модули будут обновлены в любом случае.Вы можете попробовать что-то вроде этого в вашем Dockerfile:
Тогда вы должны использовать объем следующим образом:
Стартовый скрипт должен быть частью вашего рабочего репозитория и выглядит так:
Таким образом, node_modules являются частью вашего рабочего тома и синхронизируются, а сценарии npm выполняются, когда все заканчивается.
источник
Вы также можете отказаться от своего Dockerfile, из-за его простоты, просто используйте базовое изображение и укажите команду в вашем файле compose:
Это особенно полезно для меня, потому что мне просто нужна среда изображения, но я работаю с файлами вне контейнера, и я думаю, что это то, что вы тоже хотите сделать.
источник