文章目录
docker 数据卷管理
为什么用数据卷?
因为docker本身的文件系统性能差,每次关闭容器后,操作的文件也会全部删除,而docker数据卷是 mount 到宿主机中,绕开了分层文件系统,和主机磁盘性能相同,容器删除后依然保留,但是仅限本地磁盘,不能随容器迁移
docker 官方提供两种卷:1.bind mount 2.docker managed volume
bind mount 绑定挂载
开启容器,容器里/usr/share/nginx/html 是 nginx的默认发布目录,将容器的默认发布目录挂载到宿主机的/opt/webdata下
[root@server1 ~]# docker run -d --name web1 -p 80:80 -v /opt/webdata:/usr/share/nginx/html nginx
这时候访问localhost会报错,因为挂载的/opt/webdata里面是空的,
可以直接在挂载目录里建立index.html 写入一个内容可以访问到
[root@server1 ~]# echo www.redhat.com > /opt/webdata/index.html
[root@server1 ~]# curl localhost
www.redhat.com
在容器里也可以进行修改内容,因为nginx 容器没有交互式的界面所以打开它需要执行
[root@server1 ~]# docker exec -it web1 bash
root@e7b12a47d559:/# cd /usr/share/nginx/html/
root@e7b12a47d559:/usr/share/nginx/html# echo www.redhat.com >> index.html
[root@server1 ~]# curl localhost
www.redhat.com
www.redhat.com
这种方式进行的挂载,不存在的目录会自动新建(无论容器还是宿主机),但是会以宿主机为准,绑定挂接到容器后,容器中的对应目录如果有数据,就会被覆盖。
同时挂载也可以指定挂载类型,默认是rw读写,可以指定为ro只读
[root@server1 ~]# docker run -it --name vm1 -v /opt/data:/mnt/:ro busybox #运行容器指定挂载为只读
/ # cd /mnt
/mnt # touch file1 #无法建立文件
touch: file1: Read-only file system
[root@server1 ~]# cd /opt/data/ #在宿主机里就可以去建立文件
[root@server1 data]# touch file1
还可以挂载 yum 源
将宿主机yum源挂载到容器里,rhel7没有界面所以加bash
[root@server1 data]# docker run -it --name vm2 -v /etc/yum.repos.d/test.repo:/etc/yum.repos.d/test.repo rhel7 bash
bash-4.2# yum repolist
Skipping unreadable repository '///etc/yum.repos.d/rhel7.repo'
repo id repo name status
rhel7.6 rhel7.6 5152
repolist: 5152
可以加上ro只读让yum源不可被更改
docker managed volume
bind mount 必须指定宿主机文件系统路径,移植性差,如果需要从a主机移植到b主机,但是b主机上没有这个路径,就无法移植
而 docker managed volume 不需要指定,docker 自动为容器创建,默认数据卷目录都在/var/lib/docker/volumes
[root@server1 _data]# docker run -d --name web1 -p 80:80 -v /usr/share/nginx/html nginx
#切换到数据储存的目录
[root@server1 _data]# cd /var/lib/docker/volumes/fb37c38b6bcc77445714d4d306545a654a14363e16856044388b175914d13108/_data
#重写入默认页的内容
[root@server1 _data]# echo www.redhat.com > index.html
[root@server1 _data]# curl localhost
www.redhat.com
并且还可以自定义指定数据目录的名称,因为系统生成的目录太常了也不好区分
[root@server1 _data]# docker run -d --name web2 -p 8080:80 -v website:/usr/share/nginx/html nginx #指定数据存放目录是website
[root@server1 _data]# docker inspect web2 #查看容器信息
"Source": "/var/lib/docker/volumes/website/_data", #数据路径还是/var/lib/docker/volumes/里
[root@server1 _data]# docker rm -f web2
[root@server1 _data]# ls /var/lib/docker/volumes/ #删除容器后数据还是存在的
website
想要删除数据目录里没有用的数据卷可以使用命令:docker volume prune
另一种用法
当运行一个容器web1用managed volume方式,,指定数据卷的名称为website,对默认发布页面进行改写,然后删除web1,再运行web2依然使用website数据卷,访问可以看到同样的内容
[root@server1 ~]# docker run -d --name web1 -p 80:80 -v website:/usr/share/nginx/html nginx
[root@server1 ~]# ehco www.redhat.com > /var/lib/docker/volumes/website/_data/index.html
[root@server1 ~]# docker rm -f web1
[root@server1 ~]# docker run -d --name web2 -p 80:80 -v website:/usr/share/nginx/html nginx
[root@server1 ~]# curl localhost
www.redhat.com
运行web3并且不指定端口映射,数据卷还是使用website
[root@server1 ~]# docker run -d --name web3 -v website:/usr/share/nginx/html nginx
[root@server1 ~]# docker inspect web3
"IPAddress": "172.17.0.3", #查看到web3的ip
[root@server1 ~]# curl 172.17.0.3 #访问web3,依然可以看到更改的页面
www.redhat.com
使用这种方式让多个容器挂载同一个目录,并且我们的数据卷是不会在容器被删除时被删除,如果需要恢复容器,运行时还是使用这个数据卷就可以了
卷插件
docker 卷默认使用的是 local 类型的驱动,只能存在于宿主机,跨主机的 volume 就需要第三方驱动
在官方网站里,提供了官方的插件API,开发者可以根据实际需求定制插件驱动
https://docs.docker.com/engine/extend/legacy_plugins/
卷插件的工作流程是docker engine(daemon) --> volume plugin --> storage platform,docker引擎调用卷插件,在由插件管理存储平台;
docker plugin 是以 web 服务的方式在 docker 主机上独立运行的,plugin 的启动和停止并不依赖于 docker,docker daemon 依靠在默认路径下查找 unixsocket 文件来自动发现插件。
当客户端与 daemon 交互并使用插件创将数据卷时,daemon 会在后端找到插件对应的socket 文件,建立连接并发起相应的 API 请求,最终结合 daemon 自身的处理完成客户端请求。
convoy卷插件操作
底层存储支持三种模式:devicemapper、NFS、EBS,需要在所有 docker 节点提前挂载 NFS 存储。
因为是操作共享存储所以需要两台主机来进行操作,server1和server2
配置nfs
在两台主机上安装docker服务和nfs-utils
[root@server2 ~]# yum insatll -y *.rpm
containerd.io-1.2.5-3.1.el7.x86_64.rpm
container-selinux-2.21-1.el7.noarch.rpm
docker-ce-18.09.6-3.el7.x86_64.rpm
docker-ce-cli-18.09.6-3.el7.x86_64.rpm
[root@server2 ~]# yum install -y nfs-utils
[root@server2 ~]# systemctl start rpcbind
在server1里编辑文件,指定共享目录的挂载路径
[root@server1 ~]# cat /etc/exports
/mnt/nfs *(rw,no_root_squash) #加参数保证root在操作时不切换身份,默认会切换到nfs用户
在server1里创建指定的目录/mnt/nfs
[root@server1 ~]# mkdir /mnt/nfs
[root@server1 ~]# systemctl start nfs #启动nfs
[root@server1 ~]# exportfs -rv #导出共享目录
exporting *:/mnt/nfs
在server2上同样进行操作
[root@server2 ~]# mkdir /mnt/nfs #创建挂载目录
[root@server2 ~]# showmount -e 172.25.254.1 #可以查看到server1里的共享
Export list for 172.25.254.1:
/mnt/nfs *
然后测试把serve1上的/mnt/nfs,挂载到server2的/mnt/nfs
[root@server2 ~]# mount server1:/mnt/nfs /mnt/nfs
[root@server2 ~]# df #查看挂载
server1:/mnt/nfs 8910848 2608384 6302464 30% /mnt/nfs
挂载成功后,测试在server1里建立文件
[root@server1 ~]# touch /mnt/nfs/testfile1 #server1创建文件
[root@server2 ~]# ls -l /mnt/nfs/testfile1 #server2上同步可以看到
-rw-r--r--. 1 root root 0 Jun 3 11:23 /mnt/nfs/testfile1
这样就保证里nfs配置是成功的
安装配置convoy
在命令行里直接下载源码包
wget https://github.com/rancher/convoy/releases/download/v0.5.2/convoy.tar.gz
解压convoy包,并执行
[root@server1 ~]# tar xfz convoy.tar.gz
[root@server1 ~]# cd convoy/
[root@server1 convoy]# ls
convoy convoy-pdata_tools SHA1SUMS
[root@server1 convoy]# cp convoy convoy-pdata_tools /usr/local/bin #将convoy的命令放在命令库里
运行convoy,执行成功后回车可以回到shell界面,&符可以运行在后台
[root@server1 convoy]# convoy daemon --drivers vfs --driver-opts vfs.path=/mnt/nfs &
[root@server1 convoy]# mkdir /etc/docker/plugins #创建插件目录,docker程序默认会在这个目录下查找convoy套接字
把 convoy.sock 文件路径写入 convoy.spec,必须以 spec 结尾,convoy 是插件名
[root@server1 convoy]# cd /etc/docker/plugins/
[root@server1 plugins]# echo "unix:///var/run/convoy/convoy.sock" > convoy.spec
在server1操作完成后,server2进行同样的操作
[root@server2 convoy]# convoy daemon --drivers vfs --driver-opts vfs.path=/mnt/nfs &
[root@server2 convoy]# cd /etc/docker/plugins/
[root@server2 plugins]# echo "unix:///var/run/convoy/convoy.sock" > convoy.spec
docker引擎默认扫描 /etc/docker/plugins目录中的convoy.spec—>访问/run/convoy/convoy.sock文件—>发起响应的api请求—>把数据写入vol1中—>底层通过nfs进行主机间的数据同步
创建卷,并进行查看
[root@server1 convoy]# convoy create vol1 #创建一个vol1的卷
[root@server1 convoy]# convoy list #列出所有卷信息
"vol1": {
"Name": "vol1",
"Driver": "vfs",
"MountPoint": "",
"Path": "/mnt/nfs/vol1", #创建出的路径就在/mnt/nfs/
"PrepareForVM": "false",
"Size": "0",
同时还可以看到/mnt/nfs下还会有一个 config 目录,里面的东西不要删除,否则客户端命令可能就用不了
[root@server1 convoy]# ls /mnt/nfs
config testfile1 vol1
开启一个容器,将vol1挂载到/data上,并进行操作测试
[root@server1 convoy]# docker run -it --name vm1 -v vol1:/data busybox
/ # cd data/
/data # touch file1 file2
/data # ls
file1 file2
[root@server1 ~]# ls /mnt/nfs/vol1/ #切换到宿主机shell可以看到建立的文件
file1 file2
[root@server2 nfs]# ls /mnt/nfs/vol1/ #server2上同样可以看到
file1 file2
就算是关闭容器数据同样可以看到,假设vm1这个容器挂了,在server2上再建立一个vm1里面的数据也是一样的
[root@server2 ~]# docker run -it --name vm1 -v vol1:/data busybox
/ # ls /data/
file1 file2
server2 上恢复,这里不用再次去新建 convoy 是因为插件是通过 nfs 同步的,一个节点新建,其他节点都能看到。
清理存储
想要清理储存,先删除所有占用存储的容器
[root@server2 ~]# convoy delete vol1 #删除卷
[root@server2 ~]# convoy list #就无法查看到了,server1上同样也看不到里
{}