Docker 提供了两种在本地机器上备份和同步容器数据的方法,即体积和山。除了我注意到的几点外,两者的行为方式相同:
- 卷始终将数据保存在 /var/lib/docker/volumes 中,而挂载点可以在我们想要的任何地方创建。
- 如果为分配了挂载点的容器也分配了卷,则挂载点的所有数据都会自动复制到该卷,反之则不然。
- 我们无法在 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 会很好地存储这个(上面的内容),因为它只是将现有目录挂载到容器内的某个位置,而忽略该目录的联合文件系统。
这有意义吗?