Docker 容器数据卷
先来看看Docker的理念:
将应用与运行的环境打包形成容器运行,运行可以伴随着容器,但是我们对数据的要求希望是持久化的;
容器之间希望可以共享数据;
Dokcer容器产生的数据,如果不通过docker commit 生成新的镜像,使得数据作为镜像的一部分保存下来,那么当容器删除后,数据自然也就没有了;
为了能保存数据在docker中我们使用卷;
是什么?
一句话:有点类似我们Redis里面的rdb和aof文件
卷(Valume)就是目录或文件,存在于一个或多个容器中,由docker挂载到容器,但不属于联合文件系统,因此能够绕过Union File System提供一些用于持续存储或共享数据的特性;
卷的设计目的就是数据的持久化,完全独立于容器的生存周期,因此Docker不会在容器删除时删除其挂载的数据卷;
特点:
1.数据卷可以在容器之间共享或重用数据;
2.卷中的更改可以直接生效;
3.数据卷中的更改不会包含在镜像的更新中;
4.数据卷的生命周期一致持续到没有容器使用它为止;
能干嘛?
1.容器数据的持久化;
2.容器间继承 + 数据共享;
数据卷:
容器内添加
1.直接命令添加
命令:docker run -it -v /宿主机绝对路径目录:/容器内目录 镜像名
示例:docker run -it -v /myDataVolume:/dataVolumeContainer 镜像名
案例:sudo docker run -it -v /myDataVolume:/dataVolumeContainer ubuntu (意思是让宿主机上的/myDataVolume 和 容器ubuntu 上的/dataVolumeContainer 实现互通)
查看数据卷是否挂载成功(是否绑定成功)可以通过命令:docker inspect 镜像名
示例:sudo docker inspect f45b3fb4c215
图例:
容器和宿主机之间数据共享:
在主机上的/myDataVolume 目录下新建一个host.txt文件
在容器上进入/dataVolumeContainer 目录同样也可以看到 host.txt文件,并且 echo container update 01 > host.txt
然后cat host.txt 会有刚刚追加进去的内容,而我们回到宿主机上cat host.txt同样也可以看到
容器停止退出后,主机修改后数据是否同步:
首先我们把刚刚启动的ubuntu的容器 exit 退出,即关闭退出(即关灯锁门,而不是不关灯锁门)
然后依次输入:sudo docker ps (查看目前正在运行的容器) ---> sudo docker ps -l (查看最近刚刚创建的容器)
接着我们在宿主机的/myDataVolume 目录下的 host.txt文件中 添加 host update 01 , 也可以新建一个 host01.txt 文件
看到其状态为Exited, 然后通过 sudo docker start 镜像ID,继续进入到 /dataVolumeContainer 目录中看是否有刚刚在宿主机上做的修改;
内容会同步!
图例:
命令(带权限):即不希望被写,别人只能读!写保护!
命令:docker run -it -v /宿主机绝对路径目录:/容器内目录 :ro 镜像名 --->(ro - readonly)
示例:sudo docker run -it -v /myDataVolume:/dataVolumeContainer:ro ubuntu
我们可以在宿主机上 sudo rm -rf myDataVolume 删掉这个目录,然后在ubuntu上查看时,已经显示total 0
接着 在ubuntu上 exit 退出
在使用命令: sudo docker run -it -v /myDataVolume:/dataVolumeContainer:ro ubuntu
我们在容器上操作图例:都是只读
也可以通过 命令:sudo docker inspect 40d1afa4f937
图例显示:
2.DockerFile添加:
是什么?
Docker images ====> DockerFile 类似我们Linux下的shell脚本,它是docker下的shell脚本文件
根目录下新建mydocker文件夹并进入:
先退出所有的容器
接着 cd / ; mkdir mydocker ; pwd
可在Dockerfile中使用VOLUME指令来给镜像添加一个或多个数据卷:
VOLUME["/dataVolumeContainer","/dataVolumeContainer2","/dataVolumeContainer3"]
说明:
出于可移植和分享的考虑,用 -v 主机目录:容器目录 这种方法不能够直接在Dockerfile中实现;
由于宿主机目录是依赖于特定宿主机的,并不能够保证在所有的宿主机上都存在这样的特定目录;
File构建:
在宿主机上的/mydocker目录下:vim Dockerfile
输入以下内容:
# volume test
FROM ubuntu
VOLUME ["/dataVolumeContainer1","/dataVolumeContainer2"]
CMD echo "finished,------------success1"
CMD /bin/bash
以上命令大致可以解释为类似以下命令:
docker run -it -v /host1:/dataVolumeContainer1 -v /host2:/dataVulumeContainer2 ubuntu /bin/bash
build后生成镜像:
获得一个新镜像gs/ubuntu
命令:docker build -f /mydocker/Dockerfile -t gs/ubuntu .
示例:sudo docker build -f /mydocker/Dockerfile -t gs/ubuntu .
图例:
run容器:
此时我们可以用我们新建的镜像启动
命令:sudo docker run -it gs/ubuntu
图例:
通过上述步骤,容器内的卷目录地址已经知道对应的主机目录地址在哪?
在宿主机上查看一下当前正在运行的容器:sudo docker ps
因为我们通过dockerfile 来添加数据卷,是没有指定宿主机的目录,docker会默认指定,所以需要通过 inpect命令来查看
sudo docker inspect e7d71a71b788
图例:
可以找到宿主机上对应的目录:ubuntu上是Mounts
图例:
图例二:
图例三:
图例四,在容器上可以查看结果:
主机对应默认地址:
图例:
数据卷容器:
是什么?
命名的容器挂载数据卷,其他容器通过挂载这个(父容器)实现数据共享,挂载数据卷的容器,称之为数据卷容器;
总体介绍:
举例说明:就是班长的硬盘在我的电脑上(是我们上面实现的宿主机于容器间的互通),而我们接下来的要实现的是(班长的硬盘上有其他一组,二组,三组的等等的硬盘,实现数据传递)
以上一步新建的镜像gs/ubuntu 为模板并运行容器dc01/dc02/dc03:
它们已经具有容器卷:
/dataVolumeContainer1
/dataVolumeContainer2
容器间传递共享(--volumes-from):
先启动一个父容器dc01:
把所有容器先都退出,即没有正在运行的容器
开始执行命令:
图例:
在dataVolumeContainer2新增内容:
图例:
接着 ctrl + p + q 退出
图例:
dc02/dc03继承自dc01:
--volumes-from
命令:sudo docker run -it --name dc02 --volumes-from dc01 gs/ubuntu
sudo docker run -it --name dc03 --volumes-from dc01 gs/ubuntu
图例:
dc02/dc03分别在dataVolumeContainer2各自新增内容
图例:
回到dc01可以看到02/03各自添加的都共享了(子继承父,父也能看到子):
删除dc01,dc02修改后dc03可否访问:
是没有问题的!
图例:
删除dc02后,dc03可否访问:
也是ok的!
新建dc04继承自dc03后再删除dc03:
当然没问题喽!
图例一:
图例二:
结论:
容器之间配置信息的传递,数据卷的生命周期一致持续到没有容器使用它为止;