docker-compose在node_modules上的卷但是为空

Mik*_*tin 11 node.js docker docker-compose docker-volume

我是Docker的新手,我想在我的计算机上映射node_modules文件夹(用于调试目的).

这是我的docker-compose.yml

web:
  build: .
  ports:
    - "3000:3000"
  links:
    - db
  environment:
    PORT: 3000
  volumes:
    - .:/usr/src/app
    - /usr/src/app/node_modules
db:
  image: mongo:3.3
  ports:
    - "27017:27017"
  command: "--smallfiles --logpath=/dev/null"
Run Code Online (Sandbox Code Playgroud)

我在使用Docker for Mac.当我运行docker-compose up -d所有正确,但它在我的计算机上创建一个node_modules文件夹,但它是空的.我进入容器的bash和ls node_modules,所有包都在那里.

如何在计算机上获取容器上的内容呢?

谢谢

Rob*_*ert 13

TL; DR工作示例,克隆并尝试: https ://github.com/xbx/base-server


您需要首先在计算机(外部映像)中使用node_modules进行调试(在运行容器之前).

如果您只想调试node_modules:

volumes:
    - /path/to/node_modules:/usr/src/app/node_modules
Run Code Online (Sandbox Code Playgroud)

如果要调试代码和node_modules:

volumes:
    - .:/usr/src/app/
Run Code Online (Sandbox Code Playgroud)

请记住,您需要npm install在容器外至少运行一次(或复制docker build生成的npm_modules ).如果您需要更多细节,现在就让我.


编辑.因此,在OSX中不需要npm,您可以:

  1. docker build然后docker cp <container-id>:/path/to/node-modules ./local-node-modules/.然后在你的docker-compose.yml中安装这些文件并麻烦你想要的任何东西.
  2. 或者,docker build那里(Dockerfile)npm install在另一个目录中执行.然后在你的命令(CMD或docker-compose命令)中将copy(cp)复制到正确的目录,但是这个目录从你的计算机(docker-compose.yml中的一个卷)挂起,然后麻烦你想要的任何东西.

编辑2.(选项2)工作示例,克隆并尝试: https ://github.com/xbx/base-server 我在你的这个仓库中自动完成了这一切.

Dockerfile

FROM node:6.3

# Install app dependencies
RUN mkdir /build-dir
WORKDIR /build-dir
COPY package.json /build-dir
RUN npm install -g babel babel-runtime babel-register mocha nodemon
RUN npm install

# Create app directory
RUN mkdir -p /usr/src/app
WORKDIR /usr/src/app
RUN ln -s /build-dir/node_modules node_modules

# Bundle app source
COPY . /usr/src/app

EXPOSE 1234
CMD [ "npm", "start" ]
Run Code Online (Sandbox Code Playgroud)

泊坞窗,compose.yml

web:
  build: .
  ports:
    - "1234:1234"
  links:
    - db # liaison avec la DB
  environment:
    PORT: 1234
  command: /command.sh
  volumes:
    - ./src/:/usr/src/app/src/
    - ./node_modules:/usr/src/app/node_modules
    - ./command.sh:/command.sh
db:
  image: mongo:3.3
  ports:
    - "27017:27017"
  command: "--smallfiles --logpath=/dev/null"
Run Code Online (Sandbox Code Playgroud)

command.sh

#!/bin/bash

cp -r /build-dir/node_modules/ /usr/src/app/

exec npm start
Run Code Online (Sandbox Code Playgroud)

请克隆我的回购并做docker-compose up.它做你想要的.PS:可以改进以更好的方式做同样的事情(即最佳实践等)

我在OSX,它适合我.

  • 由于`npm install`是依赖于平台的,因此在主机上运行它可能会导致跨平台问题(host = mac,container = debian). (7认同)
  • 有人用`node_modules`解决了这个问题吗?由于可能存在跨平台问题,我不想将它们安装在我的主机上(@gesellix 在上面也写了相关内容)。是否可以在 Docker 容器中安装 `node_modules` 并将它们镜像到主机,以便我可以在需要时查看源代码,并且我的 IDE 可以看到所有 `devDependencies`,如 `eslint` 和其他? (3认同)
  • 我喜欢这个解决方案,我没有考虑在挂载卷之后复制node_modules的bash脚本.非常感谢你的帮助! (2认同)

