Docker-compose:npm安装成功后,卷中没有node_modules

KGo*_*KGo 155 node.js docker ubuntu-14.04 docker-compose

我有一个具有以下服务的应用程序:

  • web/ - 在端口5000上保存并运行python 3 flask Web服务器.使用sqlite3.
  • worker/- 有一个index.js文件,它是队列的工作者.Web服务器使用json API over port与此队列交互9730.工人使用redis进行存储.工作人员还将数据本地存储在文件夹中worker/images/

现在这个问题只涉及到了worker.

worker/Dockerfile

FROM node:0.12

WORKDIR /worker

COPY package.json /worker/
RUN npm install

COPY . /worker/
Run Code Online (Sandbox Code Playgroud)

docker-compose.yml

redis:
    image: redis
worker:
    build: ./worker
    command: npm start
    ports:
        - "9730:9730"
    volumes:
        - worker/:/worker/
    links:
        - redis
Run Code Online (Sandbox Code Playgroud)

当我运行时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>
Run Code Online (Sandbox Code Playgroud)

但是当我这样做时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)
Run Code Online (Sandbox Code Playgroud)

事实证明/worker/node_modules(主机或容器中)没有任何模块存在.

如果在主机上,我npm install,那么一切正常.但我不想这样做.我希望容器处理依赖项.

这里出了什么问题?

(不用说,所有包都在package.json.)

Fre*_*kNS 227

发生这种情况是因为您已将worker目录添加为卷docker-compose.yml,因为在构建期间未装入卷.

当docker构建映像时,将在node_modules目录中创建worker目录,并在那里安装所有依赖项.然后在运行时,worker来自docker外部的目录被挂载到docker实例(没有安装node_modules),隐藏node_modules刚安装的.您可以通过从中删除已装入的卷来验证这一点docker-compose.yml.

解决方法是使用数据卷来存储所有node_modules数据,因为数据卷在worker安装目录之前从构建的docker镜像中复制数据.这可以通过以下方式完成docker-compose.yml:

redis:
    image: redis
worker:
    build: ./worker
    command: npm start
    ports:
        - "9730:9730"
    volumes:
        - worker/:/worker/
        - /worker/node_modules
    links:
        - redis
Run Code Online (Sandbox Code Playgroud)

我不完全确定这是否会对图像的可移植性造成任何问题,但由于您似乎主要使用docker来提供运行时环境,因此这应该不是问题.

如果您想了解更多有关卷的信息,可以在此处找到一个很好的用户指南:https://docs.docker.com/userguide/dockervolumes/

  • 我已经尝试过这种方法,并在依赖项发生变化时碰壁.我重建了图像,启动了新容器,卷`/ worker/node_modules`保持原样(使用旧依赖项).有没有什么技巧可以在重建图像时使用新卷? (32认同)
  • 是否有一个解决方案在2018年,而不必每次在deps改变时"重建--no-cache"? (12认同)
  • 如果其他容器使用它们(即使它们已经死了),似乎docker compose不会删除卷.因此,如果有一些相同类型的死容器(无论出于何种原因),我在之前的评论中描述的场景如下.从我的尝试,使用`docker-compose rm`似乎解决了这个问题,但我相信必须有一个更好更容易的解决方案. (8认同)
  • 很好的答案,最少侵入性和很好的解释! (7认同)
  • 这个解决方案并不是很好,因为它需要在每个`package.json`更改上都有一个`docker rebuild --no-cache`,*可以*经常发生.双卷`node_modules:/ worker/node_modules`的提议似乎很有意思. (5认同)
  • 这种方法的问题是 node_modules 文件夹无法从您的开发机器(容器外)访问 (4认同)
  • 您现在可以使用[`--renew-anon-volumes`](https://docs.docker.com/compose/reference/up/),它将重新创建匿名卷,而不是先前容器中的数据。 (2认同)
  • 到了 2023 年,我们是否没有一个解决方案,让容器中的 Nodejs 应用程序能够构建镜像并在任何机器上开发它,并且具有依赖关系并且一切正常? (2认同)

jsa*_*san 31

node_modules将覆盖该文件夹,并且容器中不再可访问该文件夹.我正在使用本机模块加载策略从卷中取出文件夹:

/data/node_modules/ # dependencies installed here
/data/app/ # code base
Run Code Online (Sandbox Code Playgroud)

Dockerfile:

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

COPY . /data/app/
WORKDIR /data/app/
Run Code Online (Sandbox Code Playgroud)

node_modules 无法从容器外部访问,因为它包含在图像中.

  • 缺点是:没有更多的IDE自动完成功能,没有帮助,没有良好的开发经验。现在还需要将所有内容都安装在主机上,但是使用docker并不是因为dev-host不需要任何项目就能使用项目吗? (2认同)

Gui*_*ent 29

@FrederikNS提供的解决方案有效,但我更喜欢显式命名我的node_modules卷.

我的project/docker-compose.yml文件(docker-compose版本1.6+):

version: '2'
services:
  frontend:
    ....
    build: ./worker
    volumes:
      - ./worker:/worker
      - node_modules:/worker/node_modules
    ....
volumes:
  node_modules:
Run Code Online (Sandbox Code Playgroud)

我的文件结构是:

project/
   ??? worker/
   ?     ?? Dockerfile
   ??? docker-compose.yml
Run Code Online (Sandbox Code Playgroud)

它会创建一个名为的卷,project_node_modules并在每次启动应用程序时重新使用它.

docker volume ls看起来像这样:

DRIVER              VOLUME NAME
local               project1_mysql
local               project1_node_modules
local               project2_postgresql
local               project2_node_modules
Run Code Online (Sandbox Code Playgroud)

  • 试图解决同样的问题几个小时,并提出了相同的解决方案我自己.你的答案应该是评价最高的,但是我猜,ppl没有得到你的答案,因为你将你的卷命名为"node_modules",并且所有读者都错过了创建新卷的事实.在阅读代码时,我认为你只是"重新安装"locale node_modules文件夹并放弃了这个想法.也许您应该将卷名称编辑为类似"container_node_modules"的内容以使其清晰.:) (3认同)
  • 虽然这个“可行”,但您在docker中规避了一个真正的概念:应将所有依赖项都纳入其中,以实现最大的可移植性。您必须先运行其他命令,否则无法移动此图像 (2认同)

