http://www.tuicool.com/articles/MnIRZvJ

http://uzhima.com/2016/08/02/what-is-docker-volume-plugin/

在之前的『闲话云计算』一文中曾提到过:构成云计算的『干细胞』是 计算、存储和网络 。Docker 作为云计算领域的新生力量,自然少不了对这三要素的关注,我们来具体看看他是怎么设计的。

众所周知,Docker 提供了容器的运行环境,通过LXC对CPU计算资源进行隔离,运行在每一台OS之上, 计算资源 是他最容易控制和管理的,但对 网络存储 的支持在之前一直不是特别理想,直到1.7之后的版本推出了 插件(Plugin) 的概念才有所改善。有了插件系统提供的能力,开发者可以根据Docker的运行周边环境,定制属于自己的网络和存储方案,对Engine进行扩展,满足自己容器化的需求。比如,阿里云上的 Docker 容器就可以使用 VPC网络插件 ,给容器分配虚拟IP,实现容器在VPC内的网络互联;还可以使用 OSS 存储插件 ,实现容器对 OSS Bucket 的访问,扩展容器的存储能力。

这就是Docker,对『计算』的完全掌控,对『存储』和『网络』的基本支持,同时通过插件扩展存储和网络的边界,与现有云计算的成果无缝融合。 除了有存储Volume、网络Network,Docker还提供了认证Authorization、IP地址管理IPAM等插件类型。

存储插件(Volume Plugin)

下面主要介绍下 Docker存储插件 的设计和实现。

图片来源: slideshare

Docker Plugin 是以Web Service的服务运行在每一台Docker Host上的,通过HTTP协议传输RPC风格的JSON数据完成通信。

Plugin的启动和停止,并不归Docker管理,Docker Daemon依靠在缺省路径下查找Unix Socket文件,自动发现可用的插件。

当客户端与Daemon交互,使用插件创建数据卷时,Daemon会在后端找到插件对应的 socket 文件,建立连接并发起相应的API请求,最终结合Daemon自身的处理完成客户端的请求。

VolumePlugin所定义的 API接口 有8个:

  • /VolumeDriver.Create
  • /VolumeDriver.Remove
  • /VolumeDriver.Mount
  • /VolumeDriver.Path
  • /VolumeDriver.Unmount
  • /VolumeDriver.Get
  • /VolumeDriver.List
  • /VolumeDriver.Capabilities

在Docker官方文档中列出的Volume Plugins有近 20个 。

OSS存储插件(OSSFS Volume Plugin)

OSS 是阿里云的对象存储服务,解决文件类存储的需求。有一个基于 OSS 的文件系统的实现,叫 ossfs 。可以把某个 OSS Bucket 挂载到OS中的一个分区上,这样就好像访问本地文件一样,访问 OSS 文件。

文件系统          1K-块    已用     可用 已用% 挂载点
ossfs           256T     0  256T    0% /mnt/i/ossfs/mytestbucket

在这个基础上,编写了一个Docker数据卷的插件,使用该插件,可以创建 ossfs 数据卷,并Bind到容器中使用。

认识插件接口(Volume Plugin API)

为了对插件有一个直观的认识,我们从实践出发,拿OSSFS插件举例,追踪接口调用,来帮助我们理解整个过程,加深理解。

OSSFS插件并不是这次的重点,因此它的启动过程以及内部实现细节并不在这次讨论范围,会逐一略过。我用的是阿里云容器服务自带的OSSFS插件,插件启动后会生成一个unix socket文件 /run/docker/plugins/ossfs.sock

为了便于监控插件API的日志,我们通过socat搭建一个代理,伪造一个新的socket文件 ossfs2.sock ,对这个代理的请求会被输出到终端上。

sudo socat -t100 -v UNIX-LISTEN:/run/docker/plugins/ossfs2.sock,mode=777,reuseaddr,fork UNIX-CONNECT:/run/docker/plugins/ossfs.sock

这时,在Docker Daemon看来我们就拥有了两个插件,ossfs和ossfs2,不过二者本质上是同一个web service。

创建Volume

下面,使用插件ossfs2创建数据卷 ff001 ,目的是为了获取请求日志。

[root@node1 ~]# docker volume create  -d ossfs2 --name=ff001 -o bucket=mytestbucket -o ak_id=xxx -o ak_secret=xxxxxx -o url=vpc100-oss-cn-hangzhou.aliyuncs.com
ff001

在刚才的socat命令下,可以看到打印日志,摘取如下:

2016/08/02 17:04:49.780139 length=143 from=0 to=142 POST /Plugin.Activate HTTP/1.1\r Host: \r

User-Agent: Go-http-client/1.1\r

Content-Length: 1\r

Accept: application/vnd.docker.plugins.v1.2+json\r

\r < 2016/08/02 17:04:49.780763 length=165 from=0 to=164

HTTP/1.1 200 OK\r

{"Implements": ["VolumeDriver"]}

