【探索docker存储之路】一、窥探docker中的volume plugin内幕

重构前言

本来想后续一篇文章专门写docker volume plugin。这篇可以简单粗暴的拉通docker的代码。之前看《Docker容器和容器云》感觉原理解析部分没有进一步深入到volume plugin的层次。本想以此作为第3篇的主要内容。最近看了一下新出的书《Docker进阶与实践》2016年2月出版,第6章对容器卷管理做出了比较接地气的的讲解,并对卷插件做了描述。于是把原来计划中的第3篇整合到第一篇,把这一篇内容升华一下。下面分析的源码版本基于docker1.10

Volume Plugin Introduction

通过volume机制,docker可以轻易地将主机目录挂载到容器中;通过docker的volume plugin机制,使docker能够方便地整合第三方存储,为docker提供volume。volume plugin

Container and Volume

container如何使用volume?

volume机制可以使容器访问存储都使用统一的接口(文件接口),对于容器中的进程来说,volume就是一个已挂载的目录,容器内进程使用该目录就与普通目录一样。

docker使用Container结构管理容器,Container结构中有map类型的MountPoints变量,用于存储container中所有已挂载的volume即是MountPoint结构,MountPoint结构保存挂载目录和volume结构的基本信息,并且管理目录的权限控制、挂载传播方式等特性。

Volume是个interface,docker实现两种volume。①基于主机文件系统。②基于Volume Plugin。
这里写图片描述

基于主机文件系统提供volume

容器启动:docker run -i -v /data ubuntu:latest /bin/bash
容器内看到的挂载信息:
这里写图片描述

/etc/resolv.conf、/etc/hostname和/etc/hosts三个文件是为了解决每个container都拥有自己的hostname和DNS配置,使用了bind mount将主机的文件,挂载到container内部。/data也是使用了同样的方式将主机的目录挂载到container中。下面是主机挂载到container的文件:
这里写图片描述

查看/dev/disk/by-uuid/88f22c9e-9d5d-4c7e-8984-eba8446361e6是链接文件指向/dev/sda2,这是主机的根目录文件系统。
这里写图片描述

container中的volume

容器启动:docker run -i -v cvol1:/data --volume-driver=convoy ubuntu:latest /bin/bash 。将volume: dockervol挂载到容器目录/data
容器内看到的挂载信息:

这里写图片描述
此时挂载卷信息:
这里写图片描述

Docker Volume Plugin

docker volume plugin框架

docker volume框架

docker daemon对volume的管理

docker daemon中的volume
如上图,docker daemon结构中有个成员volumes,类型是VolumeStore类型,包含一组管理volume的函数:Create、Remove、List、Get、Refs …。通过两个变量,管理container和volume的关系。

names : map结构,key是volume的name,value是实现Volume接口的结构对象。存储该daemon内所有的volume。
refs : map结构,key是volume的name,value是string数组保存引用该volume的container id。
docker daemon通过volumes变量,就可以管理所有的volume,提供如下命令:
这里写图片描述

docker volume 管理

基于本地文件系统的volume框架

① 基于本地文件系统的volume
可以在执行docker create或docker run时,通过-v参数将主机的目录作为容器的数据卷。这部分功能便是基于本地文件系统的volume管理。上图中蓝色部分localVolume和Root。这两个结构就是对主机目录和文件进行管理,具体的对应关系如下图:
这里写图片描述
从上图可以看出,基于本地文件系统的卷管理,Driver便是卷的根目录/var/lib/docker/volumes。一个卷就是根目录下的一个子目录。

② 适配plugin的Volume
docker为了支持第三方存储方案,在1.8版本引入volume plugin机制,volumeAdapter和volumeDriverAdapter分别实现了接口Volume和Driver接口,用于表示由plugin提供的volume和plugin driver。在下一小节详细描述。
上图中,全局变量drivers保存了所有注册到docker daemon的Driver。docker daemon需要对volume进行管理操作时,通过GetDriver函数从drivers变量中获取指定名称的Driver,通过Driver可以通过Create,Remove,List,Get对Driver中volume进行管理。通过Get函数获取Volume结构,可以对卷进行管理操作:Name,DriverName,Path,Mount,Unmount。

