默认情况下,在容器内创建的所有文件都存储在可写容器层上。这意味着:
- 当该容器不再存在时,数据就不会持续存在,并且如果另一个进程需要它,可能很难从容器中取出数据。
- 容器的可写层与运行容器的主机紧密耦合。您无法轻松地将数据移动到其他地方。
- 写入容器的可写层需要存储驱动程序来管理文件系统。存储驱动程序使用Linux内核提供联合文件系统。与使用直接写入主机文件系统的数据卷相比,这种额外的抽象降低了性能。
Docker为容器提供了两个选项来将文件存储在主机中,使容器停止后文件还可以持久保存:卷(volumes)和绑定挂载(bind mounts)。如果您在Linux上运行Docker,还可以使用tmpfs挂载。如果您在Windows上运行Docker,则还可以使用命名管道。
继续阅读有关这两种持久数据方式的更多信息。
选择正确的挂载类型
无论您选择使用哪种类型的挂载,容器中的数据看起来都是相同的。 它在容器的文件系统中显示为目录或单个文件。
区分卷,绑定挂载和tmpfs挂载之间差异的一种简单方法是考虑数据在Docker主机上的位置。
卷存储在由Docker管理的主机文件系统的一个位置上(在Linux上为
/var/lib/docker/volumes/
)。 非Docker进程不应修改这部分文件系统。 卷是在Docker中持久保存数据的最佳方法。绑定挂载可以存储在主机系统上的任何位置。 它们甚至可能是重要的系统文件或目录。 Docker主机或Docker容器上的非Docker进程可以随时对其进行修改。
tmpfs
挂载仅存储在主机系统的内存中,并且永远不会写入主机系统的文件系统中。
有关挂载类型的更多详细信息
- 卷(volume):由Docker创建和管理。您可以使用
docker volume create
命令显式创建卷,或者Docker可以在容器或服务创建期间创建卷。
创建卷时,它存储在Docker主机上的目录中。将卷挂载到容器时,此目录就是挂载容器的目录。这类似于绑定挂载的工作方式,不同的是卷由Docker管理并且与主机的核心功能隔离。
给定的卷可以同时挂载到多个容器中。当没有正在运行的容器使用卷时,该卷对于Docker来说仍然可用,并且不会自动删除。您可以使用docker volume prune
删除未使用的卷。
挂载卷时,它可能是命名的或匿名的。匿名卷是首次挂载到容器中时,没有为其指定明确的名称,因此Docker为它们提供一个随机名称,该名称在给定的Docker主机中保证是唯一的。除了名称之外,命名卷和匿名卷的行为是相同的。
卷还支持使用卷驱动程序,这使您可以在远程主机或云提供商上存储数据。
- 绑定挂载:从Docker早期开始就可用。与卷相比,绑定挂载的功能有限。使用绑定挂载时,主机上的文件或目录将挂载到容器中。文件或目录由主机上的完整路径引用。该文件或目录不需要在Docker主机上已经存在。如果尚不存在,则按需创建。绑定挂载性能非常好,但是它们依赖于具有特定目录结构的主机文件系统。如果要开发新的Docker应用程序,请考虑使用命名卷。您不能使用Docker CLI命令直接管理绑定挂载。
绑定挂载允许访问敏感文件
使用绑定挂载一个副作用,可能是好的也可能是坏的,您可以通过容器中运行的进程来更改主机文件系统,包括创建,修改或删除重要的系统文件或目录。这是一项强大的功能,可能会带来安全隐患,包括影响主机系统上的非Docker进程。
tmpfs挂载:tmpfs
挂载不会持久化到磁盘上,无论是在Docker主机上还是在容器内。容器在其生存期内可以使用它来存储非持久状态的敏感信息。例如,在内部,swarm集群服务使用tmpfs
挂载将机密挂载到服务的容器中。
命名管道:npipe
挂载可用于Docker主机与容器之间的通信。常见用例是在容器内运行第三方工具,并使用命名管道连接到Docker Engine API。
绑定挂载和卷都可以使用-v
或--volume
标记挂载到容器中,但是两者的语法略有不同。tmpfs
挂载可以使用--tmpfs
标记。但是,在Docker 17.06及更高版本中,我们建议对容器和服务,绑定挂载,卷或tmpfs
挂载使用--mount
标记,因为语法更清晰。
卷的适用场景
卷是将数据持久保存在Docker容器和服务中的首选方法。卷的一些适用场景包括:
- 在多个运行中的容器之间共享数据。如果您未明确创建它,则将在第一次将其挂载到容器时创建该卷。当该容器停止或删除时,该卷仍然存在。多个容器可以同时挂载相同的卷(可读写或只读)。仅在显式删除卷时才将它们删除。
- 不保证Docker主机具有给定的目录或文件结构时。卷可帮助您将Docker主机的配置与容器运行时解耦。
- 当您要将容器的数据存储在远程主机或云提供商上时,而不是在本地。
- 当您需要将数据从一个Docker主机备份,还原或迁移到另一个Docker主机时,卷是一个更好的选择。您可以停止使用该卷的容器,然后备份该卷的目录(例如
/var/lib/docker/volumes/<volume-name>
)。
绑定挂载的的适用场景
通常,应尽可能使用卷。绑定挂载适用于以下类型的用例:
将配置文件从主机共享给容器。这是Docker为容器提供DNS解析的方式的默认方式,通过将
/etc/resolv.conf
从主机挂载到每个容器中来。在Docker主机上的开发环境和容器之间共享源代码或构建工件。例如,您可以将Maven
target/
目录挂载到容器中,这样每次在Docker主机上构建Maven项目时,容器都可以访问重建的工件。
如果您以这种方式使用Docker进行开发,那么您的生产Dockerfile会将生产就绪的工件直接复制到映像中,而不是依赖于绑定挂载。
- 当需要确保Docker主机的文件或目录结构与绑定挂载容器所需的一致时。
tmpfs挂载的好用例
当您不希望数据在主机上或容器内持久存在时,tmpfs
挂载最适合使用。这可能是出于安全原因或为了保护容器的性能,当您的应用程序需要写入大量非持久状态数据时。
使用绑定挂载或卷的提示
如果使用绑定挂载或卷,请牢记以下几点:
如果将空卷挂载到存在文件或目录的容器中的目录中,则这些文件或目录将传播(复制)到该卷中。同样,如果启动一个容器并指定一个尚不存在的卷,则会为您创建一个空卷。这是预填充另一个容器所需数据的好方法。
如果将绑定挂载或非空卷挂载到存在文件或目录的容器的目录中,则这些文件或目录会被挂载遮盖,就像您将文件保存到Linux主机上的
/mnt
中一样,然后将USB驱动器挂载到/mnt
中。在卸载USB驱动器之前,/mnt
的内容将被USB驱动器的内容遮盖。被遮盖的文件不会被删除或更改,但是在挂载绑定挂载或卷时将无法访问。