在 docker 容器中创建卷和挂载有什么区别?

在 docker 容器中创建卷和挂载有什么区别?

Docker 提供了两种在本地机器上备份和同步容器数据的方法,即体积。除了我注意到的几点外,两者的行为方式相同:

  1. 卷始终将数据保存在 /var/lib/docker/volumes 中,而挂载点可以在我们想要的任何地方创建。
  2. 如果为分配了挂载点的容器也分配了卷,则挂载点的所有数据都会自动复制到该卷,反之则不然。
  3. 我们无法在 Dockerfile 中描述挂载点,但可以在 Dockerfile 中提供卷。

好的,所以我们可以说方法论有一些优点和缺点,但是在优化方面仍然存在一些分类或差异。

请提供解释性的答案。

答案1

实际上有三种类型的卷:

  • 主机卷:即容器中的挂载,更常见的术语是绑定挂载。
  • 命名卷:任何由 Docker 管理的、您命名的卷。
  • 匿名卷:任何没有源的卷,docker 都会将其创建为一个具有较长唯一 id 的本地卷,并且其行为如同命名卷。

卷具有源和目标。源标识卷的类型,因此文件/目录的路径(包括前导斜杠)将生成主机卷。如果您不提供源,则会获取匿名卷。如果您在 Dockerfile 中定义卷,则无法在那里指定源,因此默认情况下,docker 将创建匿名卷,除非您在运行时另行指示。

对于每种类型,其优点/缺点如下:

  • 主持人:
    • 优点:易于从主机访问底层文件
    • 缺点:当容器用户的 uid 与主机 gid 不匹配时,会出现 uid/gid 权限问题
    • 缺点:数据未初始化
  • 命名:
    • 优点:易于在不同的容器/图像之间创建重用。如果您只为其指定名称而没有其他设置,则本地驱动程序将默认将您的数据存储在 /var/lib/docker/volumes 中,而该卷只能由 root 从 docker 外部访问。
    • 优点:当镜像为空/新建且容器已创建时,将内容初始化为镜像内容。此初始化包括镜像中的文件所有者和权限,这可以解决大多数 uid/gid 问题。
    • 优点:可以使用本地驱动程序连接到 mount 命令可以连接的任何设备,包括绑定挂载或 NFS 挂载。其他驱动程序可让您引用更多位置的数据(例如云提供商)。
    • 缺点:管理内容应该通过容器来完成。
  • 匿名的:
    • 优点:无需规划即可使用
    • 缺点:由于卷与创建它的容器/镜像之间没有映射,数据通常会丢失。在我看来,这是存储卷的最糟糕的方式,也是任何人都不应该在 Dockerfile 中定义卷的原因。

如果可能,我会使用命名卷。数据的初始化和对 uid/gid 问题的更好处理胜过主机卷的便利性。如果我真的需要在 docker 之外直接访问数据,那么我会尝试使用指向绑定挂载的命名卷,而不是默认的本地驱动程序设置。一个简单的例子是:

$ docker volume create --driver local \
  --opt type=none \
  --opt device=/home/user/test \
  --opt o=bind \
  test_vol

为了定义我的卷,由于您不想在 Dockerfile 中执行此操作,因此我使用 docker-compose.yml 并在其中定义我的卷。如果它使用 Swarm 模式部署,我将指向具有命名卷的 NFS 服务器,以便在容器迁移到不同主机时可以访问数据。否则,它是一个本地命名卷,可以轻松与 docker-compose 一起使用。

答案2

dockerfile 中的卷允许在镜像中指定应始终创建为卷的路径。这本质上绕过了 docker 使用的联合文件系统。

此类映像的用户在运行时将始终获得该位置的卷

docker run <imagename>

即没有理由添加-v /my/mount/point:/mount/here,因此用户不必担心它。

-v如果需要,绑定挂载(如上例所示)必须始终存在。并且不能在图像之间移植。

与优化相比,其有效区别如下:

  • 在需要大量读写操作的地方可以使用卷,并且它在联合文件系统上有业务写入(想想数据库)
  • 卷对于安装诸如数据卷之类的东西来说是没有价值的。您可以这样做,但是您会遭受巨大的读/写损失,因为没有理由将其放在联合文件系统中。
  • 然而,mounts 会很好地存储这个(上面的内容),因为它只是将现有目录挂载到容器内的某个位置,而忽略该目录的联合文件系统。

这有意义吗?

相关内容