Docker-compose:在npm安装成功解决方案后,卷中没有node_modules

问题描述 投票:136回答:12

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

  • web/ - 在端口5000上保存并运行python 3 flask Web服务器。使用sqlite3。
  • worker/ - 有一个index.js文件,它是队列的工作者。 Web服务器使用端口9730上的json API与此队列进行交互。工人使用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 [email protected] No README data

> [email protected] 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。)

node.js docker ubuntu-14.04 docker-compose
12个回答
212
投票

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

当docker构建映像时,node_modules目录在worker目录中创建,并且所有依赖项都安装在那里。然后在运行时,来自docker外部的worker目录被挂载到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

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

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


3
投票

我在节点开发环境中看到了两个单独的要求...将源代码安装到容器中,然后从容器(用于IDE)安装node_modules。要完成第一个,你会做通常的安装,但不是一切......只需要你需要的东西

redis:
    image: redis
worker:
    build: ./worker
    ports:
        - "9730:9730"
    volumes:
        - worker/:/worker/
    links:
        - redis

(不做volumes: - worker/src:/worker/src - worker/package.json:/worker/package.json - etc... 的原因是因为docker-compose会在运行之间保持该量,这意味着你可以偏离图像中的实际内容(不仅仅是从主机绑定挂载的目的))。

第二个实际上更难。我的解决方案有点hackish,但它的工作原理。我有一个脚本在我的主机上安装node_modules文件夹,我只需要记得每当我更新package.json时调用它(或者,将它添加到在本地运行docker-compose build的make目标)。

- /worker/node_modules

2
投票

在我看来,我们不应该在Dockerfile中使用install_node_modules: docker build -t building . docker run -v `pwd`/node_modules:/app/node_modules building npm install 。相反,我们可以在运行正式节点服务之前使用bash启动容器来安装依赖项

RUN npm install

1
投票

您可以在Dockerfile中尝试这样的事情:

docker run -it -v ./app:/usr/src/app  your_node_image_name  /bin/bash
root@247543a930d6:/usr/src/app# npm install

然后你应该像这样使用音量:

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

startscript应该是工作者存储库的一部分,如下所示:

volumes:
  - worker/:/worker:rw

因此,node_modules是工作卷的一部分并获得同步,并且当所有内容都启动时,将执行npm脚本。


28
投票

node_modules文件夹被卷覆盖,容器中无法访问。我正在使用native module loading strategy从卷中取出文件夹:

/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/

qazxsw poi无法从容器外部访问,因为它包含在图像中。


25
投票

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

我的node_modules文件(docker-compose版本1.6+):

project/docker-compose.yml

我的文件结构是:

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

17
投票

我最近有类似的问题。您可以在其他地方安装DRIVER VOLUME NAME local project1_mysql local project1_node_modules local project2_postgresql local project2_node_modules 并设置node_modules环境变量。

在下面的例子中,我将NODE_PATH安装到node_modules

工人/ Dockerfile

/install

泊坞窗,compose.yml

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/

16
投票

有优雅的解决方案:

只是挂载不是整个目录,而只是挂载app目录。这样你就不会有redis: image: redis worker: build: ./worker command: npm start ports: - "9730:9730" volumes: - worker/:/worker/ links: - redis 的麻烦。

例:

npm_modules

dock而file.Dev:

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

11
投票

UPDATE: Use the 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 provided by @FrederikNS.

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

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

我的解决方案是将源包装在/worker文件夹中,然后使用srcnode_modules链接到该文件夹​​。所以,this index.js file文件现在是我的应用程序的起点。

当我运行容器时,我将index.js文件夹安装到我当地的/app/src文件夹中。

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

src

它很难看,但它有效..


9
投票

由于/app /node_modules /src /node_modules -> ../node_modules /app.js /index.js the way Node.js loads modules可以在您的源代码的路径中的任何位置。例如,将你的源码放在node_modules和你的/worker/srcpackage.json,所以/worker就是他们安装的地方。


6
投票

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

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

/worker/node_modules

码头工人,compose.yml:

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

nodejs文件夹中的Dockerfile:

version: '2'
services:
  nodejs:
    image: myproject/nodejs
    build: ./nodejs/.
    volumes:
      - ./nodejs:/workdir
    ports:
      - "23005:3000"
    command: npm run server

5
投票

还有一些简单的解决方案,无需将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 目录映射到另一个卷。它将把npm软件包安装到最终的CMD命令中。

这种方法的缺点:

  • 每次运行容器时运行node_module(从npm install切换到npm也可能会加快这个过程)。

worker/Dockerfile

yarn

docker-compose.yml

FROM node:0.12
WORKDIR /worker
COPY package.json /worker/
COPY . /worker/
CMD /bin/bash -c 'npm install; npm start'
© www.soinside.com 2019 - 2024. All rights reserved.