Docker存储(一)
简介
默认情况下,容器中创建的所有文件都存储在可写容器层中。产生的问题是:
- 当容器停止后,数据不会持久化,并且如果另一个进程需要该数据,很难从容器中读取。
- 容器的可写层与运行容器的主机紧密耦合,无法简单地将数据移动到其他地方。
- 向容器内写入文件,需要一个存储驱动程序来管理文件系统。与直接写入主机文件系统的数据卷相比,这样会降低性能。
Docker提供了两种方式,让容器将文件存储在主机上,即使容器停止后文件也能持久化:
- 数据卷
- 绑定挂载点
Docker 还支持容器在主机内存中存储文件。
- 在 Linux 上运行 Docker,使用tmpfs挂载;
- 在 Windows 上运行 Docker,使用命名管道;
这几种方式,在容器内部看来,是完全一样的。从外部来看如下图所示:
卷
卷是在 Docker 容器和服务中持久化数据的首选方式。
卷存储在由Docker管理的主机文件系统中(在Linux上为 /var/lib/docker/volumes/)。非Docker进程不应修改此文件系统的此部分。
卷由Docker创建和管理。可以使用docker volume create命令显式创建卷,也可以在容器创建时创建卷。
给定的卷可以同时挂载到多个容器中。当没有运行容器使用卷时,该卷仍然可用,并且不会自动删除。可以使用docker volume prune删除未使用的卷。
推荐使用场景
-
在多个运行的容器之间共享数据。
-
不能保证 Docker 主机有给定的目录或文件结构时。可以通过卷来与主机的配置解耦。
-
需要将容器的数据存储在远程主机或云提供商上。
-
需要从一个 Docker 主机备份、恢复或迁移数据时,卷是更好的选择。直接备份该卷的目录(/var/lib/docker/volumes/)。
-
需要高性能 I/O 时。卷存储在 Linux VM 中而不是主机中,这意味着读写具有更低的延迟和更高的吞吐量。
-
需要完全本地文件系统行为时。
例如,数据库引擎需要精确控制磁盘刷新,以保证事务的耐久性。卷存储在 Linux VM 中并可以提供这些保证,而绑定挂载则被转移到 macOS 或 Windows,其中文件系统行为略有不同。
挂载点
绑定挂载可以存储在主机系统的任何位置。包括系统文件。在Docker主机或Docker容器上的非Docker进程可以随时修改它们。
与卷相比,绑定挂载的功能有限。
绑定挂载,是将主机机器上的文件或目录挂载到容器中。需要主机上的文件(目录)的完整引用路径。
绑定挂载非常高效,缺点是要依赖于主机的文件系统是否有这样的目录结构,并且,无法使用Docker CLI命令直接管理绑定挂载。
使用绑定挂载的一个副作用,是可以通过在容器中运行的进程,直接更改主机文件系统,包括创建、修改或删除重要的系统文件或目录。这是一个强大的能力,可能会产生安全影响,包括影响主机系统上的非Docker进程。
一般来说,应该尽可能使用卷。
绑定挂载适用场景
-
从主机共享配置文件到容器。这是Docker默认提供DNS解析到容器的方式,即将主机机器的/etc/resolv.conf挂载到每个容器中。
-
在主机上的开发环境和容器之间共享源代码或构建产物。例如,将Maven target/目录挂载到容器中,每次在Docker主机上构建Maven项目时,容器都可以访问重建的产物。
-
当主机的文件或目录结构保证与容器所需的绑定挂载一致时。
tmpfs
tmpfs挂载在主机或容器内部都不会保留在磁盘上。它可以在容器的生命周期内被容器使用,用于存储非持久状态或敏感信息。例如,Swarm服务使用tmpfs挂载将Secret信息挂载到服务的容器中。
适用场景
- 不希望数据在主机或容器内持久化的情况。例如:安全原因;
- 当应用程序为了容器性能,需要写入大量非持久状态数据时。
命名管道
npipe挂载可用于Docker主机和容器之间的通信。
常见用例是在容器内部运行第三方工具,并使用命名管道连接到Docker Engine API。