Docker 为容器提供了两种存放数据的资源:
- 由 Storage driver 管理的镜像层和容器层
- Data Volume
Storage driver
容器由最上面一个可写的容器层,以及若干只读的镜像层组成,容器的数据就存放在这些层中。这样的分层结构最大的特性是 Copy-on-Write:
- 新数据会直接存放在最上面的容器层。
- 修改现有数据会先从镜像层将数据复制到容器层,修改后的数据直接保存在容器层中,镜像层保持不变。
- 如果多个层中有命名相同的文件,用户只能看到最上面那层中的文件。
分层结构使镜像和容器的创建、共享以及分发变得非常高效,而这些都要归功于 Docker storage driver。正是 storage driver 实现了多层数据的堆叠并为用户提供一个单一的合并之后的统一视图。
Docker 支持多种 storage driver,有 AUFS、Device Mapper、Btrfs、OverlayFS、VFS 和 ZFS。它们都能实现分层的架构,同时又有各自的特性。
对于那些无状态的应用,直接将数据放在由 storage driver 维护的层中是很好的选择,无状态意味着容器没有需要持久化的数据,随时可以从镜像直接创建。
Data Volume
Data Volume 本质上是宿主机文件系统中的目录或文件,能够直接被 mount 到容器的文件系统中,Data Volume 数据可以被永久的保存,即使使用它的容器已经销毁。
Data Volume有两种类型:bind mount 和 docker managed volume
bind mount
bind mount是直接将宿主机上已存在的目录或者文件直接挂到容器中,容器路径不存在会自动创建,已存在的会被隐藏起来
-v [local path]:[container path]:[ro]
[[email protected]_Machine_192.168.31.130 ~]# docker run -itd --name mybusybox -v /data/web/:/mydata/web busybox
08ce3e68d61061356993426237da2474c518aaab2b45d48271c73610217aef28
[[email protected]_Machine_192.168.31.130 ~]# docker exec -ti mybusybox sh
/ # ls -l /mydata/web/
total 0
/ #
-v 参数最后可以指定权限,默认是可读可写,ro表示只读
上面的栗子中宿主机/data/web/这个路径和容器mybusybox是共享的,不论在容器内部操作挂载点下的文件还是在宿主操作这个路径下的文件,结果都是一样的
还可以把宿主机的同一个路径挂到多个容器中,实现文件的共享
另外一种命令方式,相对麻烦些:
docker run -itd --name mybusybox --mount type=bind,source=/data/web/,target=/mydata/web,readonly busybox
用inspect 查看一下容器挂载的信息:
[[email protected]_Machine_192.168.31.130 ~]# docker inspect -f '{{.Mounts}}' mybusybox
[{bind /data/web /mydata/web false rprivate}]
#非readonly:
[[email protected]_Machine_192.168.31.130 ~]# docker inspect -f '{{.Mounts}}' mybusybox
[{bind /data/web /mydata/web true rprivate}]
docker managed volume
和bind volume最大的区别是,docker managed volume不需要指定本地路径,而是被固定指到$DOCKER_PATH/volumes/下
具体命令:
[[email protected]_Machine_192.168.31.130 ~]# docker run -tid --name=mybusybox1 -v /data/web busybox
bba8213c2e545231d5fbddd2d265d46f9740e9f6e1339747d9a7a038cd36db88
#或者:
[[email protected]_Machine_192.168.31.130 ~]# docker run -itd --name mybusybox2 --mount type=volume,target=/mydata/web busybox
#查看一下信息:
[[email protected]_Machine_192.168.31.130 ~]# docker inspect -f '{{.Mounts}}' mybusybox1
[{volume 2bd769dd0a7152f09fed996944c6a4990d60f5077a1e51f7118bf4e6e4584895 /data/dokcer/docker_data/volumes/2bd769dd0a7152f09fed996944c6a4990d60f5077a1e51f7118bf4e6e4584895/_data /data/web local true }]
可以看到,docker managed volume所配置的本地目录位置是在**/data/dokcer/docker_data/volumes/$volumes_id/_data/**,进入这个目录对该目录下的文件执行操作,和进入容器的/data/web目录是一样的
可以用docker volume命令查看:
[[email protected]_Machine_192.168.31.130 ~]# docker volume ls
DRIVER VOLUME NAME
local 2bd769dd0a7152f09fed996944c6a4990d60f5077a1e51f7118bf4e6e4584895
和bind volume的一些区别:
- 无法指定权限,只能可读可写
- 容器目录已存在的数据,会被复制到volume中,不是被隐藏
- 宿主机位置不可任意指定,都在/data/dokcer/docker_data/volumes/下
数据共享
volume container
在bind volume的情况下,我们可以将一个宿主机目录挂到多个容器中,实现数据共享,在docker managed volume的情况下呢?
可以使用 volume container,既创建一个专门为其他容器提供 volume 的容器实例,而这个实例的volume可以是bind volume
我们先创建一个volume container:
[[email protected]_Machine_192.168.31.130 ~]# docker create --name=my_volume_container -v /data/web/:/mydata/web busybox
bd25e807dd9e0518ae2d6a525bcb56fc10944f9a7195b72c3d4f7b799376531e
[[email protected]_Machine_192.168.31.130 ~]# docker inspect -f '{{.Mounts}}' my_volume_container
[{bind /data/web /mydata/web true rprivate}]
其他容器可以通过 --volumes-from 使用my_volume_container的volume:
[[email protected]_Machine_192.168.31.130 ~]# docker run -tid --volumes-from my_volume_container --name mybusybox1 busybox
a15f4e66c4cc8c9a09e572d5328edd808c34e8ea377688a1fe2671736b5b3d6b
[[email protected]_Machine_192.168.31.130 ~]# docker run -tid --volumes-from my_volume_container --name mybusybox2 busybox
aabc8bca934734b68dcacc0986463cb39c192aad958a5a6325a9d3767f502113
[[email protected]_Machine_192.168.31.130 ~]# docker run -tid --volumes-from my_volume_container --name mybusybox3 busybox
ab8158b9c8d3bfaa42da4346cf83d51ecbb7470ed32919fb94f85c2beff68293
看看其中一个容器的volume信息:
[[email protected]_Machine_192.168.31.130 ~]# docker inspect -f '{{.Mounts}}' mybusybox2
[{bind /data/web /mydata/web true rprivate}]
mybusybox1 mybusybox2 mybusybox3 这三个容器的volume就和volume container一致了
volume container 的特点:
- 与 bind mount 相比,不必为每一个容器指定 host path,所有 path 都在 volume container 中定义好了,容器只需与 volume container 关联,实现了容器与 host 的解耦。
- 使用 volume container 的容器其 mount point 是一致的,有利于配置的规范和标准化,但也带来一定的局限,使用时需要综合考虑。
docker cp
docker managed volume的源点目录一开始是不存在的,在Docker启动后,执行创建容器时才生成,这样一些数据只能等到目录创建后才能复制进去
docker cp可以在容器和 host 之间拷贝数据
[[email protected]_Machine_192.168.31.130 ~]# docker cp /data/web/index.html mybusybox1:/data/web/
[[email protected]_Machine_192.168.31.130 ~]# ll /data/dokcer/docker_data/volumes/94b92f2c5074343f8f3244ad9cb65e67bb5306f621df871224a9debbf443fada/_data/
total 4
-rw-r--r-- 1 root root 12 Aug 31 16:49 index.html
volume的生命周期
volume是本地文件或目录,在容器关闭销毁时不会被销毁
如果要删除容器时,同时删除该容器的volume,可以用命令:docker rm -v [id|name]
volume的基本管理命令
- docker volume ls:列出所有的volume
- docker volume rm:删除volume,无法删除正在使用的
- docker volume create :创建docker managed volume
- docker volume inspect:查看详细信息
- docker volume prune :清空所有不在使用的volume
简单创建一个volume:
[[email protected]_Machine_192.168.31.130 ~]# docker volume create -d local --name myvolume
myvolume
[[email protected]_Machine_192.168.31.130 ~]# docker volume inspect myvolume
[{
"CreatedAt": "2018-08-31T17:08:10+08:00",
"Driver": "local",
"Labels": {},
"Mountpoint": "/data/dokcer/docker_data/volumes/myvolume/_data",
"Name": "myvolume",
"Options": {},
"Scope": "local"
}]
使用:
[[email protected]_Machine_192.168.31.130 ~]# docker run -tid --name=mybusybox1 -v myvolume1:/data/web busybox
9cb821232d042dba071f777067361e427daaebf4250c36906b36d65587fac662
[[email protected]_Machine_192.168.31.130 ~]# docker run -tid --name=mybusybox2 --mount type=volume,source=myvolume1,target=/mydata/web busybox
a4b134dff9a3072ff06ffaaeabead7e2f6c740946be815f10f18d0a861c4a513