小智 20

我最近有类似的问题.您可以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/
Run Code Online (Sandbox Code Playgroud)

泊坞窗,compose.yml

redis:
    image: redis
worker:
    build: ./worker
    command: npm start
    ports:
        - "9730:9730"
    volumes:
        - worker/:/worker/
    links:
        - redis
Run Code Online (Sandbox Code Playgroud)

  • @FrederikNS的最高投票解决方案很有用,我是如何根据[本文]解决我本地卷的不同问题覆盖容器的`node_modules`(http://jdlm.info/articles/2016/03/06/课建设节点-APP-docker.html).但它让我体验了[本期](https://github.com/docker/compose/issues/4337).这个解决方案创建一个单独的目录来复制你的`package.json`,在那里运行`npm install`,然后在`docker-compose.yml`中指定`NODE_PATH`环境变量指向`node_modules`文件夹.该目录工作和感觉正确. (5认同)

hol*_*lms 16

有优雅的解决方案:

只是挂载不是整个目录,而只是挂载app目录.这样你就不会有麻烦了npm_modules.

例:

  frontend:
    build:
      context: ./ui_frontend
      dockerfile: Dockerfile.dev
    ports:
    - 3000:3000
    volumes:
    - ./ui_frontend/src:/frontend/src
Run Code Online (Sandbox Code Playgroud)

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
Run Code Online (Sandbox Code Playgroud)

  • 这是一个很好且快速的解决方案,但它需要在新的依赖项安装后重建和修剪。 (3认同)

JAM*_*JAM 13

更新:使用@FrederikNS提供的解决方案.

我遇到了同样的问题.当文件夹/worker安装到容器时 - 它的所有内容都将同步(因此如果你没有本地文件,node_modules文件夹将会消失.)

由于基于操作系统的不兼容的npm软件包,我不能只在本地安装模块 - 然后启动容器,所以..

我的解决方案是将源包装在一个src文件夹中,然后node_modules使用这个index.js文件链接到该文件夹.因此,该index.js文件现在是我的应用程序的起点.

当我运行容器时,我将/app/src文件夹挂载到我的本地src文件夹.

所以容器文件夹看起来像这样:

/app
  /node_modules
  /src
    /node_modules -> ../node_modules
    /app.js
  /index.js
Run Code Online (Sandbox Code Playgroud)

很难看,但它有效..

  • 哦,亲爱的主...我不敢相信我也坚持了! (3认同)

Jus*_*ton 9

由于Node.js加载模块的方式,node_modules可以在源代码的路径中的任何位置.例如,把你的源头/worker/src的和package.json/worker,所以/worker/node_modules是他们安装位置.


ser*_*rgy 6

将容器中的node_modules安装到与项目文件夹不同的位置,并将NODE_PATH设置为node_modules文件夹有助于我(你需要重建容器).

我正在使用docker-compose.我的项目文件结构:

-/myproject
--docker-compose.yml
--nodejs/
----Dockerfile
Run Code Online (Sandbox Code Playgroud)

泊坞窗,compose.yml:

version: '2'
services:
  nodejs:
    image: myproject/nodejs
    build: ./nodejs/.
    volumes:
      - ./nodejs:/workdir
    ports:
      - "23005:3000"
    command: npm run server
Run Code Online (Sandbox Code Playgroud)

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
Run Code Online (Sandbox Code Playgroud)


Pau*_*tte 5

我看到节点开发环境有两个单独的要求...将源代码安装到容器中,然后从容器中安装node_modules(对于您的IDE)。为了完成第一个任务,你需要进行通常的安装,但不是所有的事情......只是你需要的东西

volumes:
    - worker/src:/worker/src
    - worker/package.json:/worker/package.json
    - etc...
Run Code Online (Sandbox Code Playgroud)

(不这样做的原因- /worker/node_modules是因为 docker-compose 将在运行之间保留该卷,这意味着您可能会偏离映像中的实际内容(违背了不仅仅是从主机绑定安装的目的))。

第二个其实更难。我的解决方案有点黑客,但它有效。我有一个脚本用于在主机上安装 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
Run Code Online (Sandbox Code Playgroud)


Ege*_*gel 5

还有一些简单的解决方案,没有将node_module目录映射到另一个卷.它将把npm软件包安装到最终的CMD命令中.

这种方法的缺点:

  • 运行npm install每次运行容器(从开关npmyarn也可能会加速这一进程中位).

工人/ Dockerfile

FROM node:0.12
WORKDIR /worker
COPY package.json /worker/
COPY . /worker/
CMD /bin/bash -c 'npm install; npm start'
Run Code Online (Sandbox Code Playgroud)

泊坞窗,compose.yml

redis:
    image: redis
worker:
    build: ./worker
    ports:
        - "9730:9730"
    volumes:
        - worker/:/worker/
    links:
        - redis
Run Code Online (Sandbox Code Playgroud)