ChatGPT解决这个技术问题 Extra ChatGPT

向 Docker 添加卷,但排除子文件夹

假设我的主机 /hostFolder 上有一个 Docker 容器和一个文件夹。现在,如果我想将此文件夹作为卷添加到 Docker 容器中,则可以通过使用 Dockerfile 中的 ADD 或将其安装为卷来执行此操作。

到目前为止,一切都很好。

现在 /hostFolder 包含一个子文件夹 /hostFolder/subFolder

我想将 /hostFolder 挂载到 Docker 容器中(无论是读写还是只读,都对我有用),但我确实希望包含它/hostFolder/subFolder .我想排除它,并且我还希望 Docker 容器能够对这个子文件夹进行更改,而不会在主机上对其进行更改。

这可能吗?如果是这样,怎么做?

它确实通过 tmpfs 工作:stackoverflow.com/a/71911280/3419751

k
kernix

使用 docker-compose 我可以在本地使用 node_modules,但在 docker 容器中使用 docker-compose.yml 中的以下语法忽略它

volumes:
   - './angularApp:/opt/app'
   - /opt/app/node_modules/

因此,./angularApp 中的所有内容都映射到 /opt/app,然后我创建了另一个挂载卷 /opt/app/node_modules/,它现在是空目录 - 即使在我的本地计算机中 ./angularApp/node_modules 不是空的。


它可以工作,但我无法删除容器内的这些目录 例如:我需要将 /opt/app/node_modules/ 替换为另一个具有相同名称的目录。发生错误:“音量忙”
请注意,顺序很重要:如果您的映像在 /opt/app/node_modules/ 下有文件,如果您将其挂载在父目录之后,它们将被忽略。例如,如果您想在映像中包含模块,但以后能够刷新它,您可以按以下顺序列出卷:- /opt/app/node_modules/ 然后父 - './angularApp:/opt/app'
不要忘记尾部的斜线!例如。 /opt/app/node_modules 不起作用,它将被 ./angularApp/node_modules 覆盖
谢谢!你救了我的一天!如果使用简单的 docker,而不是组合,它看起来像:-v $(pwd):/build/ -v /build/node_modules
我找到了文档,docs.docker.com/storage/volumes/…If you start a container which creates a new volume, as above, and the container has files or directories in the directory to be mounted (such as /app/ above), the directory’s contents are copied into the volume.
N
Nate T

如果您希望 docker-compose 忽略子目录但持久存在,您可以在 docker-compose.yml 中执行以下操作:

volumes:
  node_modules:
services:
  server:
    volumes:
      - .:/app
      - node_modules:/app/node_modules

这会将您的当前目录挂载为共享卷,但会挂载一个持久的 docker 卷来代替您的本地 node_modules 目录。这类似于@kernix 的答案,但这将允许 node_modulesdocker-compose up 运行之间持续存在,这可能是所需的行为。


命名卷是一种优越的方法。提示:确保您没有使用带连字符的卷名。您将在调试噩梦中度过一生的一小部分,却发现您再次被可笑的细微差别所愚弄。
“请注意,docker-compose down 将杀死这些持久卷。”这在 Docker for Mac v 17.0.5+(可能还有更早的版本)中并非如此。 docker-compose down 将删除容器,但卷将持续存在,直到您运行类似 docker system prune
如果有人有兴趣了解 为什么 使用 node_modules: 命名卷“忽略” docker 容器中的 /app/node_modules,可能会发现这篇文章很有用How docker handles multiple mount types?
我不知道我是否做错了什么,但如果我这样做,启动容器,然后在主机上运行 npm install ,它也会更改容器内的 node_modules 。我无法想象为什么有人会想要这样做,但我仍然在寻找更干净的分离。
@Renra 有完全相同的问题,即使我有命名卷,我的主机也会不断地覆盖 node_modules ......导致各种不兼容问题。放弃修复它并通过仅复制我的 src 文件夹而不是整个 repo 来解决它
s
squid_ink

对于那些试图在 node_modules 未被本地覆盖的情况下获得良好工作流程的人来说,这可能会有所帮助。

更改您的 docker-compose 以将匿名持久卷挂载到 node_modules 以防止您的本地覆盖它。这已在此线程中概述了几次。

services:
  server:
    build: .
    volumes:
      - .:/app
      - /app/node_modules

这是我们缺少的重要一点。启动堆栈时,请使用 docker-compose -V。如果没有这个,如果你添加了一个新包并重建了你的镜像,它将使用你初始 docker-compose 启动中的 node_modules。

    -V, --renew-anon-volumes   Recreate anonymous volumes instead of retrieving
                               data from the previous containers.

关于 --renew-anon-volumes 的注释是一个重要的补充。在某些情况下,您想挂载源代码文件夹并通过将 node_modules 文件夹挂载为匿名卷来排除它。该标志避免重复使用先前创建的匿名卷,以便正确反映对 package.json 的更改。
使用此方法时,会在主机上创建一个空的 node_modules 目录。我们怎样才能避免呢?
F
Frank Wong

