我有一个应用程序与以下服务:
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-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文件。
@FrederikNS提供的解决方案是可行的,但我更喜欢显式地命名我的node_modules卷。
我的项目/ 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卷ls是这样的:
DRIVER VOLUME NAME
local project_mysql
local project_node_modules
local project2_postgresql
local project2_node_modules
如果希望node_modules文件夹在开发期间对主机可用,可以在启动容器时安装依赖项,而不是在构建时安装。我这样做是为了让语法高亮显示在编辑器中工作。
Dockerfile
# We're using a multi-stage build so that we can install dependencies during build-time only for production.
# dev-stage
FROM node:14-alpine AS dev-stage
WORKDIR /usr/src/app
COPY package.json ./
COPY . .
# `yarn install` will run every time we start the container. We're using yarn because it's much faster than npm when there's nothing new to install
CMD ["sh", "-c", "yarn install && yarn run start"]
# production-stage
FROM node:14-alpine AS production-stage
WORKDIR /usr/src/app
COPY package.json ./
RUN yarn install
COPY . .
dockerignore。
将node_modules添加到.dockerignore中,以防止Dockerfile运行COPY时复制node_modules。我们使用卷引入node_modules。
**/node_modules
docker-compose.yml
node_app:
container_name: node_app
build:
context: ./node_app
target: dev-stage # `production-stage` for production
volumes:
# For development:
# If node_modules already exists on the host, they will be copied
# into the container here. Since `yarn install` runs after the
# container starts, this volume won't override the node_modules.
- ./node_app:/usr/src/app
# For production:
#
- ./node_app:/usr/src/app
- /usr/src/app/node_modules