docker中的数据管理

翻译自docker官方文档,原文:https://docs.docker.com/storage/

在容器的可写层中存储数据是可行的,但有以下弊端:

  • 容器关闭后,数据会丢失。而且如果其他程序需要这些数据时,很难把这些数据导出到容器外。
  • 容器的可写层是跟容器所在的宿主机紧密关联的,你不能轻易把数据移到其他地方。
  • 写入容器的可写层需要一个存储驱动(storage driver)来管理文件系统。该驱动要使用Linux内核来提供一个联合文件系统,和使用数据卷,直接写入宿主机文件系统的方式相比,这种额外的开销会降低性能。

docker提供了三种从docker宿主机把数据挂载到容器内的方法:数据卷(volumes),挂载点(bind mounts)和tmpfs卷(tmpfs volumes)。当你不确定的时候,数据卷几乎总是正确的选择。继续阅读以了解每种方式的详细信息。

选择正确的挂载方式

不管你选择哪种挂载方式,在容器内看起来,数据都是一样的。在容器的文件系统中,他们看起来就是一个文件夹或独立的文件。
一种直观的了解数据卷,挂载点和tmpfs挂载的区别的方法是思考数据存放在docker宿主机中的什么位置。
docker中的数据管理

  • 数据卷存放在宿主机文件系统中的被docker管理的一块(在Linux中是/var/lib/docker/volumes/)。非docker相关的进程不应修改这部分文件系统。数据卷是在docker中持久化数据的最好方式。
  • 挂载点方式中的数据可以是存放在宿主机文件系统的任何位置的数据,甚至可以是很重要的系统文件或文件夹。宿主机上的非docker相关的进程或docker容器可以随时修改这些数据。
  • tmpfs挂载方式中的数据只能存放在宿主机的内存中,而且永远不能被写到宿主机文件系统中。

关于挂载方式的更多细节

  • 数据卷:由docker创建并管理。你可以使用docker volume create命令来手动创建一个数据卷,docker也可以在容器或服务启动过程中自己创建数据卷。
    当你创建数据卷时,它是存放在宿主机的一个目录中的。当你把该数据卷挂载到容器中时,实际上挂载的是它所在的目录。这和挂载点方式(bind mounts)是一样的,只是数据卷是被docker管理并和宿主机核心功能隔离的。
    一个数据卷可以同时被多个容器挂载。当没有正在运行的容器挂载某数据卷时,该数据卷对docker来说仍是可用的,并且不会自动删除。你可以用docker volume prune命令删除不用的数据卷。
    你可以挂载一个有名字的或匿名的数据卷,匿名数据卷在首次挂载到某容器时没有被显式的给定名字,所以docker会给它一个随机编号作为名字,而且保证在指定宿主机内编号的唯一性。除了名字,命名的和匿名的数据卷其他表现都是一样的。
    数据卷也支持数据卷驱动器的使用,这让你能把数据存到远程主机或云平台或其他地方。

  • 挂载点:在docker早期就支持的一种方式。和数据卷相比,挂载点在功能上有些限制。当你用挂载点方式时,宿主机上的一个文件夹或文件会被挂载到容器内。该文件夹或文件由它在宿主机上的绝对路径确定。该文件夹或文件不需要事先在宿主机中存在。如果不存在,会被要求创建(译者注:这一点在-v--mount参数中有不同的表现,前者会自动创建文件夹,后者则报告一个错误)。挂载点的性能是很高的,但它要求宿主机的文件系统有一个确定的目录结构可用。(译者注:意思可能是,容器会依赖这个挂载点的目录结构,这就要求宿主机不能修改目录结构,否则容器内的进程可能会出错)如果是在开发新的docker应用,尽量考虑用命名的数据卷而不是挂载点。你不能用docker命令行接口直接管理挂载点。
    ❌警告:不管对你来说是好是坏,挂载点的一个副作用是你可以通过容器内的进程来修改宿主机的文件系统,包括创建,修改或删除重要的系统文件或文件夹。这是个很强大的能力,并且可能导致安全隐患,比如和宿主机上的非docker进程产生冲突。

  • tmpfs挂载:tmpfs挂载点不会持久化到磁盘,不管是在docker宿主机还是容器内。他可以在容器的一个生命周期内使用,用来存储不需要持久化的数据或敏感数据。比如,在集群(swarm)内部,会使用tmpfs挂载来把敏感数据挂载到服务内的容器中。

