Docker 容器对于宿主机来说只是一个运行在linux上的应用, 因此它的数据存储还是会依赖宿主机器 ,Docker是通过挂载宿主机文件系统或内存的方式来实现数据存储的,挂载方式有三种,volume ,bind mount 和tmpfs
-
volumes-在宿主机的文件系统上的docker工作路径下创建一个文件夹(/var/lib/docker/volumes)来存储数据, 其他非docker进程是不能修改该路径下的文件,完全由docker来管理
-
bind mounts -可以存储在宿主机器任何一个地方, 但是会依赖宿主机的目录结构, 不能通过docker CLI 去直接管理 , 并且非docker进程和docker进程都可以修改该路径下的文件
-
tmpfs-无论是在docker主机上还是在容器内, tmpfs 挂载都不会持久保存在磁盘上, 它会将信息存储在宿主机内存里 。容器在其生存期内可以使用它来存储非持久化状态或敏感信息。 例如,在内部,swarm services使用tmpfs挂载将机密挂载到服务的容器中或者我们一些不需要持久化数据的开发测试环境, 可以使用tmpfs
1.1 volume初体验
Volumes是Docker推荐的挂载方式, 与把数据存储在容器的可写层相比, 使用volume可以避免增加容器的容量大小, 还可以使存储的数据与容器的的生命周期独立。
-
与bind mounts相比,volumes更易于备份或迁移
-
您可以使用docker CLI命令或docker api管理volumes
-
volumes在linux和windows容器上均可工作
-
可以在多个容器之间更安全地共享volumes
-
volumes驱动程序使您可以将volumes存储在远程主机或云提供程序上, 以加密volumes内容或添加其他功能。
volumes实战
通过默认-v方式
默认情况下, docker会帮我们创建一个随机命名的volume
-
创建一个容器, 命名为mysql01
docker run -d --name mysql01 -e MYSQL_ROOT_PASSWORD=even123 mysql
-
我们可以看看容器到底有没有自动帮我们创建一个volumes
docker volume ls
通过上面的输出结果可以看到, docker默认帮我创建了一个volume ,并且随机起了一个看不懂的名字
-
通过docker inspact 查看volume详细信息
docker inspec 容器名称或ID
从上面volume详情可以了解到, 现在容器的数据是挂在在宿主机上/var/lib/docker/目录下, scope是本地
-
通过-v 指定容器volume的名字, 使用我们自定义的一个可读的名字
docker run -d --name mysql02 -v evan_volume:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=even123 mysql
-
再次查看下volume是否创建成功
# docker volume ls local evan_volume local f1dd03fc5a8ea8263d880105a07f24dfb076a7b31a9c1f590ed00109adca5990
刚才创建的volume已经成功了
-
再查看下volume的详细信息
# docker inspect evan_volume [ { "CreatedAt": "2022-03-24T13:49:33+08:00", "Driver": "local", "Labels": null, "Mountpoint": "/var/lib/docker/volumes/evan_volume/_data", "Name": "evan_volume", "Options": null, "Scope": "local" } ]
从上面信息可以看到, 容器已经成功挂载宿主机上的evan_volume
通过--mount方式
-v 能做的 --mount 指令都可以做 , 与-v 指令对比 , --mount 指令更灵活, 支持更多复杂操作, 并且不需要严格按照参数顺序, 通过key value 键值对方式进行配置 , 可读性更高
--mount 有一下几个参数
-
type - type 可以是bind ,volume 或者tmpfs ,默认是volume
-
source - 宿主机上的目录路径, 可以用缩写src
-
destination - 目标路径, 容器上挂载的路径, 可以用dst或者target
-
readonly - 可选项, 如果设置了 , 那么容器挂载的路径会被设置为只读
-
volume-opt - 可选项, 当volume驱动接收通过多个参数作为选项时 , 可以以多个键值对的方式传入
-
创建一个容器, 命名mysql-mount ,指定volume名为mysql-mount
docker run --name mysql-mount -e MYSQL_ROOT_PASSWORD=evan123 --mount type=volume,source=mysql-volume,target=/var/lib/mysql mysql
-
查看volume是否创建成功
#docker volume ls local mysql-mount local mysql-volume local server
-
查看宿主机是否存在对应目录
#docker inspect mysql-volume
从输出结果可以看到 , 通过--mount 可以实现跟-v同样的操作结果, 数据也绑定到了宿主机对应的路径目录上
1.2 bind mounts初体验
与volume相比, bind mount 的功能有限 。使用绑定安装时 , 会将主机上的文件或目录安装到容器中。 文件或目录有主机上的完整或相对路径引用。 相比之下, 当您使用volume时 , 将在主机上docker的存储目录中创建一个新目录, 并且docker管理该目录的内容。
该文件或目录不需要在docker主机上已经存在。 如果尚不存在, 则按需创建。 bind mount 性能非常好 , 但是它依赖于具有特定目录结构的主机文件系统。 如果要开发新的docker应用程序, 请考虑使用命名volume 。 您不能使用DOCKER CLI 命令直接管理bind mounts
-
创建一个tomcat容器, 命名为tomcat-bind , 挂载宿主机路径为/tmp
docker run -d --name tomcat-mount --mount type=bind,source=/tmp,target=/user/local tomcat
-
通过docker inspect tomcat-mount 查看容器信息
"Mounts": [ { "Type": "bind", "Source": "/tmp", "Destination": "/user/local", "Mode": "", "RW": true, "Propagation": "rprivate" } ],
可以看到容器已经成功挂载到宿主机上的/tmp 目录 , 而不是前面我们演示的docker管理路径下
docker命令行挂载NFS如下:
docker volume create --driver local --opt type=nfs --opt o=addr=192.168.31.201,rw --opt device=:/nfs/data --name volume-nfs
--opt type=nfs 指定type为nfs模式
--opt o=addr=192.168.11.129,rw 指定远端NFS的地址,以及读写权限
--opt deveice=:/nfsdir 指定远端NFS的路径
代码实现
Map<String,String> map = new HashMap<>(); map.put("type",nfs); map.put("o","addr=192.168.11.129,rw"); map.put("device",":/nfsdir"); Volume volume = Volume.buidler() .name("test") .driverOpts(map) .build();
docker命令行使用cephfs
-
在docker容器中,安装ceph。
-
docker run --privileged=true 方式运行容器
-
使用ceph-fuse在用户态挂载cephfs到ceph集群的Monitor即可。
即,将ceph客户端容器作为数据卷容器来使用。
docker run --privileged=true -it -v /home/ceph/cephfs ubuntu:ceph /usr/bin/ceph-fuse -k /home/ceph/ceph.client.admin.keyring -m 10.32.170.104:6789 /home/ceph/cephfs
1.3 tmpfs初体验
使用tmpfs 不会持久化数据, 数据只会存放在宿主机内存中
-
创建一个tomcat容器, 命名为tomcat-tmps , 指定挂载方式为tmps
docker run -d --name tomcat-tmpfs --mount type=tmpfs,target=/tmp tomcat
-
我们通过docker container inspect tomcat-tmpfs 查看下是否创建任务目录在宿主机
"Mounts": [ { "Type": "tmpfs", "Source": "", "Destination": "/tmp", "Mode": "", "RW": true, "Propagation": "" } ],