HOWTO · Docker

如何将主机目录挂载到 Docker 容器中

了解如何将主机目录挂载到 Docker 容器中,并选择合适的挂载方式。

本页内容

绑定挂载可以将主机上的目录连接到 Docker 容器内的路径。当容器需要读取或更新主机上的特定目录(例如开发时使用的源代码)时,可以使用绑定挂载。下面的示例会先在主机上创建目录和文件,再说明如何通过 Docker 命令在 Alpine shell 中访问该目录。本文写作阶段没有执行 Docker 命令。

使用绑定挂载将主机目录挂载到 Docker 容器中

绑定挂载会将你指定的主机路径映射到容器路径。它与由 Docker 管理的卷不同:绑定挂载的来源是主机上的某个具体位置。对该目录中文件所做的更改,可以通过容器中的挂载点看到。应用程序也能看到这些更改,但只有在应用程序会监视文件或重新加载文件时,热重载才会发生。

使用 -v 或 --volume 标志将主机目录装载到 Docker 容器中

下面的 Python 示例会创建名为 site 的主机目录,在其中写入文件,并打印文件名。请在准备启动 Docker 的目录中运行:

from pathlib import Path

site = Path("site")
site.mkdir(exist_ok=True)
(site / "hello.txt").write_text("Hello from the host.\n")
print("\n".join(sorted(path.name for path in site.iterdir())))
hello.txt

上面的文件可以通过在容器中启动的 /site 路径访问,例如运行 docker run --rm -it --volume "$PWD/site:/site" alpine:3.20 sh。卷参数的格式为 host-path:container-path[:options]:$PWD/site 是主机目录,/site 是它在容器中的路径;可选的 ro 后缀会将挂载设为只读。简写标志 -v 和完整标志 --volume 使用相同语法,因此 -v "$PWD/site:/site:ro" 是只读挂载的写法。

容器 shell 运行期间,可以在主机上用 touch "$PWD/site/host-created.txt" 创建一个新文件。在容器提示符下运行 ls /site,并确认列表中出现 host-created.txt,即可检查这个主机端新文件是否通过挂载显示在容器中。挂载可写时,在 /site 下创建的文件也会写入主机目录。只读挂载允许容器读取文件,但容器不能通过该挂载修改文件。

如果主机目录不存在,-v 和 --volume 会将其创建为目录。使用容器前请检查实际创建的主机路径:路径拼写错误可能会生成一个新的空目录,让人误以为预期文件丢失了。

使用 --mount 标志将主机目录挂载到 Docker 容器中

--mount 写法会用逗号分隔的键值字段指定各项设置。对于同一个示例,可以运行 docker run --rm -it --mount "type=bind,source=$PWD/site,target=/site" alpine:3.20 sh。type=bind 表示使用绑定挂载,source 是主机目录,target 是该目录在容器中的路径。若要禁止通过挂载写入,可在挂载字段中添加 readonly。字段顺序不会改变来源路径和目标路径的含义;真正决定含义的是键名。

与 -v 和 --volume 不同,如果绑定挂载的来源目录不存在,--mount 会报错。启动容器前,请先创建并确认主机目录。路径中若包含逗号,逗号分隔的挂载语法需要格外处理;可以改用合适的主机路径,或查阅适用于你所用平台的 Docker 挂载语法。

绑定挂载会让容器访问所选的主机路径。只挂载工作负载所需的目录,避免暴露敏感文件;如果容器不需要写入,请使用只读访问权限。主机路径共享方式和权限也可能取决于系统上的 Docker 配置。

结论

紧凑的冒号分隔写法可以使用 -v 或 --volume;如果希望用明确的键值字段,则可以使用 --mount。这两种方式都会让主机目录出现在容器路径下:-v 可以创建不存在的来源目录,而 --mount 要求来源目录已经存在。容器需要访问主机上的特定路径时,适合使用绑定挂载。如果应用程序数据应由 Docker 管理,而不依赖主机上的某个特定目录,那么由 Docker 管理的卷通常更合适。