要排除文件,请使用以下命令

volumes:
   - /hostFolder:/folder
   - /dev/null:/folder/fileToBeExcluded

我需要的完美解决方案(不将 node_modules 映射到主机,因为符号链接的东西在 Windows 主机上损坏了)。指向 /dev/null 不起作用,但创建一个空白目录并将其映射到该目录完美地工作并解决了我遇到的问题 - 感谢这个想法。
这在 Docker for Mac 18.09.0 中不起作用:Cannot start service xxx: OCI runtime create failed: container_linux.go:348: starting container process caused "process_linux.go:402: container init caused \"rootfs_linux.go:58: mounting \\\"/dev/null\\\" to rootfs \\\"/var/lib/docker/overlay2/d15ed56ad020d408c63a1f6a6365dbb88d5d3b78a4605980d3faa9861102ef21/merged\\\" at [...] unknown: Are you trying to mount a directory onto a file (or vice-versa)? Check if the specified host path exists and is the expected type。添加尾部斜杠没有帮助。
我可以确认它在 Ubuntu 16.04 和 Docker 18.09.3 上都不起作用。
这对我不起作用。它所做的只是将 /dev/null 作为设备文件复制到容器中。
请注意,这仅适用于排除文件! /dev/null 是一个文件,因此应该是目标,错误消息非常清楚:Are you trying to mount a directory onto a file (or vice-versa)? Check if the specified host path exists and is the expected type。这不是 OP 所要寻找的,但它对我非常有用,因为我需要排除单个文件。
D
DS.

使用 docker 命令行:

docker run \
    --mount type=bind,src=/hostFolder,dst=/containerFolder \
    --mount type=volume,dst=/containerFolder/subFolder \
    ...other-args...

也可以使用 -v 选项(归功于 Bogdan Mart),但 --mount 更清晰且 recommended


A
Adrian Mouat

首先,在 Dockerfile 中使用 ADD 指令非常不同于使用卷(通过 docker run-v 参数或 Dockerfile 中的 VOLUME 指令)。 ADDCOPY 命令只是在 docker build 运行时获取文件的副本。在使用 docker build 命令创建新映像之前,不会更新这些文件。相比之下,使用卷本质上是在说“这个目录不应该存储在容器镜像中;而是使用主机上的目录”;每当卷中的文件发生更改时,主机和容器都会立即看到它。

我不相信你可以使用卷来实现你想要的,如果你想这样做,你将不得不重新考虑你的目录结构。

但是,使用 COPY(应该优先于 ADD)来实现非常简单。您可以使用 .dockerignore 文件排除子目录,或者您可以 COPY 所有文件然后执行 RUN rm bla 删除子目录。

请记住,您使用 COPYADD 添加到映像的任何文件都必须在构建上下文中,即在您运行 docker build 的目录中或目录下。


每天学习新东西 :-) COPY 和 ADD 从构建上下文(不是主机)工作。是否可以使用卷来屏蔽子文件夹? OP 想要挂载 /hostFolder(我认为),并使 /hostFolder/subFolder 断开连接。如果每个都有一个 VOLUME,但只有 hostFolder 被“挂载”(-v),那会隔离子文件夹对容器的更改吗?
我不确定,我从未尝试过嵌套卷。我不相信这是一个好主意,但我必须研究一下。
我似乎无法在任何地方找到将内容放入 .dockerignore 文件以排除子目录(甚至是目录)的示例。鉴于这是该文件的既定目的,这很奇怪。
添加任何文件后,它们仍会出现在某些层中。因此,如果安全敏感或减小图像大小(因为它们将位于底层),则删除它们不会帮助您隐藏它们。有 squash 层的选项。一个是 github.com/goldmann/docker-squash,另一个是使用 openshift 项目中的 oc ex dockerbuild
D
Daenor

对于那些也有 node_modules 文件夹仍然会从您的本地系统覆盖的问题的人,反之亦然

volumes:
  node_modules:
services:
  server:
    volumes:
      - .:/app
      - node_modules:/app/node_modules/

这是解决方案,在 node_modules 之后的尾随 / 是修复。


所以这只是将您的本地 node_modules 文件夹映射到容器中的 /app/node_modules 文件夹内?所以在容器内部,我们有 /app/node_modules/node_modules?为什么?
h
holdbar

看起来旧的解决方案不再起作用(至少对我来说)。不过,创建一个空文件夹并将目标文件夹映射到它会有所帮助。

volumes:
   - ./angularApp:/opt/app
   - .empty:/opt/app/node_modules/

对我来说也不适用于 docker-compose 1.25.0-rc3,文件语法 v3。
E
Emmario Delar

要排除计算机卷中包含的已安装文件,您必须通过将卷分配给同一文件来覆盖它。在您的配置文件中:

services:
  server:
    build : ./Dockerfile
    volumes:
      - .:/app

dockerfile 中的一个示例:

# Image Location
FROM node:13.12.0-buster
VOLUME /app/you_overwrite_file