Docker存储之Storage Driver和Data Volume
在使用 Docker 的过程中,势必需要查看容器内应用产生的数据,或
者需要将容器内数据进行备份,甚至多个容器之间进行数据共享,这就必然
会涉及到容器的数据管理
Docker 为容器提供了两种存放数据的资源:
A、由 Storage Driver 管理的镜像层和容器层
B、Data Volume
一、Storage Driver
容器 = 1个最上层的可写容器层 + N干只读镜像层组成
容器的数据 就存放在这些层中
分层结构的特性是 Copy-on-Write:
A、新数据 直接存放在最上层的容器层
B、修改现有数据 先从镜像层将数据复制到容器层,修改后的数据 直接保存在容器层,镜像层保持不变
C、如果N个层中有命名相同的文件,用户只能看到最上面那层中的文件
Docker Storage Driver 实现了多层数据的堆叠并为用户提供一个单一的合并之后的统一视图
Docker 支持多种 Storage Driver,有 AUFS、Device Mapper、Btrfs、OverlayFS、VFS 和 ZFS 它们都能实现分层的架构,同时又有各自的特性
Docker 官方给出:
优先使用 Linux 发行版默认的 Storage Driver
Docker 安装时会根据当前系统的配置选择默认的 driver
默认 driver 具有最好的稳定性,因为默认 driver 在发行版上经过了严格的测试
查看本机Docker使用的Storage Driver:
docker info
Client:
Debug Mode: false
Server:
Containers: 3
Running: 3
Paused: 0
Stopped: 0
Images: 13
Server Version: 19.03.8
Storage Driver: overlay2
Backing Filesystem: <unknown>
Supports d_type: true
Native Overlay Diff: true
Logging Driver: json-file
Cgroup Driver: cgroupfs
Plugins:
Volume: local
Network: bridge host ipvlan macvlan null overlay
Log: awslogs fluentd gcplogs gelf journald json-file local logentries splunk syslog
Swarm: inactive
Runtimes: runc
Default Runtime: runc
Init Binary: docker-init
containerd version: 7ad184331fa3e55e52b890ea95e65ba581ae3429
runc version: dc9208a3303feef5b3839f4323d9beb36df0a9dd
init version: fec3683
Security Options:
seccomp
Profile: default
Kernel Version: 3.10.0-862.el7.x86_64
Operating System: CentOS Linux 7 (Core)
这里CentOS 7 使用:Storage Driver: overlay2
1、无状态容器
直接将数据放在由 Storage Driver 维护的层中是很好的选择,
无状态意味着容器没有需要持久化的数据,随时可从镜像直接创建
例如: busybox,是一个工具箱,启动 busybox 是为执行诸如 wget,ping 之类命令,不需要保存数据供以后使用,使用完直接退出,容器删除时存放在容器层中的工作数据也一起被删除,下次再启动新容器即可
2、有状态容器
有持久化数据的需求,容器启动时需要加载已有的数据,容器销毁时希望保留产生的新数据
这时需要使用,Docker 另一种存储机制:Data Volume
二、Data Volume
Data Volume 是 Docker Host 文件系统中的目录或文件,能够直接被 mount 到容器的文件系统中
Data Volume 有以下特点:
A、Data Volume 是目录或文件,不是没有格式化的磁盘(块设备)
B、容器可读写 volume 中的数据
C、volume 数据可被永久保存,即使使用它的容器已经销毁
数据层(镜像层和容器层)和 volume 都可以用来存放数据,应如何选择?
A、Database 软件 vs Database 数据
B、Web 应用 vs 应用产生的日志
C、数据分析软件 vs input/output 数据
D、Apache Server vs 静态 HTML 文件
前者放在数据层,因为这部分内容是无状态的,应该作为镜像的一部分
后者放在 Data Volume ,这是需要持久化的数据,并且应该与镜像分开存放
如何设置 voluem 的容量?
volume 是 docker host 文件系统的一部分,所以 volume 的容量取决于host文件系统当前未使用的空间,目前还没有方法设置 volume 的容量
docker 从使用方式角度,提供2种类型的 volume:
bind mount 和 docker managed volume
1、bind mount
bind mount 是将 host 上已存在的目录或文件 mount 到容器上
情景1:
docker host 上有目录 $HOME/htdocs:
cat htdocs/index.html
this is a file in host file system !haha
-v 参数 ,mount 到 httpd容器:
docker run -d -p 80:80 --name=web02 -v ~/htdocs:/usr/local/apache2/htdocs httpd
指令解析:
-v 的格式为 <host path>:<container path>
/usr/local/apache2/htdocs 是 apache server 存放静态文件的地方
由于 /usr/local/apache2/htdocs 已经存在,原有数据会被隐藏起来,取而代之的是 host $HOME/htdocs/ 中的数据,这与 Linux mount 命令的行为是一致的
从host上访问httpd容器:
curl 127.0.0.1:80
结果显示:当前主页确实是 $HOME/htdocs/index.html 中的内容
更新一下,看是否能生效:
echo “update 2020-05-27” >> ~/htdocs/index.html
再从host上访问httpd容器:
curl 127.0.0.1:80
事实证明:
host 中的修改确实生效了,bind mount 可让 host 与容器共享数据
情景2:
当httpd的web02容器销毁
docker stop web02
docker rm web02
cat ~/htdocs/index.html
事实证明:
即使容器被删除,bind mount 也还在,因为bind mount是host里面的文件
情景3:
bind mount 指定数据的读写权限,默认是可读可写rw,可指定为只读ro
docker run -d -p 80:80 -v ~/htdocs:/usr/local/apache2/htdocs:ro httpd
docker exec -it web02 bash
echo "add data" >> htdocs/index.html
指令解析:
ro 设置了只读权限,在容器中是无法对 bind mount 数据进行修改的
只有 host 有权修改数据,提高了安全性
情景4:
bind mount 除了目录,还可单独指定一个文件
docker run -d -p 80:80 --name=web02 -v ~/htdocs/index.html:/usr/local/apache2/htdocs/new-index.html httpd
从host上访问httpd容器默认文件:
curl 127.0.0.1:80
从host上访问httpd容器bind mount上去的文件:
curl 127.0.0.1:80/new-index.html
将 html 文件加到 apache 中,同时保留容器原有的数据
应用场景:
bind mount 单个文件,只需向容器添加文件,不覆盖整个目录
注意事项:
host 中的源文件必须存在,否则会当作一个新目录 bind mount 给容器
mount point 应用场景:
A、将源代码目录 mount 到容器中,在 host 中修改代码就能看到应用的实时效果
B、将 mysql 容器的数据放在 bind mount 里,这样 host 可以方便地备份和迁移数据
bind mount 不足之处:
A、bind mount 需指定 host 文件系统的特定路径,限制了容器的可移植性,当需将容器迁移到其他 host,而该 host 没有要 mount 的数据或者数据不在相同的路径时,操作会失败
2、Docker Managed Volume
针对容器,移植性更好的方式是 docker managed volume
docker managed volume 是不需要指定 mount 源,指明 mount point 即可
案例说明:
docker run -d -p 80:80 -v /usr/local/apache2/htdocs httpd
指令解析:
-v 参数,通知docker需要1个data volume ,并把它mount到 /usr/local/apache2/htdocs
data volume 具体位置:
docker ps -a
docker inspect c03f4ae8f062 | grep -A 10 Mounts
Mounts 内容,显示容器当前使用的所有 data volume,包括 bind mount 和 docker managed volume
Source 就是该 volume 在 host 上的目录
动作解析:
当容器申请 mount docker manged volume 时,docker 都会在/var/lib/docker/volumes 下生成一个目录(此处是
/var/lib/docker/volumes/19bb48d5ee0b3d3d04d3953044587c562873b19a3ce79e0395b083429a0e20c3/_data),该目录就是 mount 源
分析Volumes:
ls -l /var/lib/docker/volumes/19bb48d5ee0b3d3d04d3953044587c562873b19a3ce79e0395b083429a0e20c3/_data
cat /var/lib/docker/volumes/19bb48d5ee0b3d3d04d3953044587c562873b19a3ce79e0395b083429a0e20c3/_data/index.html
curl 127.0.0.1:80
volume 的内容跟容器原有 /usr/local/apache2/htdocs 完全一样
因为 mount point 指向的是已有目录,原有数据会被复制到 volume 中
/usr/local/apache2/htdocs 已不再是由 storage driver 管理的层数据了,它已是一个 data volume
对数据进行更改:
echo add data >>
/var/lib/docker/volumes/19bb48d5ee0b3d3d04d3953044587c562873b19a3ce79e0395b083429a0e20c3/_data/index.html
curl 127.0.0.1:80
docker managed volume 创建过程:
A、容器启动时,告诉 docker "我需要一个 volume 存放数据,帮我 mount 到目录 /abc"
B、docker 在 /var/lib/docker/volumes 中生成一个随机目录作为 mount 源
ll /var/lib/docker/volumes
C、若 /abc 已存在,则将数据复制到 mount 源
D、将 volume mount 到 /abc
查看volume 命令:
docker inspect c03f4ae8f062 | grep -A 10 Mounts
docker volume ls
docker volume inspect VOLUME NAME
docker volume 的局限性:
只能查看 docker managed volume
看不到 bind mount
无法知道 volume 对应的容器
bind mount 与 docker managed volume 的区别:
两种 data volume 实际上都是使用 host 文件系统的中的某个路径作为 mount 源
不同之处在于:
不同点 | bind mount | docker managed volume |
volume 位置 | 可任意指定 | /var/lib/docker/volumes/... |
对已有mount point 影响 | 隐藏并替换为 volume | 原有数据复制到 volume |
是否支持单个文件 | 支持 | 不支持,只能是目录 |
权限控制 | 可设置为只读,默认为读写权限 | 无控制,均为读写权限 |
移植性 | 移植性弱,与 host path 绑定 | 移植性强,无需指定 host 目录 |
三、volume 关键特性--数据共享
1、容器与 host 共享数据
两种类型的 data volume,可在容器与 host 之间共享数据
A、bind mount 方式:
直接将要共享的目录 mount 到容器
B、docker managed volume 方式:
volume 位于 host 中的目录,是容器启动时生成的,需将共享数据拷到 volume 中
(1) 容器和 host 之间拷贝数据
docker cp ~/htdocs/index.html c03f4ae8f062:/usr/local/apache2/htdocs
curl 127.0.0.1:80
(2) Linux 的 cp 命令复制
ll /var/lib/docker/volumes/xxx
2、容器之间共享数据
方法1:
将共享数据放在 bind mount 中,然后将其 mount 到多个容器
实例演示:
3个 httpd 容器组成的 web server 集群,使用相同的 html 文件
A、将 $HOME/htdocs mount 到三个 httpd 容器
docker run --name web0 -d -p 8080:80 -v ~/htdocs:/usr/local/apache2/htdocs httpd
docker run --name web1 -d -p 8081:80 -v ~/htdocs:/usr/local/apache2/htdocs httpd
docker run --name web2 -d -p 8082:80 -v ~/htdocs:/usr/local/apache2/htdocs httpd
B、查看当前web0、web1、web2 三容器的主页
docker ps
curl 127.0.0.1:8080
curl 127.0.0.1:8081
curl 127.0.0.1:8082
C、修改 volume 中主页内容,核实web容器集群主页的更新情况
pwd
cat htdocs/index.html
echo 20200528 add test to web container Cluster >> htdocs/index.html
cat htdocs/index.html
curl 127.0.0.1:8080
curl 127.0.0.1:8081
curl 127.0.0.1:8082
方法2:
使用 volume container
volume container 是专门为其他容器提供 volume 的容器。它提供的卷可以是 bind mount,也可以是 docker managed volume
实例演示:
创建1个volume container
docker create --name=vc-data \
-v ~/htdocs:/usr/local/apache2/htdocs \
-v /other/useful/tools \
busybox
指令解析:
--name= vc-data 容器名称
docker create 命令,volume container 是提供数据,自身不需要处于运行状态
-v 参数,容器mount了2个volume
bind mount 存放web 静态文件
docker managed volume 存放实用工具(此处为空)
docker inspect vc-data | grep -A 20 Mounts
使用volume container:
--volumes-from 参数,使用 名为 vc-data 的 volume container
docker run --name web3 -d -p 8083:80 --volumes-from vc-data httpd
docker run --name web4 -d -p 8084:80 --volumes-from vc-data httpd
docker run --name web5 -d -p 8085:80 --volumes-from vc-data httpd
docker ps
查看 httpd 容器对应的 volume
docker inspect web3 | grep -A 20 Mounts
A、httpd 容器都用 vc-data 的 volume
B、mount point 都一样
C、数据共享
修改前
cat htdocs/index.html
curl 127.0.0.1:8083
curl 127.0.0.1:8084
curl 127.0.0.1:8085
做修改
pwd
cat htdocs/index.html
echo add volume container >> htdocs/index.html
cat htdocs/index.html
修改后
curl 127.0.0.1:8083
curl 127.0.0.1:8084
curl 127.0.0.1:8085
得出结论:
web3、web4、web5 容器共享 名为 vc-data 的 volume container 中的 volume
volume container 的特点:
A、与 bind mount 相比,无需为每一个容器指定 host path,所有 path 都在 volume container 中定义好了,容器只需与 volume container 关联,容器与 host 是解耦的
B、使用 volume container 的容器其 mount point 是一致的,有利于配置的规范和标准化,同时也带来一定的局限,使用时需要综合考虑
C、volume container 的数据归根到底还是在 host 里
方法3:
使用data-packed volume container
将数据完全放到 volume container 中,同时又能与其他容器共享
容器 data-packed volume container 原理:
将数据打包到镜像中,然后通过 docker managed volume 共享
实例演示:
A、编辑Dockfile 构建镜像
# This my first busybox Dockerfile
# Version 1.0
# data-packed volume container
FROM busybox
#MAINTAINER
MAINTAINER zola
#ENV
#ADD
ADD htdocs /usr/local/apache2/htdocs
VOLUME /usr/local/apache2/htdocs
#RUN
#WORKDIR
#EXPOSE
#CMD
文件解析:
ADD 将静态文件添加到容器目录 /usr/local/apache2/htdocs
VOLUME 的作用与 -v 等效,用来创建 docker managed volume,mount point 为 /usr/local/apache2/htdocs,因为这个目录就是 ADD 添加的目录,所以会将已有数据拷贝到 volume 中
B、build 新镜像 datapacked
docker build -t datapacked .
列出各个层(layer)的创建信息:
docker history datapacked
查看详情:
docker history --no-trunc datapacked
C、用新镜像 datapacked 创建 data-packed volume container
docker create --name vc_data datapacked
指令解析:
因 Dockerfile 中已经使用了 VOLUME 指令,这里不需要再指定 volume 的 mount point
D、启动 httpd 容器并使用 data-packed volume container
docker run -d --name=web6 -p 8086:80 --volumes-from vc_data httpd
curl 127.0.0.1:8086
验证结果:
web6 容器能够正确读取 volume 中的数据
应用场景:
data-packed volume container 是自包含的,不依赖 host 提供数据,具有很强的移植性,非常适合 只使用 静态数据的场景,比如应用的配置信息、web server 的静态文件等
四、管理volume的生命周期
如何备份、恢复、迁移和销毁 volume
1、备份
volume 是 host 文件系统中的目录和文件
volume 的备份实际上是对文件系统的备份
搭建本地 Registry:
docker run -d -p 5000:5000 -v /myregistry:/var/lib/registry registry:2
所有的本地镜像都存在 host 的 /myregistry 目录中,我们要做的就是定期备份这个目录。
ll /myregistry
2、恢复
volume 的恢复简单,若数据损坏,直接用备份的数据拷贝到 /myregistry 即可
3、迁移
若想新 Registry 版本,需要数据迁移
A、docker stop 当前 Registry 容器
B、启动新版本容器并 mount 原有 volume
docker run -d -p 5000:5000 -v /myregistry:/var/lib/registry registry:latest
C、在启用新容器前要确保新版本的默认数据路径是否发生变化
4、销毁
删除不再需要的 volume,volume 删除后数据找不回来
A、bind mount
docker 不会销毁 bind mount,删除数据的工作只能由 host 负责
B、docker managed volume
前提条件:没有其他容器 mount 该 volume,目的是保护数据
在执行 docker rm 删除容器时可带上 -v 参数,docker 会将容器使用到的 volume 一并删除
遗留问题:
删除容器时没有带 -v ,会产生孤儿 volume
docker 提供了 volume 子命令可以对 docker managed volume 进行维护
docker volume ls
docker run --name bubox -v /test/data busybox
查看docker managed volume:
docker volume ls
删除容器:
docker rm bubox
docker volume ls
删除孤儿 volume:
docker volume rm c793ada1bf22b0bee6000f435994e49af3ecfd73a93b52f0b24091e851fb5650
docker volume ls
批量删除孤儿volume:
docker volume rm$(docker volume ls -q)
五、总结概述
1、Docker 为容器提供了两种存储资源: 数据层和 Data Volume
2、数据层包括: 镜像层和容器层,由 storage driver 管理
3、Data Volume 分2种类型: bind mount 和 docker managed volume
4、bind mount 作用: 容器与 host 之间,容器与容器之间共享数据
5、volume container 是具有更好移植性的容器间数据共享方案,特别是 data-packed volume container
6、Data Volume的管理: 备份、恢复、迁移和销毁
详情请见,微信公众号