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

Web / -在端口5000上持有并运行一个python3 flask Web服务器。使用sqlite3。 Worker / -有一个index.js文件,它是队列的Worker。web服务器通过9730端口使用json API与这个队列进行交互。worker使用redis进行存储。worker还将数据存储在本地的worker/images/文件夹中

现在这个问题只与工人有关。

工人/ 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中。)


当前回答

我尝试了这个页面上最流行的答案,但遇到了一个问题:我的Docker实例中的node_modules目录会被缓存在命名或未命名的挂载点中,然后会覆盖作为Docker构建过程一部分构建的node_modules目录。因此,我将新模块添加到包中。json不会出现在Docker实例中。

幸运的是,我找到了这个很棒的页面,它解释了发生了什么,并提供了至少3种方法来解决它: https://burnedikt.com/dockerized-node-development-and-mounting-node-volumes/

其他回答

这是因为您已经将工作目录作为卷添加到docker-compose中。Yml,因为在构建期间没有挂载卷。

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

一个解决方案是使用一个数据卷来存储所有的node_modules,因为数据卷在工作目录被挂载之前从构建的docker映像中复制数据。这可以在docker-compose中完成。你是这样说的:

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/

EDIT: Docker已经改变了它的语法,要求在相对于Docker -compose的文件中挂载一个前导。/。yml文件。

还有一些简单的解决方案,不需要将node_module目录映射到另一个卷。它将把安装npm包移动到最后的CMD命令中。

这种方法的缺点: 每次运行container时都运行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'

docker-compose.yml

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

由于Node.js加载模块的方式,node_modules可以位于源代码路径中的任何位置。例如,将源代码放在/worker/src和包。Json在/worker中,所以/worker/node_modules是它们被安装的地方。

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

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

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

docker-compose.yml:

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

看台里的游戏

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

如果你不使用docker-compose,你可以这样做:

FROM node:10

WORKDIR /usr/src/app

RUN npm install -g @angular/cli

COPY package.json ./
RUN npm install

EXPOSE 5000

CMD ng serve --port 5000 --host 0.0.0.0

然后构建docker build -t myname。docker运行——rm -it -p 5000:5000 -v "$PWD":/usr/src/app/ -v /usr/src/app/node_modules myname