Author:rab
目录
前言
Docker 为容器提供了两种存放数据的资源:
- storage driver:管理镜像层和容器层;
- data volume:管理容器应用数据。
一、Storage Driver
1.1 Storage Driver 介绍
不同操作系统 Docker 默认的存储驱动可能不同,如 Ubuntu 15.04 使用的存储驱动是 aufs,底层文件系统时 extfs。而我下图中是 CentOS 7.9。其 Docker 存储驱动就是 overlay2。
查看存储驱动
之前博客中提到 Docker 的 Copy-on-Write 特性,之所以可以实现这样的特性,主要是因为我们 Docker Storage Driver 存储驱动,它实现了多层数据堆叠,并为用户提供一个单一的合并之后的统一视图。有兴趣的可以去看看我前面的博客《Docker 的 Copy-on-Write 特性》。
1.2 Storage Driver 类型
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
2.1 Data Volume 介绍
Data Volume 实际上是我们宿主机上的目录或文件,我们通过挂载的方式将 Host 的目录或文件挂载到容器内部文件系统,有时也可以说是把容器文件系统映射到宿主机上。
这样一来容器产生的数据就可以往 Volume 写入数据了,并持久化到 Host 本地了,即使该容器被删除了,再次运行一个新的容器,状态也是与之前保持一致的。
2.2 Data Volume 类型
2.2.1 bind mount
该类型是将 Host 上已存在的目录或文件 mount 到容器。
1、具体案例
看下面案例:其语法结构为 -v <Host_path>:<container_path(不存在则创建)>
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 操作,可根据你的实际情况操作。
2.2.2 docker managed volume
与 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 '<html><body><h1>Update It works!</h1></body></html>' > index.html
-
删除容器并新起一个容器(验证数据持久化)
docker stop tmp && docker rm tmp docker run -d --name=tmp -p 8288:80 -v /usr/local/apache2/htdocs httpd # 再起一个新容器的话,docker 又会重新创建一个随机的持久话目录 # 但是我们之前的数据依然是在红框的上一个目录里面的
2.3 查看 Data Volume
docker volume ls
但是需注意,docker volume ls
只能查看 docker managed volume
类型的 Data Volume
, bind mount
的 Data Volume
需要通过 docker inspect <container_name>
来查看。
如果我想在删除容器时,连 volume 也一并删除,如何操作?
docker stop tmp
docker rm -v tmp
# 其中-v就表示volume
# 如果你确定不再需要这些持久化数据了就可执行 -v 操作
# docker rm -v <container_name> 对 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
实现数据持久化。