如果在 macOS 上执行 docker compose up 后,原本应来自镜像的文件消失了,请检查是否有绑定挂载覆盖了它们的容器目录。绑定挂载会将宿主机文件夹的内容显示在挂载目标位置,从而遮挡镜像中已有的文件。找到该具体映射,纠正其宿主机或容器路径——如果不需要则将其移除——然后重新创建受影响的服务。Docker 文档指出,重新创建不带该挂载的容器是重新显示镜像原始文件的方法。(Bind mounts)

为什么绑定挂载会隐藏文件

绑定挂载将宿主机上的路径连接到容器中的路径。例如,挂载 ./app:/usr/src/app 会使宿主机的 app 文件夹出现在 /usr/src/app。如果镜像在该处已包含文件,这些文件仍属于镜像的一部分,但在挂载处于活动状态时会被隐藏。这可能会使原本正常的镜像看起来是空的,或者在预期程序被覆盖时引发启动错误。这一行为在 Mac 上同样适用;Docker Desktop 会通过其 Linux 虚拟机来调度宿主机文件访问。(Bind mounts)

这与文件权限问题不同:容器可能正在正确读取挂载的目录,但它读取的文件集与镜像目录中的文件集不同。在更改所有权或重新构建镜像之前,请先检查映射。

在 Compose 文件中查找映射

打开用于启动项目的 Compose 文件,找到受影响服务的 volumes: 条目。当源路径是宿主机路径时,诸如 ./app:/usr/src/app 这样的简写形式条目就是一个绑定挂载。在本地 Compose 中,相对源路径是根据 Compose 文件的父目录解析的。这意味着如果 Compose 文件位于子目录中,./app 引用的文件夹可能会与你预期的不同。(Compose services reference)

若要查看解析后的配置和服务状态,请在 macOS 终端中从项目目录运行以下命令:

docker compose config
docker compose ps

在生成的配置中,比较每个挂载的 source(Mac 路径)与其 target(容器路径)。然后将目标路径与镜像的工作目录以及预期存放其应用程序文件的目录进行比较。像 .:/usr/src/app 这样宽泛的挂载可能会覆盖整个应用程序目录;而像 ./config:/usr/src/app/config 这样更窄的映射则会让镜像目录的其余部分保持可见。

选择正确的修复方案

如果服务需要对源代码进行实时访问,请保留绑定挂载,但将其指向正确的宿主机文件夹和预期的容器子目录。确认宿主机目录中包含你预期的文件。Compose 简写语法会在绑定源缺失时自动创建一个目录,因此拼写错误可能会悄无声息地给容器分配一个空文件夹。如需进行显式控制,请使用带有 create_host_path: false 的长格式语法;这样,Compose 会在源路径缺失时报错,而不是创建一个目录。(Compose services reference)

services:
  app:
    volumes:
      - type: bind
        source: ./app
        target: /usr/src/app
        bind:
          create_host_path: false

如果应由镜像提供应用程序文件,请移除以该目录为目标的挂载。如果只有配置或某个生成的文件夹需要宿主机访问,则仅挂载该子目录。对于数据库等容器持久化数据,请考虑改用具名卷(named volume):Docker 会管理其存储,并且这避免了将数据绑定到特定的 Mac 目录。(Volumes)

重新创建服务并验证

编辑 Compose 文件后,重新创建受影响的服务,使其使用更新后的挂载。将下方的 app 替换为你文件中的服务名称:

docker compose up -d --force-recreate app
docker compose exec app sh -c 'ls -la /usr/src/app'

ls 命令会检查容器在目标位置可以看到的内容;如果你的服务使用不同的路径,请更改该路径。如果镜像没有 shell 或缺少 ls,请使用 docker compose logs app 检查其启动日志,并使用该镜像中可用的诊断命令。Docker 还记录了可以使用 docker inspect 来检查容器的挂载源和目标;在 Compose 中,先通过 docker compose ps 获取其容器名称,然后运行 docker inspect CONTAINER_NAME。(Bind mounts)

如果源路径位于 Docker Desktop 的共享文件夹之外,或者你看到 Mounts denied 或 file is not shared from the host,请检查 Docker Desktop 的 Settings > Resources > File sharing 并添加该特定 Mac 目录。Docker 将 /Users、/Volumes、/private、/tmp 和 /var/folders 列为默认共享,但这些位置之外的目录可能需要手动添加。Docker VMM 不支持绑定挂载自动共享,因此对于该后端必须手动添加目录。(Docker Desktop settings、Virtual Machine Manager)

挂载隐藏镜像文件的问题通常可以通过纠正其源或目标、缩小其范围,或将其移除并重新创建服务来解决。当容器需要特定的宿主机文件夹时保留绑定挂载;否则,让镜像提供自己的文件,或将持久化数据存储在 Docker 管理的卷中。

来源