挂载点和数据卷都可以通过-v--volume标示来挂载到容器内,但两者的语法有细微的差异,至于tmpfs挂载,你可以用--tmpfs标示。但是在docker17.06及以后的版本里,我们推荐使用--mount参数,不管是启动容器还是服务,不管是挂载点,数据卷还是tmpfs挂载,因为这个语法更清晰易懂。

数据卷的适用场景

数据卷是在docker容器和服务中持久化数据的较好方式。以下是一些数据卷的适用场景:

  • 在多个运行中的容器间共享数据。如果你没有显示地创建一个数据卷,他会在第一次被挂载到某容器时被创建。当该容器停止或被删除后,数据卷仍会保留。多个容器可以同时挂载同一个数据卷,不管是以只读方式还是可读写方式。数据卷只有在你明确删除它们的时候才会被删除。
  • 当docker宿主机不能确保存在指定的目录或文件结构时。数据卷会帮你把容器运行时和docker宿主机进行解耦。(不知道翻译的对不对:When the Docker host is not guaranteed to have a given directory or file structure. Volumes help you decouple the configuration of the Docker host from the container runtime.)
  • 当你想把容器的数据存到远程主机或云平台,而不是本地时。
  • 当你需要备份,复制或移动一个docker宿主机中的数据到另一个宿主机时,数据卷是更好的选择。你可以先禁止容器使用该数据卷,然后备份该数据卷的文件夹(比如/var/lib/docker/volumes/<volume-name>)。

挂载点的适用场景

一般情况下,你应该尽可能的使用数据卷。挂载点适用于以下场景:

  • 从宿主机中向容器共享配置。这是docker向容器提供DNS解析的默认方式,通过把宿主机的/etc/resolv.conf挂载到容器内。
  • 在docker宿主机上的开发环境和容器之间共享源代码或构建好的产品。比如,你可以把maven的target/文件夹挂载到容器中,每当你在宿主机构建maven项目时,容器都会直接访问到重构后的产品。
    如果你用这种方式进行docker开发,你生产环境的Dockerfile会把可上线的产品直接拷贝到镜像中,而不是使用挂载点。
  • 当宿主机的文件和目录结构能确保和容器的挂载点需要的格式始终一致时。

tmpfs挂载的适用场景

tmpfs挂载最好的使用场景是你不想把数据持久化到宿主机或容器内的时候。可能是出于安全性的考虑或为了保证应用要写很大的不需持久化的数据时的性能。

使用挂载点或数据卷的提示

如果你用挂载点或数据卷,记住下面的提示:

  • 如果你把一个空数据卷挂载到容器内的一个有文件或文件夹存在的目录,那些文件或文件夹会被拷贝到数据卷中。类似的,如果你启动容器时指定了一个不存在的数据卷,一个空的数据卷会被创建。这是个预准备其他容器需要的数据的好方法。
  • 如果你挂载一个挂载点或非空的数据卷到容器内的一个有文件或文件夹存在的目录,容器内的那些文件或文件夹会被挂载覆盖。就像你在Linux主机中把文件保存到/mnt目录,然后把一个USB设备挂载到/mnt目录一样,/mnt目录原来的内容会被USB设备中的内容覆盖,直到USB设备被卸载。被覆盖的文件没有被删除或修改,只是在挂载点或数据卷被挂载的时候不能被访问到。