在Docker容器内部创建的文件默认存储在可写的容器层,容易产生几个问题:

  • 当容器不存在时,数据文件不能持久化,同时这些数据文件不方便在容器之外被其他进程使用。
  • 当容器运行的时候容器可写层严重依赖宿主机,不能轻易移动这些数据文件到其他地方。
  • 在容器层写数据文件需要存储驱动(storage driver)来管理文件系统,存储驱动使用Linux内核提供的联合文件系统, 与data volumes直接将文件写到宿主机文件系统相比,性能降低。

Docker为容器提供了两种方式将数据文件存储到宿主机上,即使容器停止运行或者被删除数据文件都可以持久化,这两种方式分别为 volumes与bind mounts,当然如果Docker容器在Linux运行,也可以使用tmpfs mounts。不管使用哪种mount方式,数据文件在Docker容器内部文件系统中是相同的, 要么是一个文件夹,或者一个独立的文件。




windows 无法ping通docker容器 docker容器ping不通外网_Docker


  • volumes 存储在Docker安装目录下,在Linux上默认指的是/var/lib/docker/volumes,Docker会自动管理,非Docker进程不应该修改这些文件系统,volumes是在Docker中是最好的数据持久化方式。
  • bind mount 存储在宿主机文件系统的任何地方,宿主机上的非Docker进程或者Docker容器都可以在任何时候修改它。
  • tmpfs mount 始终存储在宿主机系统内存中,不会被写到宿主机的文件系统中。

详细介绍

  • volumes

Docker会自动创建并管理volumes,当然可以通过命令docker volumes create明确的创建一个volume,当成功创建了一个volume时,它存储在宿主机的某个目录下, 当把这个volume挂载到一个Docker容器时,这个目录自然会挂载到容器内部,volumes与bind mount工作方式类似,除了volumes是被Docker自动管理以及隔离性, 两者没什么区别。

[root@ins ~]# docker volume create mmmm[root@ins ~]# docker volume createcc0613fe5a32273134a76e5670f166f6e248634e909d64cf00061130086f5ae5[root@ins ~]# docker volume lsDRIVER VOLUME NAMElocal cc0613fe5a32273134a76e5670f166f6e248634e909d64cf00061130086f5ae5local mm[root@ins ~]#

一个volume可以同时挂载到多个Docker容器,当没有任何Running状态的容器使用这个volume,这个volume仍然有效并且不会被自动删除,除非通过执行命令 docker volume prune进行删除。当挂载一个volume时,这个volume可能匿名或者有一个名字,当它首次挂载到容器中的时候如果Docker发现该volume没有一个明确的名字, 则会给它分配一个随机的名字,这个名字在Docker宿主机上是唯一的。

volumes支持volume driver,允许通过driver将数据存储到远程机器或者云厂商等。

  • bind mounts

这种方式与volumes相比,有一些功能限制。当使用bind mounts时,宿主机上的一个文件或者目录被挂载到Docker容器中,这个文件或者目录通过它在 宿主机上的完整路径名被引用,他们在宿主机上不是必须存在的,在需要的时候Docker会自动创建它。bind mounts非常高效,但是他们依赖于宿主机文件系统明确的目录结构, 同时通过Docker CLI命令无法直接管理这些bind mounts。

注意:正在运行的容器中进程可以直接改变宿主机上的文件系统,包括创建、修改以及删除重要的文件或者目录,会引发安全风险问题,影响宿主机上运行的其它非Docker进程,请注意控制权限。

  • tmpfs mounts

这种方式不能将数据持久化到磁盘,一个tmpfs可以被一个容器在整个生命周期内使用,用于存储一些非持久状态或者敏感数据,比如swarm services使用tmpfs将secrets 挂载到service的容器中。

volumes与bind mounts都能通过-v 或者 --volume flag参数挂载到容器中,对于 tmpfs mount,可以使用--tmpfs flag参数,在Docker17.06以及更高版本中, 推荐使用--mount,对于这三种方式--mount语法更明确。


三种方式优点

volumes可以在多个运行的容器之间共享,解耦Docker容器与宿主机文件系统,支持存储远程以及云厂商,方便在不同的Docker机器上迁移数据。

bind mounts可以让多个容器共享宿主机文件,比如Docker就是通过将/etc/resolv.conf挂载到每个容器方式实现DNS解决方案,开发的时候可以共享项目源代码,在容器内编译运行。

tmpfs保存敏感数据,非持久化数据,由于保存在内存中,相比文件系统性能更高。

默认规则:

  • 如果将一个空的volumes挂载到容器内的某个目录,如果该目录中已经有一些文件或者目录,那么这些文件或者目录会直接复制到volumes中。
  • 如果将一个bind mount或者非空volume挂载到容器的某个目录,这个目录中已经存在文件或者目录,那么这个目录中的文件或者目录会被mount覆盖,被覆盖的文件或者目录只是暂时被隐藏,当移除挂载时即可恢复。

使用介绍

早期,Docker都是通过flag -v或者--volume给单机容器实现挂载,而swarm service则是通过 flag --mount实现,在Docker 17.06版本开始,--mount也适用于单机容器挂载,该命令的 语法更灵活明确,在使用-v或者--volume时尽量使用--mount代替。

-v or –volume

-v db:/var/lib/mysql,通过英文冒号分隔,如果volume有名字,冒号之前的是volume,如果volume匿名,则直接 -v /var/lib/mysql,如果需要控制容器读写volume权限,可以 -v db:/var/lib/mysql:ro

–mount

--mount包含许多以英文逗号分隔的key-value键值对,它的语法比-v以及--volume更详细,key的顺序无关紧要,主要包含以下key(只列举部分)

  • type 它的值可以为 volume、bind或者tmpfs
  • source 对于已命名的volume,source即为volume名字,volume匿名,则该值为空,source也可定义为src
  • destination 指定挂载到容器中的path路径,可以定义为dst、destination或者target
  • readonly 如果存在,则被挂载的volume在容器中只能读
  • volume-opt 可选参数,可以定义多次,key-value形式

基础使用

创建一个volume

docker volume create sunjinfu

查看volume

docker inspect sunjinfu[ { "CreatedAt": "2019-04-20T15:00:12+08:00