BMi*_*tch 11

首先,有一个操作顺序。构建映像时,不会挂载卷,只有在运行容器时才会挂载它们。因此,当您完成构建后,所有更改将仅存在于映像内部,而不存在于任何卷中。如果将卷安装在目录上,则该卷会覆盖该位置上映像的内容,从而将这些内容从视图中隐藏(一个初始化例外,请参见下文)。


接下来是卷语法:

  volumes:
    - .:/usr/src/app
    - /usr/src/app/node_modules
Run Code Online (Sandbox Code Playgroud)

告诉docker-compose从当前目录创建一个主机卷到/usr/src/app容器内部,然后映射/usr/src/app/node_modules到docker维护的匿名卷。后者将显示为docker volume ls带有较长uuid字符串的卷,相对来说是没有用的。

要映射/usr/src/app/node_modules到主机上的文件夹,您需要像上面的一行一样在其前面包含一个文件夹名称和冒号。例如/host/dir/node_modules:/usr/src/app/node_modules

命名卷与主机卷有所不同,因为docker用您可以在中看到的名称维护它们docker volume ls。您仅使用名称而不是路径来引用这些卷。因此,node_modules:/usr/src/app/node_modules将创建一个名为的卷node_modules,您可以使用该名称将其装入容器中。

我之所以对命名卷进行了描述,是因为它们具有一项功能,该功能变成了主机卷的陷阱。Docker通过使用该位置的映像内容进行初始化来帮助您命名卷。因此,在上面的示例中,如果命名的卷node_modules为空(或新的),它将首先将/ usr / src / app / node_modules`中的映像内容复制到该卷,然后将其装入容器中。

使用主机卷,您将永远不会看到任何初始化,无论在那个位置,无论是空目录,都是在容器中看到的全部内容。无法从该目录位置的映像中获取内容,然后首先复制到该位置的主机卷。这也意味着容器内所需的目录权限不会自动继承,您需要在将在容器内工作的主机目录上手动设置权限。


最后,还有一个用于Windows和Mac的docker小陷阱,它们在VM内运行,并且您的主机卷已安装到VM。要将卷安装到主机,必须配置应用程序以将主机中的文件夹共享到VM,然后将VM中的卷安装到容器中。默认情况下,在Mac上,包含/ Users文件夹,但是如果您使用其他目录,例如/ Projects目录,甚至是小写的/ users(unix和bsd区分大小写),您将看不到Mac放在容器中。


掌握了这些基础知识之后,一种可能的解决方案是重新设计您的工作流程,以将映像中的目录内容复制到主机中。首先,您需要将文件复制到图像内的其他位置。然后,您需要在容器启动时将文件从保存的映像位置复制到卷安装位置。当您执行后者时,您应该注意,您正在达到拥有卷(持久性)的目的,并且可能要考虑添加一些逻辑以便对运行副本的时间更具选择性。首先,向您的构建中添加一个entrypoint.sh,如下所示:

#!/bin/sh
# copy from the image backup location to the volume mount
cp -a /usr/src/app_backup/node_modules/* /usr/src/app/node_modules/
# this next line runs the docker command
exec "$@"
Run Code Online (Sandbox Code Playgroud)

然后更新您的Dockerfile以包括入口点和备份命令:

FROM node:6.3

# Create app directory
RUN mkdir -p /usr/src/app
WORKDIR /usr/src/app

# Install app dependencies
COPY package.json /usr/src/app/
RUN npm install -g babel babel-runtime babel-register mocha nodemon
RUN npm install

# Bundle app source
COPY . /usr/src/app
RUN cp -a /usr/src/app/. /usr/src/app_backup

EXPOSE 1234
ENTRYPOINT [ "/usr/src/app/entrypoint.sh" ]
CMD [ "npm", "start" ]
Run Code Online (Sandbox Code Playgroud)

然后从docker-compose.yml中删除多余的卷:

  volumes:
    - .:/usr/src/app
Run Code Online (Sandbox Code Playgroud)