2016/08/02 17:04:49.781068 length=162 from=143 to=304 POST /VolumeDriver.Get HTTP/1.1\r {"Name":"ff001"} < 2016/08/02 17:04:49.781364 length=229 from=165 to=393

HTTP/1.1 500 Internal Server Error\r

{"Mountpoint":"","Err":"Invalid ossfs options.","Volumes":null,"Volume":null}

2016/08/02 17:04:49.781708 length=316 from=305 to=620 POST /VolumeDriver.Create HTTP/1.1\r {"Name":"ff001","Opts":{"ak id":"xxxx","ak secret":"xxxxxx","bucket":"mytestbucket","url":"vpc100-oss-cn-hangzhou.aliyuncs.com"}} < 2016/08/02 17:04:49.849440 length=188 from=394 to=581

HTTP/1.1 200 OK\r

{"Mountpoint":"","Err":"","Volumes":null,"Volume":null}

2016/08/02 17:04:49.867860 length=163 from=621 to=783 POST /VolumeDriver.Path HTTP/1.1\r {"Name":"ff001"} < 2016/08/02 17:04:49.872552 length=220 from=582 to=801

HTTP/1.1 200 OK\r

{"Mountpoint":"/mnt/i/ossfs/mytestbucket","Err":"","Volumes":null,"Volume":null}

2016/08/02 17:04:51.984118 length=148 from=784 to=931 POST /VolumeDriver.List HTTP/1.1\r {} < 2016/08/02 17:04:51.985414 length=316 from=802 to=1117

{"Mountpoint":"","Err":"","Volumes":[{"Name":"ff001","Mountpoint":"/mnt/i/ossfs/mytestbucket"}],"Volume":null}

所有的请求都是POST方法,URI、request body和response body我都已经加粗。简单解释下, /Plugin.Activate 接口是Plugin的公共接口,是做第一次Handshake,Plugin会返回类型是Volume还是Network等。一个Volume的创建过程,会先通过 Get 判断名称是否存在,然后执行 Create 做数据卷的初始化,接着通过 Path 接口获取Volume的本地路径。最后的 List 是用来查询这个插件下有哪些Volume的,是被其他客户端发起的,跟这次的创建过程并无关系。

至此,一个Volume就创建完成了,但还没有被容器使用。

使用Volume

下面我们看看,在容器使用Volume时,Plugin提供了哪些接口。执行下面命令:

[root@node1 ~]# docker run -ti --volume-driver=ossfs2 -v ff001:/oss busybox ls /oss
1.jpeg

创建并启动一个容器,挂载数据卷 ff001 到容器内的 /oss 目录,然后执行命令 ls /oss 查看目录下文件,命令退出后容器停止。

在ossfs2.sock处抓取到请求日志如下:

2016/08/02 17:35:18.680407 length=164 from=13610 to=13773 POST /VolumeDriver.Mount HTTP/1.1\r {"Name":"ff001"} < 2016/08/02 17:35:18.680923 length=220 from=24348 to=24567

HTTP/1.1 200 OK\r

{"Mountpoint":"/mnt/i/ossfs/mytestbucket","Err":"","Volumes":null,"Volume":null}

2016/08/02 17:35:19.143549 length=166 from=13774 to=13939 POST /VolumeDriver.Unmount HTTP/1.1\r {"Name":"ff001"} < 2016/08/02 17:35:19.144880 length=188 from=24568 to=24755

HTTP/1.1 200 OK\r

{"Mountpoint":"","Err":"","Volumes":null,"Volume":null}

启动容器时,Daemon会请求Plugin的 Mount 接口,然后与容器内的目录绑定,容器停止时会请求 Unmount 接口。

删除Volume

我们使用以下命令删除Volume

docker volume rm ff001

当有容器在使用Volume时,删除会失败(Daemon中有记录)。成功删除时,会打印以下日志:

2016/08/02 18:29:23.833416 length=162 from=34688 to=34849 POST /VolumeDriver.Get HTTP/1.1\r {"Name":"ff001"} < 2016/08/02 18:29:23.833928 length=249 from=59892 to=60140

HTTP/1.1 200 OK\r

{"Mountpoint":"","Err":"","Volumes":null,"Volume":{"Name":"ff001","Mountpoint":"/mnt/i/ossfs/mytestbucket"}}

2016/08/02 18:29:23.834274 length=165 from=34850 to=35014 POST /VolumeDriver.Remove HTTP/1.1\r {"Name":"ff001"} < 2016/08/02 18:29:24.027498 length=188 from=60141 to=60328

HTTP/1.1 200 OK\r

{"Mountpoint":"","Err":"","Volumes":null,"Volume":null}

一个 Get ,一个 Remove 就完成了删除时的接口调用。

自己写一个?

