【问题标题】:Sharing the `node_modules` folder between the container and the host在容器和主机之间共享 `node_modules` 文件夹
【发布时间】:2019-08-23 15:05:09
【问题描述】:

这是一个很好讨论的话题,但我从未找到解决方案。

所以您可能知道,当我的容器中有一个卷并且我在 Dockerfile 中使用yarn install 安装我的依赖项时,Yarn 将在我的容器上创建一个node_modules 文件夹,并具有root:root 访问权限。

这种方法有两个问题(在本地/开发环境中):

  1. node_modules 文件夹仅在我的容器中,但主机的代码编辑器(我的是 VSC)可能需要此文件夹才能正常工作。比如你没有,VSC会骂你找不到导入的模块...

  2. 如果主机想要使用yarn add ... 安装软件包,他将不得不重新启动并重建容器以安装要安装的软件包。

所以我想出了另一个想法,如果我在 Dockerfile 中使用 CMD 安装依赖项(或者在 docker-compose 文件中使用服务的 command 属性)会怎样。因此,Docker 将与主机共享node_modules。但这是主要问题,node_modules 具有 root:root 权限访问,因此如果您的主机的用户名命名为例如 mint 并且没有相同的 uid 和 gid 您将需要运行 root访问命令以安装/删除依赖项(例如 sudo yarn add ...)。

这是我当前的配置:

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 是我主机的用户)。这就是第二种解决方案的问题。

最后,我的问题是:有没有更好的方法来完成这一切?

【问题讨论】:

  • 您可以在 dockerfile 中使用 USER 指令,以便不以 root 身份运行所有内容,而是以特定用户身份运行。其中,安全方面是一个更好的主意,而不是以 root 身份运行所有内容。
  • @β.εηοιτ.βε 使用硬编码的 uid / gid ?如果是,图像可以重复使用吗?他们是否需要与我的主机相同才能修改node_modules 文件夹?

标签: javascript node.js docker docker-compose docker-machine


【解决方案1】:

在你的情况下,为了让它以你想要的方式工作,你应该在 docker 文件中添加USER,在 docker-compose.yml 中添加user:。例如

Dockerfile:

FROM node:12.8.1-alpine

WORKDIR /usr/src/app

USER node

COPY . .

docker-compose.yml:

version: '3.7'

services:
  app:
    container_name: 'app_DEV'
    build: .
    command: sh -c "yarn install && node ./server.js"
    user: "1000:1000"
    volumes:
      - ./:/usr/src/app
    ports:
      - 3000:3000
    tty: true

无论如何,我们面临着类似的情况,我们选择了不同的方法。我们决定避免在 docker-compose.yml 中挂载 node_modules 文件夹,而不是在主机和容器之间共享 node_modules 文件夹(如果您与使用不同操作系统的同事一起工作,会出现令人讨厌的行为)。

在我们的例子中,Dockerfile 如下所示:

FROM node:8.12.0-stretch

RUN mkdir /api

WORKDIR /api

COPY ./package.json ./package-lock.json ./
RUN npm ci --prod

COPY . .

CMD [ "nodemon", "server.js" ]

docker-compose.yml 看起来像这样:

version: '3.7'

services:
  app:
    build: .
    volumes:
      - "./:/api"
      - "/api/node_modules/"

通过这种方式,我们能够在主机中创建 node_modules(可用于测试、开发等)并安全地保持 docker 容器的内容不变。这种方法的缺点是我们的开发人员还必须在主机上运行npm ci,并且每次更改 package.json 时都需要重新创建图像。

【讨论】:

  • (将 node_modules 放入卷中会主动阻止 Docker 安装任何新的或更改的模块,即使 package.json 文件更改也是如此。)
【解决方案2】:

一般来说,我不会推荐这种方法,因为您是主机和容器可能无法共享相同的模块。例如,如果您团队中的其他人使用 Windows,并且您有一些已编译的模块(即 node-sass 或 bcrypt),那么共享这些模块会使容器或主机无法使用它们。

另一个经常出现的解决方案是在 Dockerfile 中分离 node_modules 安装步骤,并为此覆盖卷安装。每次您想要添加一个包时,您仍然需要重新构建 Docker 映像,但这种情况(可能)不应该经常发生。

这里是 Dockerfile 的相关部分:

FROM 节点:12.8.1-alpine

工作目录 /usr/src/app

复制 ./package*.json 。
复制 ./yarn.lock 。

润纱

复制 。 .

CMD [“纱线”,“开始”]

然后,在您的 docker-compose 文件中:

版本:'3.7' 服务: 应用程序: 容器名称:'app_DEV' 建造: 。 命令:sh -c "yarn install && node ./server.js" 卷: - ./:/usr/src/app - /usr/src/app/node_modules/ 端口: - 3000:3000 tty: 真

确保将/usr/src/app/node_modules/ 卷AFTER 包含在根挂载中,因为它将在容器中覆盖它。另外,斜线很重要。

【讨论】:

  • 我主要为 prod 容器执行此操作,如果我没有进行多阶段构建,那是因为 node_modules 未与主机共享,但您可以通过安装 deps 来解决此问题docker-compose up,当你有很多部门时,这需要一点时间。但目前这是最好的解决方案,所以我会花一点时间,如果没有其他解决方案,我会接受。谢谢你!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-06-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-12-26
  • 1970-01-01
相关资源
最近更新 更多