在容器和主机之间共享`node_modules`文件夹

时间:2019-08-23 15:05:09

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

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

您可能知道,当我的容器中有一个卷并且我在Dockerfile中使用yarn install安装依赖项时,yarn将在{{1 }}访问。

这种方法(在开发环境中)存在两个问题:

  1. node_modules文件夹仅在我的容器中,但是主机的代码编辑器(我的是VSC)可能需要此文件夹才能正常工作。例如,如果您没有此文件,VSC会错误告知您他找不到您的进口商品...

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

所以我想到了另一个想法,如果我将依赖项与Dockerfile的node_modules(或yarn add ...文件中的CMD服务属性)一起安装。因此,Docker将与主机共享command文件夹,因为他将在构建后创建它。但这是主要问题,docker-compose具有node_modules权限访问权限,因此,如果您主机的用户名为node_modules,并且没有相同的root:root和{{1 }},您将需要使用某种mint来安装/删除依赖项。

这是我当前的配置:

uid

gid

sudo

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

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

2 个答案:

答案 0 :(得分:2)

在您的情况下,为了使其按您希望的方式工作,应在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

无论如何,我们面临着类似的情况,因此我们选择了不同的方法。我们决定避免在主机和容器之间共享node_modules文件夹(如果与使用不同操作系统的同事共享行为很讨厌),而是决定避免将node_modules文件夹安装在docker-compose.yml中。

在我们的例子中,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时,他们都需要重新创建映像。

答案 1 :(得分:2)

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

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

这是Dockerfile的相关部分:

FROM node:12.8.1-alpine

WORKDIR /usr/src/app

COPY ./package*.json .
COPY ./yarn.lock .

RUN yarn

COPY . .

CMD [ "yarn", "start" ]

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

version: '3.7'

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

确保包含/usr/src/app/node_modules/卷{strong>之后的根挂载,因为它将在容器中覆盖它。另外,尾部的斜线很重要。