管理 Docker 中的数据
默认情况下,容器内创建的所有文件都存储在可写的容器层。这意味着
- 当该容器不再存在时,数据不会持久保存,并且如果另一个进程需要该数据,则很难从容器中获取该数据。
- 容器的可写层与运行容器的主机紧密耦合。您无法轻松地将数据移动到其他位置。
- 写入容器的可写层需要一个 存储驱动程序 来管理文件系统。存储驱动程序提供了一个联合文件系统,使用 Linux 内核。与使用数据卷相比,这种额外的抽象会降低性能,数据卷直接写入主机文件系统。
Docker 为容器提供了两种在主机上存储文件的方法,以便即使在容器停止后,这些文件也能持久保存:卷和绑定挂载。
Docker 还支持容器在主机内存中存储文件。这些文件不会持久保存。如果您在 Linux 上运行 Docker,则使用tmpfs
挂载将文件存储在主机的系统内存中。如果您在 Windows 上运行 Docker,则使用命名管道将文件存储在主机的系统内存中。
选择正确的挂载类型
无论您选择使用哪种类型的挂载,数据在容器内部看起来都一样。它作为容器文件系统中的目录或单个文件公开。
一个容易理解卷、绑定挂载和tmpfs
挂载之间差异的方法是思考数据在 Docker 主机上的存储位置。
卷存储在主机文件系统的一部分中,该部分由Docker 管理(在 Linux 上为
/var/lib/docker/volumes/
)。非 Docker 进程不应修改文件系统的这部分。卷是将数据持久保存到 Docker 中的最佳方法。绑定挂载可以存储在主机系统的任何位置。它们甚至可能是重要的系统文件或目录。Docker 主机或 Docker 容器上的非 Docker 进程可以随时修改它们。
tmpfs
挂载仅存储在主机系统的内存中,并且永远不会写入主机系统的文件系统。
绑定挂载和卷都可以使用-v
或--volume
标志挂载到容器中,但每种方法的语法略有不同。对于tmpfs
挂载,您可以使用--tmpfs
标志。我们建议对容器和服务都使用--mount
标志,无论是绑定挂载、卷还是tmpfs
挂载,因为语法更清晰。
卷
卷由 Docker 创建和管理。您可以使用docker volume create
命令显式创建卷,或者 Docker 可以在创建容器或服务时创建卷。
当您创建卷时,它存储在 Docker 主机上的目录中。当您将卷挂载到容器中时,此目录就是挂载到容器中的目录。这与绑定挂载的工作方式类似,不同之处在于卷由 Docker 管理,并且与主机的主要功能隔离。
给定的卷可以同时挂载到多个容器中。当没有运行的容器使用卷时,卷仍然可用于 Docker,并且不会自动删除。您可以使用docker volume prune
删除未使用的卷。
当您挂载卷时,它可能是命名卷或匿名卷。匿名卷被赋予一个随机名称,该名称保证在给定的 Docker 主机中是唯一的。与命名卷一样,匿名卷即使在您删除使用它们的容器后仍然存在,除非在创建容器时使用--rm
标志,在这种情况下,匿名卷会被销毁。请参见 删除匿名卷。如果您依次创建多个使用匿名卷的容器,则每个容器都会创建自己的卷。匿名卷不会自动在容器之间重用或共享。要在一个或多个容器之间共享匿名卷,您必须使用随机卷 ID 挂载匿名卷。
卷还支持使用卷驱动程序,这使您能够将数据存储在远程主机或云提供商上,以及其他可能性。
绑定挂载
与卷相比,绑定挂载的功能有限。当您使用绑定挂载时,主机上的文件或目录会挂载到容器中。文件或目录通过其在主机上的完整路径引用。该文件或目录不需要已经存在于 Docker 主机上。如果它还不存在,则会按需创建。绑定挂载速度很快,但它们依赖于主机文件系统具有可用的特定目录结构。如果您正在开发新的 Docker 应用程序,请考虑改用命名卷。您无法使用 Docker CLI 命令直接管理绑定挂载。
重要
绑定挂载默认情况下允许对主机上的文件进行写入访问。
使用绑定挂载的一个副作用是,您可以通过在容器中运行的进程来更改主机文件系统,包括创建、修改或删除重要的系统文件或目录。这是一种强大的能力,可能会对安全产生影响,包括影响主机系统上的非 Docker 进程。
提示
处理大型存储库或单体仓库,或者处理不再随着代码库扩展的虚拟文件系统?查看 同步文件共享。它通过使用同步文件系统缓存来增强绑定挂载性能,从而提供快速灵活的主机到 VM 文件共享。
tmpfs
tmpfs
挂载不会持久保存到磁盘上,无论是 Docker 主机还是容器内部。容器可以在容器的生命周期内使用它来存储非持久性状态或敏感信息。例如,在内部,Swarm 服务使用tmpfs
挂载将 密钥 挂载到服务的容器中。
命名管道
命名管道 可用于 Docker 主机和容器之间的通信。常见的用例是在容器内运行第三方工具并使用命名管道连接到 Docker Engine API。
卷的良好用例
卷是在 Docker 容器和服务中持久保存数据的首选方法。卷的一些用例包括
在多个运行的容器之间共享数据。如果您没有显式创建它,则卷会在第一次挂载到容器中时创建。当该容器停止或被删除时,卷仍然存在。多个容器可以同时挂载同一个卷,无论是读写还是只读。卷只有在您显式删除它们时才会被删除。
当 Docker 主机没有保证具有给定的目录或文件结构时。卷帮助您将 Docker 主机的配置与容器运行时分离。
当您想要将容器的数据存储在远程主机或云提供商上,而不是本地存储时。
当您需要备份、恢复或将数据从一个 Docker 主机迁移到另一个 Docker 主机时,卷是更好的选择。您可以停止使用卷的容器,然后备份卷的目录(例如
/var/lib/docker/volumes/<volume-name>
)。当您的应用程序需要在 Docker Desktop 上进行高性能 I/O 时。卷存储在 Linux 虚拟机中,而不是主机中,这意味着读写操作具有更低的延迟和更高的吞吐量。
当您的应用程序需要在 Docker Desktop 上进行完全本地的文件系统行为时。例如,数据库引擎需要对磁盘刷新进行精确控制,以确保事务持久性。卷存储在 Linux 虚拟机中,可以满足这些保证,而绑定挂载则被远程到 macOS 或 Windows,在那里文件系统的行为略有不同。
绑定挂载的良好用例
一般来说,您应该尽可能使用卷。绑定挂载适用于以下类型的用例
从主机共享配置文件到容器。这是 Docker 默认情况下为容器提供 DNS 解析的方式,通过将主机的
/etc/resolv.conf
挂载到每个容器中。在 Docker 主机上的开发环境和容器之间共享源代码或构建制品。例如,您可以将 Maven 的 `target/` 目录挂载到容器中,每次您在 Docker 主机上构建 Maven 项目时,容器都能访问重建的制品。
如果您以这种方式使用 Docker 进行开发,您的生产 Dockerfile 将直接将生产就绪的制品复制到镜像中,而不是依赖于绑定挂载。
当 Docker 主机的文件或目录结构保证与容器所需的绑定挂载一致时。
tmpfs 挂载的良好用例
tmpfs
挂载最适合您不想将数据持久化到主机或容器的情况。这可能是出于安全原因,或者为了在您的应用程序需要写入大量非持久性状态数据时保护容器的性能。
使用绑定挂载或卷的提示
如果您使用绑定挂载或卷,请牢记以下几点:
如果您将一个空卷挂载到容器中存在文件或目录的目录中,这些文件或目录将被传播(复制)到卷中。类似地,如果您启动一个容器并指定一个尚未存在的卷,将为您创建一个空卷。这是一种预填充另一个容器所需数据的良好方法。
如果您将一个绑定挂载或非空卷挂载到容器中存在一些文件或目录的目录中,这些文件或目录将被挂载遮蔽,就像您将文件保存到 Linux 主机上的 `/mnt`,然后将 USB 驱动器挂载到 `/mnt` 一样。`/mnt` 的内容将被 USB 驱动器的内容遮蔽,直到 USB 驱动器被卸载。被遮蔽的文件不会被删除或更改,但在绑定挂载或卷被挂载期间不可访问。