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

Isaac Tony 2023年1月30日
  1. 使用绑定挂载将主机目录挂载到 Docker 容器中
  2. 结论
将主机目录挂载到 Docker 容器中

除了其他功能外,Docker 还提供了与主机操作系统和容器文件系统一起工作的工具。这些功能之一是能够将数据持久保存在容器中,并通过将目录挂载到 Docker 容器在容器之间共享数据。

将目录挂载到 Docker 容器在开发环境和生产环境中很有帮助。除了创建依赖于主机系统目录的服务外,这还可以确保在 Docker 容器被破坏时不会破坏整个文件系统。

假设我们想构建一个新版本的容器。在这种情况下,直接将目录挂载到 Docker 容器会启用热重载。

本文要求 Docker 已正确设置并具有 Docker 映像和容器。无论我们是在 wsl 还是 Linux 上运行 Docker,这都会起作用。

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

绑定挂载是最早的解决方案之一,它允许我们通过将 Docker 容器挂载到主机系统上的目录来持久化数据。这些将使我们能够通过引用目标目录的绝对文件路径来引用目录。

在这种情况下,Docker 不受此目录的控制,这与 Docker 卷的情况不同。Docker 卷在 Docker 管理的 Docker 存储系统中创建一个目录。

除此之外,与 Docker 卷不同,我们无法通过 Docker CLI 或 Docker API 直接管理挂载到容器的目录。但是,Docker 挂载在 MAC 或 windows 等主机中具有高性能,在这些主机中 Docker 卷的性能稍显逊色。

我们还应该注意,使用绑定挂载将容器挂载到目录肯定会增加容器的大小。

我们可以在启动容器时使用两个标志将目录挂载到容器。其中包括 -v--mount 标志。

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

它由三个字段组成,这些字段应始终按正确的顺序排列并用冒号分隔。这些包括:

  • 我们要挂载的主机上目录的路径。
  • 我们应该挂载这个目录的容器中目录的路径。
  • 其他可选选项如 ro 指定只读模式。
docker run -t -i -v <host_dir>:<container_dir

一旦我们确定了我们要一起挂载的主机和容器目录,我们就可以实现上述命令。但是,我们不能对敏感文件进行修改。

这是因为挂载让我们可以访问敏感文件,如果被篡改,可能会导致我们的系统发生致命故障。

在这种情况下,我们将使用官方的 ruby​​ 镜像来创建容器并挂载目录。我们使用目录名称命名脚本,与 Docker 容器相同。

isaac@DESKTOP-HV44HT6:~/isaac$ docker run -it --rm -v$HOME/Desktop/scripts:/scripts --name scripts ruby bash
Unable to find image 'ruby:latest' locally
latest: Pulling from library/ruby
e4d61adff207: Pull complete
4ff1945c672b: Pull complete
ff5b10aec998: Pull complete
12de8c754e45: Pull complete
ada1762e7602: Pull complete
f8f0dec0b2ef: Pull complete
7109f2ab3080: Pull complete
fe1e1dda18a5: Pull complete
Digest: sha256:a1ebc64daa170324dde5b668829de85487575eaa2bdea5216b4c983b1822f9df
Status: Downloaded newer image for ruby:latest

如果我们本地没有镜像,Docker 会自动下载。一旦容器构建过程完成,Docker 将为我们打开容器。

root@9d057cf9e33d:/#
root@9d057cf9e33d:/# ls
bin  boot  dev  etc  home  lib  lib64  media  mnt  opt  proc  root  run  sbin  scripts  srv  sys  tmp  usr  var
root@9d057cf9e33d:/# cd scripts
root@9d057cf9e33d:/scripts# ls

我们可以看到容器中的脚本目录是空的。

现在,让我们转到主机中的脚本目录并在该目录中创建一个新文件。它将自动反映在 Docker 容器目录脚本中。

isaac@DESKTOP-HV44HT6:~/Desktop$ cd scripts
isaac@DESKTOP-HV44HT6:~/Desktop/scripts$ touch new_file.txt
touch: cannot touch 'new_file.txt': Permission denied
isaac@DESKTOP-HV44HT6:~/Desktop/scripts$ sudo touch new_file.txt
[sudo] password for isaac:
isaac@DESKTOP-HV44HT6:~/Desktop/scripts$ ls
new_file.txt
isaac@DESKTOP-HV44HT6:~/Desktop/scripts$

一旦我们在本地目录中创建了一个文件,它将显示在下面的容器目录中。

root@913609933be2:/scripts# ls
new_file.txt

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

这是一种比 -v 标签更直接的方法,由多个键值对组成,用逗号分隔。对于这些标签,字段的顺序无关紧要。

但是,与 -v 标签相比,它更加冗长。

这些方法由以下命令组成:

  • 装载类型,例如 Bindvolumetmpfs
  • 源,即我们要挂载的主机上的目录的路径,通常用 src 表示。
  • 目标,即我们要挂载目录的容器上目录的路径。
  • 我们还有其他选项,例如只读选项和绑定传播,可以将此目录指定为私有或共享。

一旦我们记下所有需要的字段,尤其是源和目标,我们就可以运行如下所示的命令。

在这种情况下,我们使用官方 Nginx 镜像来构建容器并将本地目录名称 new_scripts 映射到位于 etc/nginx 的目录。

$ docker run -d \
> -it \
> --mount type=bind,source=$HOME/Desktop/scripts/new_scripts,target=/etc/nginx \
> nginx \
> bash
e079e3254970e290ae68473239e101c6aa8ba4ba56482c75cd21f9bb9f49600b

现在我们成功映射了这两个目录,对主机上的目录所做的任何更改都会自动反映在容器中的目录上。

isaac@DESKTOP-HV44HT6:~/Desktop/scripts/new_scripts$ sudo touch new_file.txt
[sudo] password for isaac:
isaac@DESKTOP-HV44HT6:~/Desktop/scripts/new_scripts$ ls
new_file.txt

这个文件会在映射到这个目录的 docker 目录中体现出来,说明我们已经成功映射了这两个目录。

root@e079e3254970:/etc# cd nginx
root@e079e3254970:/etc/nginx# ls
new_file.txt

结论

我们已经成功演示了如何使用 Docker -v-mount 标签挂载目录。

但是,我们也应该注意,当使用 -v 标签挂载一个不存在的目录时,Docker 会自动创建它; 这与使用 Docker --mount 标签时的情况不同。

在开发新应用程序时,我们应该考虑使用 Docker 卷。

作者: Isaac Tony
Isaac Tony avatar Isaac Tony avatar

Isaac Tony is a professional software developer and technical writer fascinated by Tech and productivity. He helps large technical organizations communicate their message clearly through writing.

LinkedIn

相关文章 - Docker Container