零基础学习 Docker(五)| 关于存储
0. 系列导读
本系列共六篇:
- 零基础学习 Docker(一)| 安装与运行
- 零基础学习 Docker(二)| 基本命令的使用
- 零基础学习 Docker(三)| 关于镜像
- 零基础学习 Docker(四)| 关于网络通信
- 零基础学习 Docker(五)| 关于存储
- 零基础学习 Docker(六)| 关于多主机管理
1. 两种存储方式
根据数据的持久性,可以分为两类
1. 非持久化:Storage Driver
存储在镜像层或者容器层
2. 持久化:Data Volume
在 host 上会保留着一份数据。容器再挂载这个文件或者目录。
Storage Driver
Docker支持很多Driver,有 AUFS、Device Mapper、Btrfs、OverlayFS、VFS 和 ZFS。
Docker 建议使用Docker 默认的Driver,这几个什么区别,还需要了解下。
1. ReHat/CentOS 系列,网上说默认使用 Device Mapper,但是我的为什么是OverlayFS,通过 docker info 查看
2. Ubuntu ,默认使用 AUFS
(前面在镜像那章已经讨论过)
分层结构使镜像和容器的创建、共享以及分发变得非常高效,而这些都要归功于 Docker Storage Driver。正是 Storage Driver 实现了多层数据的堆叠并为用户提供一个单一的合并之后的统一视图。
- 新数据会直接存放在最上面的容器层。
- 修改现有数据会先从镜像层将数据复制到容器层,修改后的数据直接保存在容器层中,镜像层保持不变。
- 如果多个层中有命名相同的文件,用户只能看到最上面那层中的文件。
适用场景
适用那些无状态的容器,也就是工具类的容器,无需持久化数据。
Data Volume
Data Volume 也分两种
1. bind mount
创建时,需要指定挂载源。
在创建的时候指定,创建后无法更改。
2. docker managed volume
创建时,无需指定挂载源,会指定随机命令的文件名作为路径。
2. 两种Data Volume
bind mount
# 创建时需要指定挂载源和挂载点
# 如果没挂载源这个路径,会自己创建
# 默认是可读可写,还可以指定只读:-v ~/htdocs:/usr/local/apache2/htdocs:ro
docker run -d -p 80:80 -v ~/htdocs:/usr/local/apache2/htdocs httpd echo "update new page" >~/htdocs/index.html
$ curl 127.0.0.1:80/index.html
update new page
# 删除容器的时候,并不会删除这些文件。
# 在容器创建的时候,挂载的路径就已经固定,这限制了容器移植的灵活性
docker managed volume
# 无需自己指定挂载源,会自动生成。
docker run -d -p 8080:80 -v /usr/local/apache2/htdocs httpd
# 查看mount的源路径,比如我的是/var/lib/docker/volumes/1ab45061435b8ecba1c1d70b877831d003a590797f086442052f467198656be0/_data
# 1ab45061435b8ecba1c1d70b877831d003a590797f086442052f467198656be0 是container id,是docker随机生成的。
# 在这个路径下,你就可以放你要放的文件,容器里都可以访问到。
# 容器里/usr/local/apache2/htdocs 原有文件会被拷贝到volumns docker inspect <container id>
curl 127.0.0.1:8080
<html><body><h1>It works!</h1></body></html>
# 查看 volume 列表,使用bind mount 是没有的 docker volume ls
DRIVER VOLUME NAME
local 1ab45061435b8ecba1c1d70b877831d003a590797f086442052f467198656be0
# 查询该volume具体信息
$ docker volume inspect 1ab45061435b8ecba1c1d70b877831d003a590797f086442052f467198656be0
[
{
"CreatedAt": "2017-12-29T18:00:15-05:00",
"Driver": "local",
"Labels": null,
"Mountpoint": "/var/lib/docker/volumes/1ab45061435b8ecba1c1d70b877831d003a590797f086442052f467198656be0/_data",
"Name": "1ab45061435b8ecba1c1d70b877831d003a590797f086442052f467198656be0",
"Options": {},
"Scope": "local"
}
]
二者对比
相关命令
$ docker inspect <contain id>
$ docker volume ls
$ docker volume inspect <contain id>
3. 实现数据的共享
根据共享的位置,可以分为两种
1. host
2. date-packed volume
host
虽然 docker managed volume
可移植性好,但是在实现多个容器数据共享,就要稍微麻烦点。
由于 docker managed volume
的volume路径是随机生成的,所以,要实现共享,必须在创建后再把我们的数据拷贝至该文件夹里。
而 bind mount
就相当方便了,只要多个容器在创建的时候使用同一挂载源就可以了,更方便的还可以使用 volume container
1. 多个容器使用同一挂载源
docker run -d -p 1001:80 -v ~/htdocs:/usr/local/apache2/htdocs httpd docker run -d -p 1002:80 -v ~/htdocs:/usr/local/apache2/htdocs httpd
docker run -d -p 1003:80 -v ~/htdocs:/usr/local/apache2/htdocs httpd
echo "new page" >~/htdocs/index.html curl 127.0.0.1:1001
curl 127.0.0.1:1002 curl 127.0.0.1:1003
2. 使用volume container
# 先创建一个容器,当做模板,无需run
docker create --name vc_date\
-v ~/htdocs:/usr/local/apache2/htdocs\
-v /other/useful/tools \
busybox docker run --name web1 --volumes-form vc_date httpd
docker run --name web2 --volumes-form vc_date httpd docker run --name web3 --volumes-form vc_date httpd
date-packed volume
其原理是将数据打包到镜像中,然后通过 docker managed volume 共享。
既然是放到镜像里,那我们就要重新制作一个镜像。Dockerfile如下
FROM busybox:latest
ADD htdocs /usr/local/apache2/htdocs
VOLUME /usr/local/apache2/htdocs
然后和上面一样,要先制作一个镜像模板。
$ docker build -t datepacked .
$ docker create --name vc_date datepacked
然后以这个为模板,创建容器
$ docker run --name web1 --volumes-form vc_date httpd
$ docker run --name web2 --volumes-form vc_date httpd
$ docker run --name web3 --volumes-form vc_date httpd
4. 管理volume生命周期
1. 创建
docker run -d -p 80:80 -v /container/dir --name <name> <image> docker run -d -p 80:80 -v /host/dir:/container/dir --name <name> <image>
2. 共享
具体步骤看上面
3. 删除
bind mount 是不会删除挂载源的。除非host自己删除
docker managed volume 默认不删除volume,除非删除的时候指定 -v
docker stop <container id> docker rm -v <container id>
4. 备份
只需要备份volume路径下的文件即可
5. 恢复
只需将备份的数据拷贝到volume即可
6. 迁移
如果我们想使用更新版本的 Registry,这就涉及到数据迁移。
方法是:
docker stop 当前 Registry 容器。
启动新版本容器并 mount 原有 volume。
$ docker run -d -p 5000:5000 -v /myregistry:/var/lib/registry registry:latest