根据上面的介绍,相比你已经大概清楚一个Volume Plugin需要做哪些事情,提供哪些接口,以及在什么时候使用这些接口了。 如果,你想自己写一个Volume Plugin,也是很简单的事情。Docker已经提供了Go语言的 Plugin SDK 『go-plugins-helpers』 ,内置了基础API接口,你只需要引用它们,并根据自己存储的特征具体实现这些接口就可以了。同样可以参考这些 公开插件 的文档或代码,比如 Flocker , Glusterfs 等。

转载于:https://www.cnblogs.com/zhengah/p/5889340.html

Docker 的插件式设计相关推荐

  1. 插件式设计的架构模型与实例

    插件式设计近年来非常流行,其中eclipse起了推波助澜的作用,提到插件式就会不由自主的想到eclipse.其实插件式设计并不是什么新事物,早在几十年前就有了.像X Server就是基于插件式设计的, ...

  2. 通过自定义配置实现插件式设计

    软件设计有一句话叫做"约定优于配置",很多人将其作为拒绝配置的理由.但是,"约定"和"配置"的使用,都有个度的问题.我不赞为了所谓的扩展性, ...

  3. 插件式架构设计实践:插件式系统架构设计简介

    本系列博文将使用微软RIA技术解决方案Silverlight以及扩展性管理框架Managed Extensibility Framework(MEF),以插件式架构设计为导线,分享本人在从事基于微软S ...

  4. 插件式架构设计实践一:插件式系统架构设计简介

    本系列博文将使用微软RIA技术解决方案Silverlight以及扩展性管理框架Managed Extensibility Framework(MEF),以插件式架构设计为导线,分享本人在从事基于微软S ...

  5. Thinkphp多用户B2B2C商城源码带安装视频 系统主要功能采用高内聚,辅助功能插件式实现

    Thinkphp5多用户B2B2C商城源码+安装视频 源码分享,需要源码学习可私信我. 系统概述:本系统是基于ThinkPHP 5.1.34搭建的多商户电商平台,是目前完善度领先的电商管理平台.系统主 ...

  6. 插件式可扩展架构设计心得(干货)

    点击上方 程序员成长指北,关注公众号 回复1,加入高级 Node 进阶交流群 引子 大家可能不知道,鄙人之前人送外号"过度设计".作为一个自信的研发人员,我总是希望我开发的系统可以 ...

  7. Docker Buildx插件

    Docker Buildx插件 Overview Docker Buildx是一个CLI插件,它扩展了Docker命令,完全支持Moby BuildKit builder toolkit提供的功能.它 ...

  8. .net 插件式开发学习总结

    .NET简谈插件系统开发模式 今天跟大家分享一下我们在日常开发中并不常用的开发模式"插件系统模式",什么叫插件从大一点的概念讲就是我们开发的软件是由很小的模块组成,每一块都能成功的 ...

  9. Android应用插件式开发解决方法[转]

    一.现实需求描述 一般的,一个Android应用在开发到了一定阶段以后,功能模块将会越来越多,APK安装包也越来越大,用户在使用过程中也没有办法选择性的加载自己需要的功能模块.此时可能就需要考虑如何分 ...

最新文章

  1. 关于Storm Tick
  2. jni c call java_Java通过-jni调用c语言
  3. python numpy逆_numpy.linalg.inv返回奇异矩阵的逆函数 - python
  4. append 后如何删除_如何在STATA中合并数据文件呢?
  5. 微信小程序和vue双向绑定哪里不一样_浅析Vue 和微信小程序的区别、比较
  6. JVM知识(三):内存模型和可见性
  7. html+css+js实现登录页面
  8. 用python实现中文词云完整流程(wordcloud、jieba)
  9. php对象依赖注入作用,php面向对象依赖注入理解及代码举例分析解释
  10. VPP 助你创新更高效、更灵活的报文处理方案
  11. YAF 菜鸟的学习笔记
  12. jsp后台页面登录html代码,炫酷的登录jsp页面完整代码
  13. 计算机读不出光盘,光驱读不出光盘,详细教您电脑光盘不能被识别怎么解决
  14. 解决No thread-bound request found: Are you referring to request attributes outside of an actual web.异常
  15. c++读取mnn模型
  16. Java编译成功但是运行不成功的原因
  17. 2022年山东省安全员C证考试题及在线模拟考试
  18. C语言实现双向非循环链表(不带头结点)的基本操作
  19. 新消费到底「新」在哪里?
  20. mediacodec.java_Android原生编解码接口 MediaCodec 之——踩坑

热门文章

  1. Boost:自定义双端队列的测试程序
  2. Boost:bimap双图项目的测试程序
  3. Boost:cpu时间的实例
  4. ITK:使用Otsu阈值图像
  5. DCMTK:OFUUID测试程序
  6. OpenCV:使用OpenCV无缝克隆模块的实例(附完整代码)
  7. OPENCV背景细分background segmentation的实例(附完整代码)
  8. C++Rabin Karp算法字符串快速查找(附完整源码)
  9. C++ number of positive divisors计算正除数的实现算法(附完整源码)
  10. c++容器共性机制研究