docker Volume Plugin 开发及Golang实现

      该项目要用于生产环境了,完善加固了一下代码,顺便更新一下文章。

     在加固项目的代码时候 ,调整了卷创建的顺序,调用docker volume create的时候,就把lv创建出来,并挂载到了本地目录,中间遇到了一个很奇怪的问题,挂载lv代码

1
2
3
4
5
6
err = syscall.Mount(lvdiskname, mountPoint, "xfs", syscall.MS\_NOSUID|syscall.MS\_STRICTATIME, "")

if err != nil {
log.Error("mount lv failed", err)
return volume.Response{Err: "mount lv failed"}
}

      使用该代码挂载完成后,在命令行执行df -h 命令是无法查看到挂载信息的,代码也没有报错,尝试把lv删除时,会出现 Device busy的错误。数据并没有丢失,可以在容器内正常使用。

google到了 mount namespace的概念。

``
mnt namespace为进程提供独立的文件系统视图。当clone()函数中带有CLONE_NEWNS标志时,新的mnt ns在子进程中被创建,新的mnt ns是一份父mnt ns的拷贝,
但是在子进程中调用mount安装的文件系统,将独立于父进程的mnt ns,只出现在新的mnt ns上
使用syscall.Mount 函数应该是在另一个namespace 中进行了挂载,因此我是无法查看到。

    前期的项目需求,需要合理利用宿主机的存储,利用在宿主机部署Agent的方式,实现了基于LVM分配docker数据卷的方式,随着开发的进行,项目想要集成docker compose 完成应用的自动编排,需要在docker compose中为容器创建数据卷并且指定卷大小,之前的采用agent的模式已经无法满足目前的需求。参考docker 官方文档Local-Persist项目,实现了一个基于LVM的volume 插件 docker-volume-plugin-lvm

      docker Volume Plugin 提供了标准的卷管理API,第三方只需要实现这些API就可以了。

     插件加载方式,将自己实现的Driver注册,启动main函数,实际上是启动了一个监听端口,sock文件:/var/run/docker/plugins/LVM.sock

1
2
3
4
5
6
func main() {
driver := NewLvmPersistDriver()

handler := volume.NewHandler(driver)
fmt.Println(handler.ServeUnix("root", driver.Name))
}

 查询卷API:

1
func (driver \*LvmPersistDriver) Get(req volume.Request) volume.Response

       创建卷API:根据入参获取卷名称和卷大小,在LVM的VG中分配LV,并将卷的元数据保存到内存并持久化,若没有设置卷大小,可以设置默认值(目前只能通过代码修改) PS:在使用docker create 命令创建容器时,无法指定卷大小比较坑,还好docker compose支持

1
2
func (driver \*LvmPersistDriver) Create(req volume.Request) volume.Response
```    挂载卷API:根据入参获取卷名称,校验该卷是否已经存在,若存在,将该LV格式化,并挂载到宿主机的目录(宿主机目录由卷插件指定)(若宿主机目录已经被挂载,则不执行该步骤),将挂载点,也就是宿主机目录以volume.Response的方式返回,PS:支持多个容器挂载同一个数据卷,但是读写控制目前没有实现,需要Container自己控制。

func (driver *LvmPersistDriver) Mount(req volume.Request) volume.Response

1
2

  卸载卷API:

func (driver *LvmPersistDriver) Unmount(req volume.Request) volume.Response

1
2
3
4



删除卷API:

func (driver *LvmPersistDriver) Remove(req volume.Request) volume.Response

```
具体实现可以参考代码实现。docker-volume-plugin-lvm

代码目前不是很完善,测试代码,部署运行代码 还没有实现。我比较懒。。。