这是一个非常热门的主题,但我从来没有真正找到一个解决办法。
正如您可能知道的,当我们在容器中有一个卷,并且我们从一个Dockerfile(使用默认权限)安装依赖项(使用npm i
或其他内容)时,Npm将在容器中创建一个node_modules
文件夹,并使用root:root
访问权限。
我在使用此方法时遇到了两个问题(在本地/dev环境中):
node_modules
文件夹只存在于容器中,但宿主的IDE/LSP需要此文件夹才能正常工作(模块导入、类型定义等)。
1.如果主机要安装/更新软件包(npm i ...
等),则必须重新启动并为要更新的node_modules
文件夹重建容器。
所以我想出了另一个主意,如果我在Dockerfile中使用CMD
安装依赖项会怎样(或docker-compose
文件中服务的command
属性)并使用一个卷,这样node_modules
就可以与主机共享。不幸的是,这种方法引入了新的问题。例如,node_modules
具有root:root
权限访问,因此,如果您的主机用户名为“named”,并且不具有相同的uid
和gid
,则需要运行root访问命令更新node_modules
(sudo npm i ...
)。
以下是我的当前配置:docker-compose.yml
:
version: '3.7'
services:
app:
container_name: 'app_DEV'
build: .
command: sh -c "yarn install && node ./server.js"
volumes:
- ./:/usr/src/app
ports:
- 3000:3000
tty: true
Dockerfile
:
FROM node:12.8.1-alpine
WORKDIR /usr/src/app
COPY . .
package.json
:
{
"dependencies": {
"express": "^4.17.1"
}
}
server.js
:
const app = require('express')();
app.get('/', (req, res) => {
res.send('Hello');
});
app.listen(3000, () => console.log('App is listening on port 3000'));
然后,您可以尝试运行docker-compose up
并执行ls -la
:
-rw-r--r-- 1 mint mint 215 août 23 16:39 docker-compose.yml
-rw-r--r-- 1 mint mint 56 août 23 16:29 Dockerfile
drwxr-xr-x 52 root root 4096 août 23 16:31 node_modules
-rw-r--r-- 1 mint mint 53 août 23 16:31 package.json
-rw-r--r-- 1 mint mint 160 août 23 16:29 server.js
正如你所看到的每个文件/文件夹都有mint:mint
访问除了node_modules
(mint
是我的主机的用户).
所以总结一下我的问题:有没有更好的方法来管理与Docker容器的NodeJS依赖关系?
3条答案
按热度按时间f2uvfpb91#
在你的例子中,为了让它以你想要的方式工作,你应该在docker文件中添加
USER
,在docker-compose. yml文件中添加user:
。停靠文件:
docker-compose.yml:
无论如何,我们遇到了类似的情况,我们选择了一种不同的方法。我们决定避免在主机和容器之间共享node_modules文件夹(如果您与使用不同操作系统的同事一起工作,这是一种很糟糕的行为),而是避免在docker-compose. yml中挂载node_modules文件夹。
在我们的示例中,Dockerfile看起来如下所示:
docker-compose.yml看起来像这样:
这样我们就可以在主机上创建node_modules(可以用于测试、开发等),并安全地保持docker容器的内容不变。这种方法的缺点是我们的开发人员必须在主机上运行
npm ci
,并且在每次package.json更改时都需要重新创建映像。ilmyapht2#
自从我最初写这个问题以来已经过去了几年。我想回来分享一个不同的观点,因为我的POV从那时起发生了一些变化,我现在认为我想要使用容器的方式是不正确的。
首先,在容器中创建的文件/文件夹不应该在容器外修改。在本文中,修改
node_modules
文件夹的任何命令都应该在容器内运行。我知道这可能有点麻烦,但我认为只要使用docker-compose就可以了(例如docker-compose exec app npm i
)。我认为它更适合OCI容器的使用方式。在操作系统兼容性方面,由于所有(与开发环境相关的)操作都应该在容器内部完成,因此不应该有任何问题。注意,我看到过一些组织发布的开发映像既有卸载的,也有预装的依赖项。我认为这两种方式都很好,只是这真的取决于你是否想要一个轻量级的开发映像。
fiei3ece3#
一般来说,我不会推荐这种方法,因为你是主机,容器可能无法共享相同的模块。例如,如果你的团队中有人使用Windows,而你有一些编译过的模块(如node-sass或bcrypt),共享这些模块会使容器或主机无法使用它们。
另一个经常出现的解决方案是在你的Docker文件中分离node_modules安装步骤,并覆盖这个步骤的卷挂载。每次你想添加一个包时,你仍然需要重建Docker映像,但这种情况(可能)不应该经常发生。
以下是Dockerfile的相关部分:
然后,在您的Dock合成文件中:
确保你在根目录挂载之后******包含了
/usr/src/app/node_modules/
卷,因为它会覆盖容器中的/usr/src/app/node_modules/
。