Docker-compose: node_modules не присутствует в томе после завершения установки npm

Вопрос:У меня есть приложение со следующими службами: web/ - хранит и запускает веб-сервер на флэке python 3 на порту 5000. Использует sqlite3. worker/ - имеет файл index.js, который является рабочим для очереди. веб-сервер взаимодействует с этой очередью, используя json API через порт 9730. Рабочий использует redis для хранения. Рабочий также сохраняет данные локально в папке

Вопрос:

У меня есть приложение со следующими службами:

  • web/ – хранит и запускает веб-сервер на флэке python 3 на порту 5000. Использует sqlite3.
  • worker/ – имеет файл index.js, который является рабочим для очереди. веб-сервер взаимодействует с этой очередью, используя json API через порт 9730. Рабочий использует redis для хранения. Рабочий также сохраняет данные локально в папке worker/images/

Теперь этот вопрос касается только worker.

Содержание

  1. worker/Dockerfile
  2. docker-compose.yml
  3. Рабочий /Dockerfile
  4. докер-compose.yml
  5. ОБНОВЛЕНИЕ: используйте решение, предоставленное @FrederikNS.
  6. работник /Dockerfile
  7. докер-compose.yml

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.)

Ответ №1

Это происходит потому, что вы добавили каталог worker в качестве тома в ваш docker-compose.yml, поскольку том не монтируется во время сборки.

Когда docker создает изображение, каталог node_modules создается в каталоге worker, и там устанавливаются все зависимости. Затем во время выполнения каталог worker из внешнего докера монтируется в экземпляр докера (который не имеет установленного node_modules), скрывая только что установленный node_modules. Вы можете проверить это, удалив установленный том из docker-compose.yml.

Обходной путь заключается в использовании тома данных для хранения всего node_modules, поскольку копии томов данных в данных из встроенного изображения докеров перед установкой каталога worker. Это можно сделать в docker-compose.yml следующим образом:

redis: image: redis worker: build: ./worker command: npm start ports: — «9730:9730» volumes: — worker/:/worker/ — /worker/node_modules links: — redis

Я не совсем уверен, что это накладывает какие-либо проблемы на переносимость изображения, но, как кажется, в первую очередь вы используете докер для обеспечения среды выполнения, это не должно быть проблемой.

Если вы хотите больше узнать о томах, здесь доступно хорошее руководство пользователя: https://docs.docker.com/userguide/dockervolumes/

Ответ №2

Папка node_modules перезаписывается томом и больше недоступна в контейнере. Я использую стратегию загрузки загружаемого модуля, чтобы вынуть папку из тома:

/data/node_modules/ # dependencies installed here /data/app/ # code base

Dockerfile:

COPY package.json /data/ WORKDIR /data/ RUN npm install ENV PATH /data/node_modules/.bin:$PATH COPY . /data/app/ WORKDIR /data/app/

node_modules недоступен извне контейнера, потому что он включен в изображение.

Ответ №3

Решение, предоставляемое @FrederikNS, работает, но я предпочитаю явно указывать свой том node_modules.

Мой project/docker-compose.yml файл (docker-compose version 1.6+):

version: ‘2’ services: frontend: …. build: ./worker volumes: — ./worker:/worker — node_modules:/worker/node_modules …. volumes: node_modules:

моя файловая структура:

project/ │── worker/ │  └─ Dockerfile └── docker-compose.yml

Он создает том с именем project_node_modules и повторно использует его каждый раз, когда я загружаю свое приложение.

Мой docker volume ls выглядит следующим образом:

DRIVER VOLUME NAME local project1_mysql local project1_node_modules local project2_postgresql local project2_node_modules Ответ №4

У меня недавно была аналогичная проблема. Вы можете установить node_modules в другое место и установить переменную среды NODE_PATH.

В приведенном ниже примере я установил node_modules в /install

Рабочий /Dockerfile

FROM node:0.12 RUN [«mkdir», «/install»] ADD [«./package.json», «/install»] WORKDIR /install RUN npm install —verbose ENV NODE_PATH=/install/node_modules WORKDIR /worker COPY . /worker/

докер-compose.yml

redis: image: redis worker: build: ./worker command: npm start ports: — «9730:9730» volumes: — worker/:/worker/ links: — redis Ответ №5

Там элегантное решение:

Просто установите не весь каталог, а только каталог приложения. Таким образом, у вас не будет проблем с npm_modules.

Пример:

frontend: build: context: ./ui_frontend dockerfile: Dockerfile.dev ports: — 3000:3000 volumes: — ./ui_frontend/src:/frontend/src

Dockerfile.dev:

