Docker镜像是由多个文件系统[只读层]叠加而成。当我们启动一个容器的时候,Docker会加载只读镜像层并在其上[镜像栈顶部]添加一个读写层。如果运行中的容器修改了现有的一个已经存在的文件,那该文件将会从读写层下面的只读层复制到读写层,然后在读写层进行修改,但是文件的只读版本仍然存在于只读层,只是已经被读写层中该文件的副本所隐藏。当删除Docker容器,并通过该镜像重新启动时,之前在读写层的更改将会丢失。所以默认情况下,数据在Docker运行时无法进行持久化操作。

为了能够持久化数据以及共享容器间的数据,Docker提出了Volume的概念。简单来说,数据卷是可以存在于一个或多个容器中的特定文件或文件夹,并且以正常的文件或者目录的形式存在于宿主机上。其生存周期独立于容器的生存周期。

目前Docker提供了三种不同的方式将数据从宿主机挂载到容器中: volume[最常用], bind mount[比较常用], tmpfs mount[很少使用]。

Docker Volume
  • docker volume: Docker管理宿主机文件系统的一部分,默认位于 var/lib/docker/volumes 目录中。

  • bind mounts: 可以存储在宿主机系统的任意位置, 但是在不同的宿主机系统时不可移植,比如Windows和Linux的目录结构是不一样的,bind mount所指向的host目录也不能一样。这也是为什么bind mount不能出现在Dockerfile中的原因,因为这样Dockerfile就不可移植了。

  • tmpfs:挂载存储在宿主机系统的内存中,而不会写入宿主机的文件系统。

Best Practice

docker 专门提供了 volume 子命令来操作数据卷。

create     创建数据卷
inspect    显示数据卷的详细信息
ls         列出所有的数据卷
prune      删除所有未使用的 volumes,并且有 -f 选项
rm         删除一个或多个未使用的 volumes,并且有 -f 选项

create volume

$ docker volume create myvol
myvol

$ docker volume ls
DRIVER              VOLUME NAME
local               myvol

$ docker volume inspect myvol
[
    {   
        "CreatedAt": "2021-12-02T10:36:58-06:00",
        "Driver": "local",
        "Labels": {},
        "Mountpoint": "/var/lib/docker/volumes/myvol/_data",
        "Name": "myvol",
        "Options": {},
        "Scope": "local"
    }
]

mount volume

docker提供两种命令行方式使用数据卷,-v--mount,具体用法如下:

-v/--volume
由三个字段组成,卷名:容器路径:选项列表。选项列表可以是ro/rw,也就是read-only和read-write
--mount,由多个键值对组成,由,分隔,每个由一个<key=<value>>元组组成。
type,值可以为 bind,volume,tmpfs。
source,对于命名卷,是卷名。对于匿名卷,这个字段被省略。可能被指定为 source 或 src。
destination,文件或目录将被挂载到容器中的路径。可以指定为 destination,dst 或 target。
volume-opt 可以多次指定。

reference:

  1. https://yeasy.gitbook.io/docker_practice/
  2. https://www.modb.pro/db/41033