
Author:rab
Docker 为容器提供了两种存放数据的资源:
不同操作系统 Docker 默认的存储驱动可能不同,如 Ubuntu 15.04 使用的存储驱动是 aufs,底层文件系统时 extfs。而我下图中是 CentOS 7.9。其 Docker 存储驱动就是 overlay2。

查看存储驱动

之前博客中提到 Docker 的 Copy-on-Write 特性,之所以可以实现这样的特性,主要是因为我们 Docker Storage Driver 存储驱动,它实现了多层数据堆叠,并为用户提供一个单一的合并之后的统一视图。有兴趣的可以去看看我前面的博客《Docker 的 Copy-on-Write 特性》。
Docker 支持多种 Storage Driver,主要有这几种类型:
VFS
ZFS
Btrfs
AUFS
OverlayFS
Device Mapper
对于 DOcker 使用哪种类型的存储引擎,官方给出的答案是:默认使用你当前 Linux 发行版的 Storage Driver,因为默认的 Storage Driver 是最稳定存储引擎,在发行版上经过了严格的测试。
使用 Storage Driver 数据存储有什么优势呢?对于那些无状态(即无需数据持久化到本地)的容器,Storage Driver 的优势将是毫无疑问的,因为它能从镜像直接创建、删除(且删除时生成的数据也一并随容器删除)。
而对于需要做数据持久化的容器,Storage Driver 显然就不如 Data Volume,也就是对于这类有状态的容器,我们要用到 Docker 的 Data Volume 来做容器数据持久化存储。
Data Volume 实际上是我们宿主机上的目录或文件,我们通过挂载的方式将 Host 的目录或文件挂载到容器内部文件系统,有时也可以说是把容器文件系统映射到宿主机上。
这样一来容器产生的数据就可以往 Volume 写入数据了,并持久化到 Host 本地了,即使该容器被删除了,再次运行一个新的容器,状态也是与之前保持一致的。
该类型是将 Host 上已存在的目录或文件 mount 到容器。
1、具体案例
看下面案例:其语法结构为 -v
docker run -it \
--name=elasticsearch \
--privileged=true \
--restart=always \
--net=host \
-v /etc/localtime:/etc/localtime \
-v /data/elasticsearch/data:/usr/share/elasticsearch/data \
-v /data/elasticsearch/logs:/usr/share/elasticsearch/logs \
-v /data/elasticsearch/plugins:/usr/share/elasticsearch/plugins \
-v /data/elasticsearch/config/elasticsearch.yml:/usr/share/elasticsearch/config/elasticsearch.yml \
-e ES_JAVA_OPTS="-Xms512m -Xmx512m" \
-e "discovery.type=single-node" \
-d elasticsearch:6.8.20
注意:如果 container_path 存在数据,则会被隐藏,取而代之的是 Host mount 的目录或文件,这与 Linux 中 mount 效果一样。
2、带有权限的 bind mount
类似 Linux 的 mount,在挂载时可指定挂载目录权限,默认时读写权限。
docker run -it \
...
-v /data/elasticsearch/plugins:/usr/share/elasticsearch/plugins:ro \
...
# ro:只读
# rw:读写
小结:从上面的案例上看,bind mount 可实现对目录或文件的 mount 操作,可根据你的实际情况操作。
与 bind mount 不同的是,docker managed volume 不需要指定 mount 源,只需指明挂载点(mount point)即可。
1、案例
docker run -d --name=tmp -p 8280:80 -v /usr/local/apache2/htdocs httpd
我只指定了容器内部挂载点,并没有指定 Host 源目录/文件,那这个数据持久化到 Host 的哪个位置呢?

继续查看容器的详细信息:
docker inspect tmp
# 看 Mount 部分

2、如何持久化呢?
此时上图红框中的部分就是数据持久化目录了,就可以像 bind mount 对持久化目录/文件进行相关更新了。具体如下:
当前内容

内容更新
[root@docker_swarm_work1 _data]# pwd
/var/lib/docker/volumes/fb39b435deb9bd50531b7da00ff1313f94bed8e489afb0ff69f27b77cd8a9253/_data
[root@docker_swarm_work1 _data]# cat index.html
<html><body><h1>It works!</h1></body></html>
[root@docker_swarm_work1 _data]# echo 'Update It works!
' > index.html

删除容器并新起一个容器(验证数据持久化)
docker stop tmp && docker rm tmp
docker run -d --name=tmp -p 8288:80 -v /usr/local/apache2/htdocs httpd
# 再起一个新容器的话,docker 又会重新创建一个随机的持久话目录
# 但是我们之前的数据依然是在红框的上一个目录里面的

docker volume ls

但是需注意,docker volume ls 只能查看 docker managed volume 类型的 Data Volume, bind mount 的 Data Volume 需要通过 docker inspect 来查看。
如果我想在删除容器时,连 volume 也一并删除,如何操作?
docker stop tmp
docker rm -v tmp
# 其中-v就表示volume
# 如果你确定不再需要这些持久化数据了就可执行 -v 操作
# docker rm -v 对 bind mount 类型的volume无效(也是无法删除,想删除需手动)
# 如果你运行容器时指定了--rm,那在停止容器时volume也会被自动删除(当然也是只对docker managed volume才有效)

bind mount 与 docker managed volume 就类似于动态指定端口和静态指定端口,动态指定端口:-p 80 此时会将容器的 80 端口在 Host 上映射一个随机端口,静态指定端口:-p 8080:80。
区别:
bind mount 指定的数据卷是静态的,而 docker managed volume 指定的数据卷是随机动态的;
bind mount 挂载时 Host 源 path 会覆盖掉容器目标 path(但并不代表被永久替换),而 docker managed volume 则是将容器原有的目录或文件随机持久化在 /var/lib/docker/volumes 目录下;
bind mount 可指定挂载目录的读写权限,而 docker managed volume 不能;
bind mount 的 mount 源可以是目录或文件,而 docker managed volume 只能是目录。
对于无状态(无需做数据持久化)的容器我们可以选择 Storage Driver 默认存储引擎即可,如果对于有状态(需做数据持久化)的容器我们需要引入 Data Volume 实现数据持久化。