概述

Docker 有两种方式可以持久化数据,分别是 volumebind mount,当然,还有其他的方式,例如 Linux 下的 tmpfs 和 windows 下的 named pipe,但是都不是通用的,所以这里就不展开。这篇文章主要介绍一下 volumebind mount 的区别以及使用场景,并且对其中一些细节的东西拿出来说一下。

数据管理图

图 1:Docker 常用数据管理方式
From: https://docs.docker.com/storage/volumes/

使用入门

volume 使用

[root@liqiang.io]# docker volume create redis
[root@liqiang.io]# docker run -v redis:/data redis:6.0 redis-server

bind mount 使用

[root@liqiang.io]# docker run -v /myredis/conf:/usr/local/etc/redis redis redis-server

持久化方式选择

volume 使用场景

卷是在 Docker 容器和服务中持久化数据的首选方式。卷的一些使用场景包括:

  • 在多个运行的容器之间共享数据。如果你没有显式地创建它,volume 在第一次安装到容器中时就会被创建。当该容器停止或被移除时,volume 仍然存在。多个容器可以同时挂载同一个 volume,可以是读写式的,也可以是只读式的。只有当你明确删除卷时,卷才会被删除;
  • 当 Docker 主机不能保证拥有给定的目录或文件结构时,volume 可以将 Docker 主机的配置与容器运行时解耦;
  • 当您想将容器的数据存储在远程主机或云提供商上时;
  • 当你需要将数据从一个 Docker 主机备份、还原或迁移到另一个 Docker 主机时,volume 是一个更好的选择。你可以停止使用 volume 的容器,然后备份 volume 的目录(如 /var/lib/docker/volumes/<volume-name>)。
  • 当你的应用需要在 Docker Desktop 上进行高性能的 I/O 时。volume 存储在 Linux 虚拟机中,而不是主机中,这意味着读写的延迟和吞吐量要低得多。
  • 当你的应用需要在 Docker Desktop 上实现完全原生的文件系统行为时。例如,数据库引擎需要精确控制磁盘冲洗以保证事务的耐久性。Volume 存储在 Linux 虚拟机中,可以做出这些保证,而绑定挂载则会被远程到 macOS 或 Windows 中,文件系统的行为略有不同。

bind mount 使用场景

一般来说,您应该尽可能地使用 volume。bind mount 适用于以下场景:

  • 将配置文件从主机共享给容器。这是 Docker 默认向容器提供 DNS 解析的方式,通过将主机上的 /etc/resolv.conf 挂载到每个容器中;
  • 在 Docker 主机上的开发环境和容器之间共享源代码或构建组件。例如,你可以将 Maven target/ 目录挂载到容器中,每次在 Docker 主机上构建 Maven 项目时,容器都可以访问重建的组件;
    如果你以这种方式使用 Docker 进行开发,你的生产 Dockerfile 会直接将生产就绪的组件复制到镜像中,而不是依赖绑定挂载;
  • 当保证 Docker 主机的文件或目录结构与容器所需的绑定挂载一致时。

使用方式

无论是 volume 还是 bind mount,都可以通过 -v/--volume 或者 --mount 来使用,-v--mount 区别是:

  • -v--volume):简单直接
  • --mount:更加明确,但冗长,如果你需要指定 mount 的参数,那么你应该用这一个

额外提示

容器目录不为空

  • 如果你挂载一个 volume 到容器内的目录,但是这个目录里面已经有内容了,那么这个时候具体表现取决于你的 volume 是否是空的
    • 如果 volume 是空的,那么容器内目录的内容会被拷贝到 volume 中;
    • 如果 volume 不空,那么容器内的目录就会被隐藏,但是不会被删除或者修改。
  • 如果是使用的 bind mount 方式,那么无论是否主机内的目录为空,容器内的目录都会被隐藏。

主机目录/volume 不存在

如果使用 -v 指定 volume 或者主机的目录,但是这个目录或者 volume 不存在,那么 docker 的操作是帮你创建一个:

  • bind mount:创建的永远是一个目录;(--volume 会自动创建,但是 --mount 会抛出一个错误)
  • volume:创建的是一个空的 volume。(--volume--mount 都会创建)

Ref