node.js - node_modules 上的 docker-compose 卷但为空

我是 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"

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

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

谢谢

最佳答案

首先,有一个操作顺序。构建镜像时,不会挂载卷,它们仅在您运行容器时才会挂载。因此,当您完成构建时,所有更改将仅存在于镜像中,而不存在于任何卷中。如果你在一个目录上挂载一个卷,它会覆盖该位置的图像中的任何内容,从 View 中隐藏这些内容(有一个初始化异常(exception),见下文)。


接下来是卷语法:

  volumes:
    - .:/usr/src/app
    - /usr/src/app/node_modules

告诉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 "$@"

然后更新您的 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" ]

然后从 docker-compose.yml 中删除额外的卷:

  volumes:
    - .:/usr/src/app

https://stackoverflow.com/questions/38425996/

相关文章:

docker - 使用 pyodbc 将 docker python 连接到 SQL 服务器

docker - 如何在 Docker 内的 Jenkins 中运行 Katalon 测试套件

docker - Artifactory 作为 docker 注册表

ssl - 在 Synology NAS 上使用 Docker 在 GitLab 上启用 SSL

node.js - 为什么 NPM 在 Docker 容器中不可用

linux - 如何删除所有 Docker 容器

git - 何时从 Docker 存储库中提取,何时从 Git 存储库中提取然后构建?

docker - 如何用 nix 构建一个 docker 容器?

python - 如何在构建过程中安装私有(private) Python 包

docker - Alpine Linux 处理证书的方式与 Busybox 不同吗?