docker plugin 实现原理

volume plugin实现原理
① docker plugin机制
上一节已经说过docker针对volume plugin实现了两个适配类型volumeDriverAdapter和volumeAdapter。
* volumeDriverAdapter : 实现Driver接口,用于抽象各种plugin的驱动,该类型可以适配所有符合规范的volume plugin,对plugin进行管理。
* volumeAdapter : 实现Volume接口,用于抽象所有plugin提供的volume,该类型可以适配所有符合规范的volume plugin提供的类型,对volume进行管理。
通过抽象,对于plugin和其提供的volume,docker daemon结构和container结构使用上述两个适配类型,对plugin和volume进行管理和使用。

上述两个类型都有一个volumeDriverProxy结构变量proxy,用于与plugin进行通信。volumeDriverProxy结构实现了与plugin通信的接口volumeDriver,提供Create、Remove、Path、Mount、Unmount、List、Get接口与通信。volumeDriverProxy结构的client变量,使用这个变量与Plugin Daemon进行通信。client变量是Plugin结构中的Client变量是Client结构类型,包含了http.Client类型对象。
上图左下方,plugins结构类型的全局变量storage保存所有被docker daemon发现的Plugin结构,Plugin结构代表外部插件。

② docker plugin的发现过程
docker daemon通过unix域套接字与plugin daemon进行通信。所以plugin需要让docker daemon知道plugin的unix域套接字文件的路径。在执行命令:docker run … -v volumename:/data –volume-driver=convoy。

plugin发现步骤
* docker daemon首先会在/run/docker/plugins搜索对应的套接字文件,套接字文件名必须和VolumeDriver名一致,如上述命令,便是搜索convoy.sock。
* 如果上一步搜索不到,则到/etc/docker/plugins和/usr/lib/docker/plugins两个目录搜索spec或json文件。文件中指定套接字文件的URL。如:unix:///var/run/convoy/convoy.sock 。
* 根据前面两步发现的unix域套接字URL,构建Plugin对象,并将新建对象加入到全局变量storage的plugins字段中。

③ docker volume plugin的使用
执行docker run命令时,指定参数–volume-driver=convoy。docker daemon会先从storage.plugins中寻找Plugin结构,如果没有找到,就发起②的发现流程。找到则直接使用Client构建volumeDriverProxy。

④ docker daemon与plugin daemon通信的API
前面已经提到过,docker daemon和plugin daemon基于unix域套接字,使用Restful API进行通信,下面是详细的API:
* Plugin.Activate : 发送一个请求到Plugin,plugin返回其类型,如convoy就返回VolumeDriver。相当于Docker和Plugin daemon直接的连接建立的握手报文。
* VolumeDriver.Create : 创建一个卷,Docker会发送卷名称和参数发送给插件,卷插件会根据Docker发送过来的参数创建一个卷,并和这个卷名称关联。
* VolumeDriver.Mount : 挂载一个卷到本机,Docker会把卷名称和参数发送给参数。插件会返回一个本地路径给Docker,这个路径就是卷所在的位置。Docker在创建容器的时候,会将这个路径挂载到容器中。
* VolumeDriver.Path : 一个卷创建成功后,Docker会调用Path API来获取这个卷的路径,随后Docker通过调用Mount API,让插件将这个卷挂载到本机。
* VolumeDriver.Unmount : 当容器退出时,Docker daemon会发送Umount API给插件,通知插件这个卷不再被使用,插件可以对该卷做些清理工作(比如引用计数减一,不同的插件行为不同)。
* VolumeDriver.Remove : 删掉特定的卷时调用,当运行”docker rm -v”命令时,Docker会调用该API发送请求给插件。
* VolumeDriver.List : 执行docker volume ls命令时,会向plugin发送该请求,获取volume list。
* VolumeDriver.Get : 获取plugin volume的详细信息。

自定义volume plugin

为了方便实现volume plugin,docker提供go-plugins-helper包,提供基础的功能,仅仅需要实现一个接口volume.Driver,并启动http server便可。
这里写图片描述
例子:GlusterFS就是使用这个包,基于glusterfs提供volume。docker-volume-glusterfs

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值