FROM node:7.2.0 #Show colors in docker terminal ENV COMPOSE_HTTP_TIMEOUT=50000 ENV TERM=»xterm-256color» COPY . /frontend WORKDIR /frontend RUN npm install update RUN npm install —global typescript RUN npm install —global webpack RUN npm install —global webpack-dev-server RUN npm install —global karma protractor RUN npm install CMD npm run server:dev Ответ №6

ОБНОВЛЕНИЕ: используйте решение, предоставленное @FrederikNS.

Я столкнулся с той же проблемой. Когда папка /worker монтируется в контейнер – все его содержимое будет синхронизировано (поэтому папка node_modules исчезнет, если у вас ее нет локально).

Из-за несовместимых пакетов npm, основанных на ОС, я не мог просто установить модули локально – затем запустить контейнер, так что..

Мое решение для этого было node_modules в исходный код в папку src, а затем связать node_modules в эту папку, используя этот файл index.js. Итак, файл index.js теперь является отправной точкой моего приложения.

Когда я запустил контейнер, я /app/src папку /app/src к своей локальной папке src.

Таким образом, папка контейнера выглядит примерно так:

/app /node_modules /src /node_modules -> ../node_modules /app.js /index.js

Это некрасиво, но это работает..

Ответ №7

Благодаря тому, что Node.js загружает модули, node_modules могут находиться где угодно на пути к вашему исходному коду. Например, поместите ваш источник в /worker/src а ваш package.json в /worker, чтобы они были установлены в /worker/node_modules.

Ответ №8

Установка node_modules в контейнере в отличие от папки проекта, а установка NODE_PATH в вашу папку node_modules помогает мне (вам нужно перестроить контейнер).

Я использую docker-compose. Моя файловая структура проекта:

-/myproject —docker-compose.yml —nodejs/ —-Dockerfile

докер-compose.yml:

version: ‘2’ services: nodejs: image: myproject/nodejs build: ./nodejs/. volumes: — ./nodejs:/workdir ports: — «23005:3000» command: npm run server

Dockerfile в папке nodejs:

FROM node:argon RUN mkdir /workdir COPY ./package.json /workdir/. RUN mkdir /data RUN ln -s /workdir/package.json /data/. WORKDIR /data RUN npm install ENV NODE_PATH /data/node_modules/ WORKDIR /workdir Ответ №9

Существует также некоторое простое решение без отображения каталога node_module в другой том. Он собирается переместить установки пакетов npm в окончательную команду CMD.

Недостаток этого подхода:

  • запускайте npm install каждый раз, когда вы запускаете контейнер (переход от npm в yarn может также немного ускорить этот процесс).

работник /Dockerfile

FROM node:0.12 WORKDIR /worker COPY package.json /worker/ COPY . /worker/ CMD /bin/bash -c ‘npm install; npm start’

докер-compose.yml

redis: image: redis worker: build: ./worker ports: — «9730:9730» volumes: — worker/:/worker/ links: — redis Ответ №10

Есть два отдельных требования, которые я вижу для сред node dev… смонтируйте исходный код в контейнере и смонтируйте node_modules из контейнера (для вашей IDE). Чтобы выполнить первое, вы делаете обычное монтирование, но не все… только то, что вам нужно

volumes: — worker/src:/worker/src — worker/package.json:/worker/package.json — etc…

(причина не делать — /worker/node_modules заключается в том, что docker-compose будет сохранять этот том между прогонами, то есть вы можете расходиться с тем, что на самом деле находится на изображении (побеждая цель не просто привязать установку с вашего хоста)).

Второй – на самом деле сложнее. Мое решение немного хакерское, но оно работает. У меня есть script, чтобы установить папку node_modules на моем хост-компьютере, и я просто должен помнить, чтобы вызывать ее всякий раз, когда я обновляю package.json(или добавляю его в цель make, которая запускает сборку docker-compose).

install_node_modules: docker build -t building . docker run -v `pwd`/node_modules:/app/node_modules building npm install Ответ №11

На мой взгляд, мы не должны RUN npm install в Dockerfile. Вместо этого мы можем запустить контейнер, используя bash для установки зависимостей перед запуском службы формального узла

docker run -it -v ./app:/usr/src/app your_node_image_name /bin/bash root@247543a930d6:/usr/src/app# npm install Ответ №12

Вы можете попробовать что-то вроде этого в вашем Dockerfile:

FROM node:0.12 WORKDIR /worker CMD bash ./start.sh

Тогда вы должны использовать объем следующим образом:

volumes: — worker/:/worker:rw

Начальный скрипт должен быть частью вашего рабочего репозитория и выглядит следующим образом:

#!/bin/sh npm install npm start

Таким образом, node_modules являются частью вашего рабочего тома и синхронизируются, а сценарии npm выполняются, когда все работает.

Оцените статью
Добавить комментарий