背景与目标
OpenStack 是目前广泛使用的资源管理平台,向用户提供包括镜像、云主机、云硬盘等在内的资源,而 Ceph RBD 是最为流行的 OpenStack 块存储后端之一,提供了可伸缩的存储能力。
CurveBS(后称CBD)是 Curve 社区推出的高性能块存储软件。OpenStack 对于存储的访问是通过各个存储的驱动实现。CBD 如果想要对接 OpenStack, 那么需要维护对应的 CBD 存储驱动,改动包括 glance, nova, cinder, libvirt 和qemu。目前改动暂时并没有推到对应上游的计划,如果用户需要使用,需要自行修改代码并且编译上述的所有软件。
除了这一种做法,我们可以通过使用 CBD 的接口来模拟 OpenStack 中使用的部分 RBD 接口,来直接使用 RBD 驱动以调用 CBD,这也就是 Ceph RBD 的兼容层,用户只需要替换 RBD 对应的 librados 和 librbd 动态库以及 python3-rbd 和 python3-rados 的实现就可以进行体验。如果后续有长期使用的需求,再将这种使用方式替换为 CBD 专属驱动。
RBD 和 CBD的概念映射
在配置使用 Ceph RBD 时,我们往往需要指定几个配置,包括集群配置,逻辑池等。在 CBD 中,我们需要找到一种映射关系来正确合理地处理他们。
以下是概念的映射表:
rbd -> cbd
pool -> dir
user -> owner
vol -> vol其中需要注意的是,CBD 中目前没有类似 ceph 中 pool 的概念可以配置,但是可以创建 dir, 用以模拟 RBD 的 pool;CBD 在访问卷的时候,需要指定 volume 的 owner,我们这里不传入 passwd(sdk不支持),用以对应 RBD 的 user 概念。
镜像(Glance):
上传镜像并打快照并设置保护 flag
下载镜像
虚拟硬盘(Cinder):
创建(新卷或克隆卷)
删除
调整大小
打快照/克隆
虚拟主机(Nova):
创建(使用 cinder 卷或是自行创建系统卷,一般来源是镜像快照或硬盘快照)
删除
挂载卷
兼容层工作
我们需要做的就是提供一个新的 python3 module(rados、rbd)实现来替换现有的。
我们将用到 CBD的 python sdk库https://github.com/opencurve/curve/tree/master/curvefs_python来进行模拟。
文档如下:
https://github.com/opencurve/curve/blob/master/docs/cn/curve-client-python-api.md
在 python 多进程(涉及到fork)的环境中,如果在父进程已经进行了 CBDclient 的初始化,由于 fork 只会拷贝调用线程,而 CBD client 初始化时会创建 rpc 工作线程池,导致子进程异常,无法正常发送 rpc 和后端通信。这个问题主要出现在 Nova 中,nova 会 fork 出N个 worker,可以通过延迟初始化来绕过。
CBD 的 python 模块的 read/write 相关接口使用的是 str 来接受 bytes 数据。在 python2 中 byte 和 str 的区分还不是很严格不会出问题,但是 python3 中 str 的使用是必须需要经过编解码的,接口使用 str 会导致数据的错误。
CBD 现在的快照机制是将源卷的数据转储到S3兼容的对象存储,如果写入的数据很多,将耗时非常久。快照完成后,源卷和快照解耦。快照克隆时,如果不开启 COW,将会需要将对象存储的数据再拷贝一次到 CBD 中,如果启用 COW,那么后续 IO 有可能会需要走对象存储的 IO 栈,可能会很慢。Glance 在镜像上传完成后会自动打一次快照,后续虚拟机的创建也受到这一问题的影响。
由于 CBD 的 python sdk 依赖 CBD 的共享库,在各个平台需要单独编译和打包,目前并没有完善的打包,可能需要自己编译处理。
CBD 逻辑卷大小最小为10G,如果创建一个1G的卷,实际在 CBD 调用 size()获得的仍是10G。
除了直接调用 python 库,可能会需要调用"ceph df", "ceph mon dump", "rbd status", "rbd import" 等命令,需要 hook 实现。
目前不支持上传 COW 镜像。
虚拟机的运行 LibVirt/Qemu
宿主机虚拟机的管理和虚拟化靠 libvirt 和 qemu, libvirt 接收来自 nova 生成的 xml, 生成对应的 qemu 命令运行虚拟机。RBD 驱动下,libvir t和 qemu 使用了 ceph 提供的 librados.so 和 librbd.so 共享库来对接后端的IO。
兼容层工作
我们需要做的是提供一个新的动态库来模拟 librbd 和 librados 的接口,CBD 侧我们将会使用 libnebd-client 来和通过 nebd 和 CBD 后端进行IO交互。nebd 是一个用于解决 client 端热升级的组件,server 端和 CBD 后端进行交互,client 端和 server 端通信,升级时只需要升级重启 nebd-server 即可,不用重启 client(在这里就是qemu)
这里将开发中遇到的问题进行了记录,帮大家避坑。
libnebd-client 库的回调不支持传 args, 无法和 rbd 的接口兼容。通过修改 libnebd-client 来适配。 由于 libnebd-client 中链接了 brpc, 对 pthread 造成了影响,需要在 libvirtd的 env 中设置 preload,不然会导致 symbol 找不到的问题。https://github.com/apache/brpc/issues/1086 虚拟机中 lsblk 看到的硬盘大小是调用的后端 size 接口,由于前面提到的 CBD 逻辑卷大小最小为10G,小硬盘的显示可能不正确。 qemu 的 rbd driver 没有限制 io 对齐,允许任意大小的 io,但是 CBD 要求IO必须4096/4K字节对齐,这个需要 CBD 进行后端支持,或者修改 qemu 的IO限制,默认应该是512字节。
部署一个 curvebs 后端集群。 计算节点上安装 qemu 和 libvirt 以及 rbd 的支持(qemu-block-extra, libvirt-daemon-driver-storage-rbd), 修改 qemu 的执行用户为 root,关闭 apparmor. 计算节点上安装 nebd 软件包,和部署 nebd, 用于支持连接后端的 curve 集群。 替换 librados2 和 librbd1 包中的对应 librados.so 和 librbd.so 为我们魔改的 so(用cbd模拟了rbd的接口,代码https://github.com/h0hmj/curve/commit/d1df07c86c38b5d0d16a025cb560977d3bfc568f)还有 libnebdclientmod.so 修改/etc/default/libvirtd,添加 preload 参数LD_PRELOAD=/usr/lib/nebd/libnebdclientmod.so 使用 kolla 部署 openstack, base 镜像选用 debian, 为 glance、nova 和 cinder 启用 rbd 支持,为了简单,使用 use r为 admin,pool 为 curve 对应的文件夹名称,如果需要从 glance 卷 clone 来创建 vm, 打开 glance 的选项 show_image_direct_url = True.在 curve 后端创建对应的文件夹。 修改 openstack nova-compute 配置使用本机的 libvirt 为 glance-api/nova-compute/cinder-volume 的容器 apt install libunwind8 添加/etc/curve/client.conf 安装 curvefs 的 wheel 包 删除自带的 python-rbd/rados 的 so 实现,替换为我们的魔改版 替换/usr/bin/ceph和/usr/bin/rbd 为我们的魔改版本 重启所有相关服务。 后续可以通过 horizon 的 web 界面进行试用,镜像的创建删除,云主机的创建删除,云硬盘的创建删除等。
我们探索了一种可能的 RBD 兼容方式,即提供 hook 了对应接口的共享库,以及适配当中遇到的问题。但这会导致失去原有的 Ceph RBD 的支持,如果有需求,建议仍然使用单独的 CBD 驱动。
<原创作者:马杰,Curve PMC>


关于 Curve
Curve 亦可作为云存储中间件使用 S3 兼容的对象存储作为数据存储引擎,为公有云用户提供高性价比的共享文件存储。
GitHub:https://github.com/opencurve/curve 官网:https://opencurve.io/ 用户论坛:https://ask.opencurve.io/ 微信群:搜索群助手微信号 OpenCurve_bot




