ceph-disk源码分析
原文 http://www.hl10502.com/2017/06/23/ceph-disk-1/#more
ceph-disk是一个用于部署osd数据及journal分区或目录的工具,基于Python开发。ceph-disk工具放在ceph-base包中,安装ceph-base rpm包将默认安装此工具,比如Jewel版ceph-10.2.7中的ceph-base-10.2.7-0.el7.x86_64.rpm。
ceph-disk命令行
ceph-disk 命令格式如下
-
ceph-disk [-h] [-v] [--log-stdout] [--prepend-to-path PATH] [--statedir PATH] [--sysconfdir PATH] [--setuser USER] [--setgroup GROUP] {prepare,activate,activate-lockbox,activate-block,activate-journal,activate-all,list,suppress-activate,unsuppress-activate,deactivate,destroy,zap,trigger} ...
- prepare:使用一个文件目录或磁盘来准备创建OSD
- activate:激活一个OSD
- activate-lockbox:激活一个lockbox
- activate-block:通过块设备激活一个OSD
- activate-journal:通过journal激活一个OSD
- activate-all:激活所有标记的OSD分区
- list:列出磁盘、分区和OSD
- suppress-activate:禁止激活一个设备
- unsuppress-activate:停止禁止激活一个设备
- deactivate:停用一个OSD
- destroy:销毁一个OSD
- zap:清除设备分区
- trigger:激活任何设备(由udev调用)
ceph-disk工作机制
通过ceph-disk创建osd, 数据分区和journal分区将自动mount。创建osd,主要是prepare和activate。
假设/dev/sdb是OSD要使用的数据盘,OSD要使用的journal分区在/dev/sdc上创建,/dev/sdc是SSD, 创建激活OSD的命令如下:
- ceph-disk prepare /dev/sdb /dev/sdc
- ceph-disk activate /dev/sdb1
sgdisk 命令参考 https://linux.die.net/man/8/sgdisk
udevadm 命令参考 https://linux.die.net/man/8/udevadm
prepare过程
- 使用sgdisk命令销毁数据盘/dev/sdb的GPT和MBR,清除所有分区
- 获取osd_journal_size大小,默认5120M,可以指定设置,准备journal分区
- 一个SSD很可能被多个OSD共享来划分各自的journal分区,/dev/sdc上已分好的区不变,使用sgdisk在分区上增加新的分区作为journal,不影响原来的分区,如果不指定创建分区的uuid,自动为journal分区生成一个journal_uuid,journal分区的typecode为45b0969e-9b03-4f30-b4c6-b4b80ceff106,journal是一个link,指向一个固定的位置,再由这个link指向真正的journal分区,这样可以解决盘符漂移带来的问题
- 使用sgdisk创建数据分区,使用--largest-new来使用磁盘最大可能空间,即将所有的空间用来创建数据分区/dev/sdb1
- 格式化数据分区/dev/sdb1为xfs
- 挂载数据分区/dev/sdb1到临时目录
- 在临时目录下写入ceph_fsid、fsid、magic、journal_uuid四个临时文件,文件内容相应写入
- 创建journal链接,使用ln -s将sdc新建的journal分区连接到临时目录journal文件
- 卸载、删除临时目录
- 修改OSD分区的typecode为4fbd7e29-9d25-41b8-afd0-062c0ceff05d
- udevadm trigger强制内核触发设备事件
activate过程
/lib/udev/rules.d/目录下的两个rules文件60-ceph-by-parttypeuuid.rules、95-ceph-osd.rules
其实并不需要显式的调用activate这个命令。是因为prepare最后的udevadm trigger强制内核触发设备事件,udev event调用了ceph-disk trigger命令,分析该分区的typecode,是ceph OSD的数据分区,会自动调用ceph-disk activate /dev/sdb1。typecode为journal的分区则通过ceph-disk activate-journal来激活。
[root@ceph ~]# cat /lib/udev/rules.d/95-ceph-osd.rules
# OSD_UUID
ACTION=="add", SUBSYSTEM=="block", \
ENV{DEVTYPE}=="partition", \
ENV{ID_PART_ENTRY_TYPE}=="4fbd7e29-9d25-41b8-afd0-062c0ceff05d", \
OWNER:="ceph", GROUP:="ceph", MODE:="660", \
RUN+="/usr/sbin/ceph-disk --log-stdout -v trigger /dev/$name"
ACTION=="change", SUBSYSTEM=="block", \
ENV{ID_PART_ENTRY_TYPE}=="4fbd7e29-9d25-41b8-afd0-062c0ceff05d", \
OWNER="ceph", GROUP="ceph", MODE="660"
- 获取文件系统类型xfs、osd_mount_options_xfs、osd_fs_mount_options_xfs
- 挂载/dev/sdb1到临时目录
- 卸载、删除临时目录
- 启动OSD进程
源码结构
ceph-disk就两个文件
- __init__.py:空白初始化文件
- main.py:所有的ceph-disk命令操作在这个文件中,代码超5000行
类图
main.py所有类图: ceph-disk.png
Prepare类
Prepare是准备OSD的操作。两个子类PrepareBluestore、PrepareFilestore分别对应Bluestore、Filestore。目前Jewel10.2.7默认Filestore
PrepareData类
PrepareData是准备OSD的数据操作,磁盘数据分区、Journal分区。两个子类PrepareFilestoreData、PrepareBluestoreData
PrepareSpace类
PrepareSpace是用来获取磁盘分区大小。两个子类PrepareJournal、PrepareBluestoreBlock
DevicePartition类
DevicePartition是设备分区的加密模式。四个子类DevicePartitionCrypt、DevicePartitionCryptLuks、DevicePartitionCryptPlain、DevicePartitionMultipath对应四种不同的dmcrypt
OSD管理
创建OSD主要是分为prepare与activate两个操作。
main.py主函数
if __name__ == '__main__':
main(sys.argv[1:])
warned_about = {}
main函数
def main(argv):
# 命令行解析
args = parse_args(argv)
#设置日志级别
setup_logging(args.verbose, args.log_stdout)
if args.prepend_to_path != '':
path = os.environ.get('PATH', os.defpath)
os.environ['PATH'] = args.prepend_to_path + ":" + path
# 设置ceph-disk.prepare.lock、ceph-disk.activate.lock的目录/var/lib/ceph/tmp
setup_statedir(args.statedir)
# 设置配置文件目录/etc/ceph/
setup_sysconfdir(args.sysconfdir)
global CEPH_PREF_USER
CEPH_PREF_USER = args.setuser
global CEPH_PREF_GROUP
CEPH_PREF_GROUP = args.setgroup
# 执行子命令函数
if args.verbose:
args.func(args)
else:
main_catch(args.func, args)
parse_args函数解析子命令
def parse_args(argv):
parser = argparse.ArgumentParser(
'ceph-disk',
)
...
...
...
# prepare 子命令解析
Prepare.set_subparser(subparsers)
# activate 子命令解析
make_activate_parser(subparsers)
make_activate_lockbox_parser(subparsers)
make_activate_block_parser(subparsers)
make_activate_journal_parser(subparsers)
make_activate_all_parser(subparsers)
make_list_parser(subparsers)
make_suppress_parser(subparsers)
make_deactivate_parser(subparsers)
make_destroy_parser(subparsers)
make_zap_parser(subparsers)