cinder中transfer卷功能实现
cinder服务提供了几个transfer-*接口,用来支持租户间转移卷功能:
|
~$ cinder help | grep transfer transfer-accept Accepts a volume transfer. transfer-create Creates a volume transfer. transfer-delete Undo a transfer. transfer-list List all the transfers. transfer-show Show details about a transfer. |
大概流程是,租户A的卷vol-1,可以通过transfer-create接口创建一个转移操作流,并返回一个接收卷所需的验证码,然后可以通过transfer-list、transfer-show可以看到这个操作流,如果租户A在卷未被接收前反悔了,还可以通过transfer-delete接口删除这个操作流。
目标租户B,可以通过transfer-accept接口接收这个卷vol-1,接收完之后,租户A就看不到这个卷vol-1了,而租户B则可以看到并使用它。
命令行操作流程大概如下,首先使用租户A的账号执行:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
|
~$ cinder create --display-name vol-1 10 # 租户A创建一个卷 +---------------------+--------------------------------------+ | Property | Value | +---------------------+--------------------------------------+ | attachments | [] | | availability_zone | zw | | bootable | false | | created_at | 2015-07-06T08:18:14.214559 | | display_description | None | | display_name | vol-1 | | id | ec1323d5-467b-4ddb-a3fb-352936e688e8 | | metadata | {} | | size | 10 | | snapshot_id | None | | source_volid | None | | status | creating | | volume_type | None | +---------------------+--------------------------------------+ |
|
~$ cinder transfer-create --display-name transfer-to-project-b vol-1 # 租户A创建卷转移操作流 +------------+--------------------------------------+ | Property | Value | +------------+--------------------------------------+ | auth_key | 289fa570e6dc4626 | # 接收卷验证码,只在创建操作流时返回一次 | created_at | 2015-07-06T08:19:07.687577 | | id | c7ff2c3c-f051-480e-94be-bef91d164a73 | # 卷转移操作流UUID | name | transfer-to-project-b | | volume_id | ec1323d5-467b-4ddb-a3fb-352936e688e8 | +------------+--------------------------------------+ |
|
~$ cinder transfer-list +--------------------------------------+--------------------------------------+-----------------------+ | ID | Volume ID | Name | +--------------------------------------+--------------------------------------+-----------------------+ | b41c6e3a-6db4-4d82-9466-79ecce569fcf | 7c811013-9546-4059-9084-4f1a70bc1fea | transfer-to-project-b | +--------------------------------------+--------------------------------------+-----------------------+ |
|
~$ cinder transfer-show c7ff2c3c-f051-480e-94be-bef91d164a73 +------------+--------------------------------------+ | Property | Value | +------------+--------------------------------------+ | created_at | 2015-07-06T08:19:07.000000 | | id | c7ff2c3c-f051-480e-94be-bef91d164a73 | | name | transfer-to-project-b | | volume_id | ec1323d5-467b-4ddb-a3fb-352936e688e8 | +------------+--------------------------------------+ |
然后更换到租户B的账号下执行:
|
~$ cinder transfer-accept c7ff2c3c-f051-480e-94be-bef91d164a73 289fa570e6dc4626 # 租户B接收卷 +-----------+--------------------------------------+ | Property | Value | +-----------+--------------------------------------+ | id | c7ff2c3c-f051-480e-94be-bef91d164a73 | | name | transfer-to-project-b | | volume_id | ec1323d5-467b-4ddb-a3fb-352936e688e8 | +-----------+--------------------------------------+ |
注意:如果在租户B下执行transfer-list、transfer-show操作,是看不到租户A创建的卷转移操作流的,如果租户B具有管理员权限,则可以根据卷转移操作流UUID来通过transfer-show看到操作流详情。
租户B接收卷之后,就可以通过cinder list、cinder show看到卷vol-1了,租户A则看不到了。
整个流程的代码实现也比较简单,主要就是:
1、检查并预留租户B的配额(类似创建一个新卷)
2、修改卷所属的租户和用户
3、减少租户A的配额(类似删除一个卷)
当然上面这部分不是本文的重点,接下来是考虑在nova服务中实现云主机的转移功能。
云主机租户间转移方案
背景
主要说下为啥要做这个功能?
最终目标是让自动部署平台可以快速的扩容,具体使用场景是,自动部署平台使用的docker容器是在云主机中运行的,在集群资源利用率达到某个预设值后,可以快速的水平扩容出去,比如新增一批docker容器来运行各种服务(可能对应的是一批kubernetes的pod,也就是多个docker实例),这里的“快速”是要尽量做到秒级扩容,但是目前我们创建一台本地实例存储盘启动的云主机,如果目标计算节点上没有base镜像缓存,可能需要几分钟的时间来下载base镜像,然后创建云主机(几秒钟),最后启动云主机(几十秒),即使有base镜像缓存,也需要几十秒到1分钟以上的等待时间(创建+启动)才能通过自动部署平台的agent开始在云主机内部执行部署操作,这个耗时情况目前看来自动部署平台是不能接受的,需要实现一个云主机资源池,来随时加入到集群中作为docker宿主机,如果云主机不支持在租户间转移,那么这个资源池只能是每个租户维护一个,可想而知,会有很多资源浪费情况,如果资源池能做到平台级别,整个平台维护一个,则会节约很多。
预期操作流程
nova本身并未实现该功能,所有功能都需要我们自己开发实现,并且只是给内部PAAS服务使用,因此实现和操作流程越简单越好,不需要跟cinder中的卷转移一样,还要create然后accept,只需要实现一个transfer接口就好了,直接把云主机转移到指定租户(当然需要操作调用方有特定权限去执行该操作),并且修改掉两个租户的配额。
另外要说明的是租户私有网问题,由于租户的私有网是不互通的,所以云主机资源池中的云主机不能绑定私有网port,需要等待云主机从资源池中分配出去之后,再根据云主机真实所属的租户来动态挂载私有网等网络类型的port到云主机,达到网络连通的目的。
但是目前看起来如果创建云主机时不指定network id,会返回400错误,这个还需要进一步分析解决。
大致代码实现流程
1、通过扩展api,增加一个action,比如叫“transferInstance”,具体扩展方法可以参考我们的commit 2ed5a96089eb3fd57efb4fa88b9956ec288e539c,patch下载:extend-vnc-password.tar。
API URL:POST http://nova/v2/981f3e7cdba14f0ab769d3325b931838/servers/73cae225-7a96-4d4f-836c-931d8be77261/action
参数大概为:
|
{ "transferInstance": { "tenant_id": "abcdefg", # 新租户的id "user_id": "123456" # 新用户的id } } |
2、在nova/netease/compute/api.py中新增transfer_instance方法,实现修改转移前后两个租户的配额,以及nova db中instances表中instance所属project_id和user_id
3、返回结果给调用方(成功200,失败其他错误码,比如配额不足413,目标云主机或租户找不到404等)
网络相关问题
目前必须带私有网创建云主机,如果要改掉这一限制,整个创建云主机的流程都需要修改,改动比较多,对现有功能影响也比较大,不建议修改,可以通过创建后卸载私有网操作来规避这个问题,大致流程如下:
1、创建云主机,并且包含了一个私有网port
2、创建完毕后,从云主机上卸载私有网port
3、放入云主机资源池,之后按需转移云主机到新租户下
4、在新租户内创建新的私有网port并挂载到云主机
这一流程潜在的问题包括:
1、私有网挂载卸载操作之前没有测试过,默认都是与云主机生命周期绑定的,需要进一步测试验证相关流程和网络连通性
2、挂载私有网port后,要多久网络才能连通也需要测试,如果耗时较长,甚至比新创建云主机还要耗时,那么这个方案是不可接受的
3、卸载完私有网port之后,要多久才能挂载新的port到云主机,以防止并发问题(主要是指qemu进程和云主机内部的pci设备hotplug模块两个方面)导致的其他问题(比如看不到网卡、网络不通等)
4、可能需要自动部署平台增加从云主机资源池中选择被转移云主机的逻辑,比如先进先出方式,而不是随机选择,以防止刚加入池子的云主机被转移,导致的port挂卸载并发问题
说明:上述流程待POC验证