【问题标题】:Add a volume to Docker, but exclude a sub-folder向 Docker 添加卷,但排除子文件夹
【发布时间】:2015-05-24 17:14:31
【问题描述】:

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

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

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

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

这可能吗?如果有,怎么做?

【问题讨论】:

  • @AbhijitSarkar 这不是一个很有建设性(也没有任何帮助)的评论。
  • @Kano 这是评论,不是答案。

标签: docker dockerfile


【解决方案1】:

首先,在 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),这是否会将 subFolder 更改隔离到容器?
  • 我不确定,我从未尝试过嵌套卷。我不相信这是个好主意,但我必须研究一下。
  • 我似乎无法在任何地方找到要在.dockerignore 文件中放入什么以排除子目录(甚至是目录)的示例。鉴于这是文件的既定目的,这很奇怪。
  • 一旦你添加了任何文件,它们仍然会出现在某些层中。因此,如果安全敏感或减小图像大小(因为它们将位于底层),则删除它们不会帮助您隐藏它们。有squash 层的选项。一个是 github.com/goldmann/docker-squash,另一个是使用 openshift 项目中的 oc ex dockerbuild
【解决方案2】:

使用 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.
【解决方案3】:

如果你想让 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 来解决它
【解决方案4】:

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

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。添加尾部斜杠没有帮助。
  • 我可以确认它在带有 Docker 18.09.3 的 Ubuntu 16.04 上也不起作用。
  • 这对我不起作用。它所做的只是将/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 所要寻找的,但对我来说非常有用,因为我需要排除单个文件。
【解决方案5】:

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

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

【讨论】:

  • 对我也不起作用 docker-compose 1.25.0-rc3,文件语法 v3。
【解决方案6】:

使用 docker 命令行:

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

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

【讨论】:

    【解决方案7】:

    对于同样遇到 node_modules 文件夹仍会从您的本地系统覆盖的问题的人,反之亦然

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

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

    【讨论】:

      【解决方案8】:

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

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

      你的 dockerfile 中的一个例子:

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

      【讨论】:

        【解决方案9】:

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

        1. 更改您的 docker-compose 以将匿名持久卷挂载到 node_modules 以防止您的本地覆盖它。此主题已多次概述了这一点。
        services:
          server:
            build: .
            volumes:
              - .:/app
              - /app/node_modules
        
        1. 这是我们遗漏的重要部分。启动堆栈时,请使用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 目录。我们怎样才能避免这种情况?
        猜你喜欢
        • 1970-01-01
        • 2020-08-06
        • 2013-02-15
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2023-03-12
        • 2021-06-13
        相关资源
        最近更新 更多