Docker存储管理

默认情况下,所有在容器中创建的文件都存储在一个可写入的容器层(writable container layer),这意味着:

  • 如果容器销毁,数据也就不存在了,并且这种方式很难在容器之间共享数据
  • 这个容器可写入层是和容器所运行的host主机紧密结合的,很难迁移数据
  • 写入容器的可写入层需要一个 Docker存储驱动 来管理文件系统。这个存储驱动使用Linux内核来提供了一个联合文件系统(union filesystem)。

注解

Docker容器默认使用的union filesystem需要通过 Docker存储驱动 读写文件系统,由于增加了这层额外的抽象层,导致读写性能低于 Docker 卷 (直接读写host主机文件系统)。

在生产环境中使用Docker容器,务必尽可能将所有数据读写都通过 Docker 卷 来实现,以获得最佳的存储性能。 Docker存储驱动 应用于构建容器(静态数据)而不是生产数据。

Docker可以使用两种方式把文件存储到Host主机上,以实现数据持久化:

此外借助Host主机的内存文件系统 tmpfs ,Docker可以实现速度最快的外部文件交换(通常用于向外部传输日志):

选择正确的挂载模式

无论你选择哪种挂载方式,数据在容器内部看起来都是一样的,数据在容器内部表现为文件系统一个目录或独立文件。如何区分数据挂载类型,例如 卷,绑定挂载,以及 tmpfs 挂载,最简单的方式是考虑数据在Docker Host(底层主机)上存储的位置:

../../_images/types-of-mounts.png
  • Volumes (卷)将数据存储在host主机文件系统中由Docker管理的部分( /var/lib/docker/volumes/ )。不是Docker的进程将不会修改这部分文件系统,通常卷是Docker持久化数据的最佳选择。
  • Bind mounts (绑定挂载)可以将数据存储在host主机的任何位置,甚至可以存储在重要的系统文件和目录。在Docker主机上非Docker进程也能够访问和修改这些数据。(限制最小,但存在安全隐患,因为不仅每个容器都可以修改系统文件导致影响其他容器,而且在host主机修改也将影响所有容器)
  • tmpfs mounts (内存文件系统tmpfs挂载) 只将数据存储在host主机系统内存,但绝不存储到host主机磁盘存储文件系统。

挂载类型的详细解析

  • volumes ( Docker 卷 ) 由Docker创建和管理,可以使用 docker volume create 命令显式创建一个卷,或者有Docker在容器或服务创建时创建一个卷。

创建的卷位于Docker host的目录,可以在多个容器中挂载相同的卷,这样就可以实现容器间数据共享。和 Docker 捆绑挂载 区别是 Volume 卷只能位于Docker管理目录下而不是host主机的任意位置。

注解

当没有容器使用某个卷时,这个卷依然位于Docker中不会自动移除,需要使用命令 docker volume prune 来删除一个不使用的卷。

在挂载一个卷时,卷可以是 named (命名的)也可以是 anonymous (匿名的)。匿名卷没有明确给出名字,当挂载到一个容器上时,Docker会随机给卷命名,已确保在Docker host上卷的命名唯一性。

卷也支持 volume drivers 的使用方式,这样允许将数据存储到远程主机或者云存储。

  • bind mounts ( Docker 捆绑挂载 )是Docker早期提供的挂载方式,和volume相比较,bind mount 有功能限制。当使用bind mount,在host主机上的文件或目录被挂载到容器内部,文件和目录是通过它在host主机的完整路径来引用的,在Docker host主机上,这个挂载文件或目录并不需要一定存在,如果不存在,文件和目录会在必要时自动创建。bind mount的性能很好,但是它依赖host主机文件系统具备一个特定的目录结构。注意,不能使用Docker CLI命令来直接管理bind mount。

警告

Docker 捆绑挂载 是一个强大的存储方式:可以在容器中直接修改host主机上的文件,甚至包括修改和删除系统文件。这是具有安全隐患的,会影响host系统中非Docker进程。

  • tmpfs mounts ( Docker内存文件系统(tmpfs)挂载 ) 是非持久化数据存储,只在容器的生命周期内存在,用于存储非持久化数据或敏感信息。例如,在Docker内部,swarm服务使用 tmpfs 挂载来挂载 secrets 到服务的容器中。

bind mounts 和 volumes 都是使用 -v 或者 --volume 命令参数来挂载到容器内,不过有轻微的差异。 对于 tmpfs 挂载,则需要使用 --tmpfs 参数。从 Docker 17.06 或更高版本,建议使用 --mount 参数用于容器和服务,以及用于bind mounts 和volumes 、 tmpfs 挂载,以保持清晰语法。