Openstack源码阅读的正确姿势

域名2025-11-05 13:57:444

1. 谈谈Openstack的码阅发展历史

OpenStack是一个面向IaaS层的云管理平台开源项目,用于实现公有云和私有云的正确姿势部署及管理。最开始Openstack只有两个组件,码阅分别为提供计算服务的正确姿势Nova项目以及提供对象存储服务的Swift,其中Nova不仅提供虚拟机服务,码阅还包含了网络服务、正确姿势块存储服务、码阅镜像服务以及裸机管理服务。正确姿势之后随着项目的码阅不断发展,从Nova中拆分成多个独立的正确姿势项目各自提供不同的服务,如拆分为Cinder项目提供块存储服务,码阅拆分为Glance项目,正确姿势提供镜像服务,码阅nova-network则是正确姿势neutron的前身,裸机管理也从Nova中分离出来为Ironic项目。码阅最开始容器服务也是由Nova提供支持的,作为Nova的driver之一来实现,而后迁移到Heat,到现在已经分离成独立的项目Magnum,b2b供应网后来Magnum主要提供容器编排服务,单纯的容器服务由Zun项目负责。最开始Openstack并没有认证功能,从E版开始才加入认证服务Keystone,至此Openstack 6个核心服务才终于聚齐了。

Keystone 认证服务。 Glance 镜像服务。 Nova 计算服务。 Cinder 块存储服务。 Neutorn 网络服务。 Swift 对象存储服务。

E版之后,在这些核心服务之上,又不断涌现新的服务,如面板服务Horizon、服务编排服务Heat、数据库服务Trove、文件共享服务Manila、大数据服务Sahara以及前面提到的Magnum等,这些服务几乎都依赖于以上的核心服务。比如Sahara大数据服务会先调用Heat模板服务,Heat又会调用Nova创建虚拟机,调用Glance获取镜像,调用Cinder创建数据卷,调用Neutron创建网络等。还有一些项目围绕Openstack部署的项目,比如Puppet-openstack、Kolla、亿华云TripleO、Fuel等项目。

截至现在(2016年11月27日),Openstack已经走过了6年半的岁月,***发布的版本为第14个版本,代号为Newton,Ocata版已经处在快速开发中。

Openstack服务越来越多、越来越复杂,并且不断变化发展。以Nova为例,从最开始使用nova-conductor代理数据库访问增强安全性,引入objects对象模型来支持对象版本控制,现在正在开发Cell项目来支持大规模的集群部署以及将要分离的Nova-EC2项目,截至到现在Nova包含nova-api、nova-conductor、nova-scheduler、nova-compute、nova-cell、nova-console等十多个组件。这么庞大的分布式系统需要深刻理解其工作原理,理清它们的交互关系非常不容易,尤其对于新手来说。

2.工欲善其事,必先利其器

由于Openstack使用python语言开发,而python是动态类型语言,参数类型不容易从代码中看出,云服务器提供商因此首先需要部署一个allinone的Openstack开发测试环境,建议使用RDO部署:Packstack quickstart,当然乐于折腾使用devstack也是没有问题的。

其次需要安装科学的代码阅读工具,图形界面使用pycharm没有问题,不过通常在虚拟机中是没有图形界面的,***vim,需要简单的配置使其支持代码跳转和代码搜索,可以参考我的vim配置GitHub - int32bit/dotfiles: A set of vim, zsh, git, and tmux configuration files。

掌握python的调试技巧,推荐pdb、ipdb、ptpdb,其中ptpdb***用,不过需要手动安装。打断点前需要注意代码执行时属于哪个服务组件,nova-api的代码,你跑去nova-compute里打断点肯定没用。另外需要注意打了断点后的服务必须在前端运行,不能在后台运行,比如我们在nova/compute/manager.py中打了断点,我们需要kill掉后台进程:

systemctl stop openstack-nova-compute 

然后直接在终端运行nova-compute即可。

su -c nova-compute nova 

3 .教你阅读的正确姿势

学习Openstack的***步骤是:

看文档 部署allineone 使用之 折腾之、怒斥之 部署多节点 深度使用、深度吐槽 阅读源码 混社区,参与社区开发

阅读源码的首要问题就是就要对代码的结构了然于胸,需要强调的是,Openstack项目的目录结构并不是根据组件划分的,而是根据功能划分的,以Nova为例,compute目录并不是一定在nova-compute节点上运行的代码,而主要是和compute相关(虚拟机操作相关)的功能实现,同样的,scheduler目录代码并不全在scheduler服务节点运行,但主要是和调度相关的代码。好在目录结构并不是完全混乱的,它是有规律的。

通常一个服务的目录都会包含api.py、rpcapi.py、manager.py,这个三个是最重要的模块。

api.py: 通常是供其它组件调用的库。换句话说,该模块通常并不会由本模块调用。比如compute目录的api.py,通常由nova-api服务的controller调用。 rpcapi.py:这个是RPC请求的封装,或者说是RPC实现的client端,该模块封装了RPC请求调用。 manager.py: 这个才是真正服务的功能实现,也是RPC的服务端,即处理RPC请求的入口,实现的方法通常和rpcapi实现的方法对应。

前面提到Openstack项目的目录结构是按照功能划分的,而不是服务组件,因此并不是所有的目录都能有对应的组件。仍以Nova为例:

cmd:这是服务的启动脚本,即所有服务的main函数。看服务怎么初始化,就从这里开始。 db: 封装数据库访问,目前支持的driver为sqlalchemy。 conf:Nova的配置项声明都在这里。 locale: 本地化处理。 image: 封装Glance调用接口。 network: 封装网络服务接口,根据配置不同,可能调用nova-network或者neutron。 volume: 封装数据卷访问接口,通常是Cinder的client封装。 virt: 这是所有支持的hypervisor驱动,主流的如libvirt、xen等。 objects: 对象模型,封装了所有实体对象的CURD操作,相对以前直接调用db的model更安全,并且支持版本控制。 policies: policy校验实现。 tests: 单元测试和功能测试代码。

根据进程阅读源码并不是什么好的实践,因为光理解服务如何初始化、如何通信、如何发送心跳等就不容易,各种高级封装太复杂了。而我认为比较好的阅读源码方式是追踪一个任务的执行过程,比如追踪启动一台虚拟机的整个流程。

不管任何操作,一定是先从API开始的,RESTFul API是Openstack服务的唯一入口,也就是说,阅读源码就从api开始。而api组件也是根据实体划分的,不同的实体对应不同的controller,比如servers、flavors、keypairs等,controller通常对应有如下方法:

index: 获取资源列表,一般对应RESTFul API的URL为“GET /resources”,如获取虚拟机的列表API为“GET /servers”。 get: 获取一个资源,比如返回一个虚拟机的详细信息API为”GET /servers/uuid“。 create: 创建一个新的资源,通常对应为POST请求。比如创建一台虚拟机为 “POST /servers”, 当然POST的数据为虚拟机信息。 delete: 删除指定资源,通常对应DELETE请求,比如删除一台虚拟机为“DELETE/servers/uuid”。 update: 更新资源信息,通常对应为PUT请求,比如更新虚拟机资源为”PUT /servers/uuid,body为虚拟机数据。

了解了代码结构,找到了入口,再配合智能跳转,阅读源码势必事半功倍。如果有不明白的地方,随时可以加上断点单步调试。

4.案例分析

接下来以创建虚拟机为例,根据组件划分,一步步分析整个工作流程以及操作序列。请再次回顾下api.py、rpcapi.py、manager.py以及api下的controller结构,否则阅读到后面会越来越迷糊。

S1 nova-api

入口为nova/api/openstack/compute/servers.py的create方法,该方法检查了一堆参数以及policy后,调用compute_api的create方法,这里的compute_api即前面说的nova/compute/api.py模块的API。

compute_api会创建数据库记录、检查参数等,然后调用compute_task_api的build_instances方法,compute_task_api即conductor的api.py。

conductor的api并没有执行什么操作,直接调用了conductor_compute_rpcapi的build_instances方法,该方法即时conductor RPC调用api,即nova/conductor/rpcapi.py模块,该方法除了一堆的版本检查,剩下的就是对RPC调用的封装,代码只有两行:

cctxt = self.client.prepare(version=version)  cctxt.cast(context, build_instances, **kw) 

其中cast表示异步调用,build_instances是远程调用的方法,kw是传递的参数。参数是字典类型,没有复杂对象结构,因此不需要特别的序列化操作。

截至到现在,虽然目录由api->compute->conductor,但仍在nova-api进程中运行,直到cast方法执行,该方法由于是异步调用,因此nova-api不会等待远程方法调用结果,直接返回结束。

S2 nova-conductor

由于是向nova-conductor发起的RPC调用,而前面说了接收端肯定是manager.py,因此进程跳到nova-conductor服务,入口为nova/conductor/manager.py的build_instances方法。

该方法首先调用了_schedule_instances方法,该方法调用了scheduler_client的select_destinations方法,scheduler_client和compute_api以及compute_task_api都是一样对服务的client调用(即api.py),不过scheduler没有api.py,而是有个单独的client目录,实现在client目录的__init__.py模块,这里仅仅是调用query.py下SchedulerQueryClient的select_destinations实现,然后又很直接的调用了scheduler_rpcapi的select_destinations方法,终于又到了RPC调用环节。

毫无疑问,RPC封装同样是在scheduler的rpcapi中实现。该方法RPC调用代码如下:

return cctxt.call(ctxt, select_destinations, **msg_args) 

注意这里调用的call方法,即同步调用,此时nova-conductor并不会退出,而是堵塞等待直到nova-scheduler返回。

S3 nova-scheduler

同理找到scheduler的manager.py模块的select_destinations方法,该方法会调用driver对应的方法,这里的driver其实就是调度算法实现,由配置文件决定,通常用的比较多的就是filter_scheduler,对应filter_scheduler.py模块,该模块首先通过host_manager拿到所有的计算节点信息,然后通过filters过滤掉不满足条件的计算节点,剩下的节点通过weigh方法计算权值,***选择权值高的作为候选计算节点返回。nova-scheduler进程结束。

S4 nova-condutor

回到scheduler/manager.py的build_instances方法,nova-conductor等待nova-scheduler返回后,拿到调度的计算节点列表,然后调用了compute_rpcapi的build_and_run_instance方法。看到xxxrpc立即想到对应的代码位置,位于compute/rpcapi模块,该方法向nova-compute发起RPC请求:

cctxt.cast(ctxt, build_and_run_instance, ...) 

可见发起的是异步RPC,因此nova-conductor结束,紧接着终于轮到nova-compute登场了。

S5 nova-compute

到了nova-compute服务,入口为compute/manager.py,找到build_and_run_instance方法,该方法调用了driver的spawn方法,这里的driver就是各种hypervisor的实现,所有实现的driver都在virt目录下,入口为driver.py,比如libvirt driver实现对应为virt/libvirt/driver.py,找到spawn方法,该方法拉取镜像创建根磁盘、生成xml文件、define domain,启动domain等。***虚拟机完成创建。nova-compute服务结束。

一张图总结以上是创建虚拟机的各个服务的交互过程以及调用关系,需要注意的是,所有的数据库操作,比如instance.save()以及update操作,如果配置use_local为false,则会向nova-conductor发起RPC调用,由nova-conductor代理完成数据库更新,而不是由nova-compute直接访问数据库,这里的RPC调用过程在以上的分析中省略了。

整个流程用一张图表示为:

【本文是专栏作者“付广平”的原创文章,如需转载请通过获得联系】

戳这里,看该作者更多好文

本文地址:http://www.bzuk.cn/html/340d33699323.html
版权声明

本文仅代表作者观点,不代表本站立场。
本文系作者授权发表,未经许可,不得转载。

全站热门

Linux下最好用的pdf查看器, foxit reader,adobe reader 不是,应该是Okular复制代码代码如下:2 注释假如安装完成后中文显示有问题的话,可按如下试试,假如没有问题可跳过。复制代码代码如下:假如还不行,则再次输入复制代码代码如下:假如依然不行,则可能是因为某些 pdf 文件没有明确指明字体,系统就会默认用英文字体来显示,于是导致中文字体显示失败!复制代码代码如下:把复制代码代码如下:改为复制代码代码如下:假如修改后的字体 monospace 依然不能显示,则可以改为 宋体 来显示!优点: 兼容多种格式包括 PDFs, EPUB ebooks, CBR and CBZ comic books, DjVu, images…能对 PDF进行多种标记注解: 评论, 高亮, 画图, 贴图(类似加上水印),导出文本, 加入书签等等缺点:由于是KDE的程序,所以非KDE用户需要安装其他依赖(笔者mint14上安装消耗了170MB)。它还不是pdf编辑器,所以对编辑功能有需求的话,转到LibreOffice或其他的软件

通用富士的品质与性能(全方位解读通用富士的关键优势与卓越表现)

华硕R513C笔记本电脑的综合评价(性能卓越,外观精致,是值得推荐的选择)

小版手机(探索小版手机的功能和使用体验)

一. VIM高亮进入vim后,在普通模式下输入如下命令,开启php代码高亮显示   :syntax enable   :source $VIMRUNTIME/syntax/php.vim 二. VI常用命令_______________________________________________________一般模式                           光标移动__________________________________________________________h 或 向左方向键                    光标向左移动一个字符j 或 向下方向键                    光标向下移动一个字符k 或 向上方向键                    光标向上移动一个字符l 或 向右方向键                    光标向右移动一个字符Ctrl + f                           屏幕向前翻动一页(常用)Ctrl + b                           屏幕向后翻动一页(常用)Ctrl + d                           屏幕向前翻动半页Ctrl + u                           屏幕向后翻动半页+                                  光标移动到非空格符的下一列-                                  光标移动到非空格符的上一列n                           接下数字后再按空格键,光标会向右移动这一行的                                   n个字符,例如20,则光标会向右移动20个字符0                                  (这是数字0) 移动到这一行的第一个字符处(常用)$                                  移动到这一行的最后一个字符处(常用)H                                  光标移动到这个屏幕最上方的那一行M                                  光标移动到这个屏幕中央的那一行L                                  光标移动到这个屏幕最下方的那一行G                                  移动到这个文件的最后一行(常用)nG                                 移动到这个文件的第n行.例如20G,则会移动到这个文件的                                   第20行(可配合:set nu)n                           光标向下移动n行(常用)________________________________________________________________一般模式                           查找替换________________________________________________________________/word                              在光标之前查找一个名为word的字符串 word                              在光标之前查找一个名为的word字符串:n1,n2s/word1/word2/g              在第n1与n2行之间查找word1这个字符串,并将该字符串替换                                   为word2(常用):1,$s/word1/word2/g                从第一行到最后一行查找word1字符串,并将该字符串替换                                   为word2(常用):1,$s/word1/word2/ge               从第一行到最后一行查找word1字符串,并将该字符串替换                                   为word2,且在替换前显示提示符让用户确认(confirm)(常用)__________________________________________________________________一般模式                           删除 复制与粘贴__________________________________________________________________x,X                                x为向后删除一个字符,X为向前删除一个字符(常用)nx                                 向后删除n个字符dd                                 删除光标所在的那一整行(常用)ndd                                删除光标所在行的向下n行,例如,20dd则是删除20行(常用)d1G                                删除光标所在行到第一行的所有数据dG                                 删除光标所在行到最后一行的所有数据yy                                 复制光标所在行(常用)nyy                                复制光标所在行的向下n行,例如,20yy则是复制20行(常用)y1G                                复制光标所在行到第一行的所有数据yG                                 复制光标所在行到最后一行的所有数据p,P                                p为复制的数据粘贴在光标下一行,P则为粘贴在光标上一行(常用)J                                  将光标所在行与下一行的数据结合成一行u                                  恢复前一个动作(常用) ____________________________________________________________________编辑模式                          ___________________________________________________________________I,I                                插入:在当前光标所在处插入输入的文字,已存在的字符会向后                                   退(常用)a,A                                添加:由当前光标所在处的下一个字符开始输入,已存在的字符                                   会向后退(常用)o,O                                插入新的一行:从光标所在处的下一行行首开始输入字符(常用)r,R                                替换:r会替换光标所指的那一个字符:R会一直替换光标所指的                                   文字,直到按下Esc为止(常用)Esc                                退出编辑模式,回到一般模式(常用) ___________________________________________________________________命令行模式                          ___________________________________________________________________ :w                                 将编辑的数据写入硬盘文件中(常用):w!                                若文件属性为只读,强制写入该文件:q                                 退出vi(常用):q!                                若曾修改过文件,又不想保存,使用!为强制退出不保存文件:wq                                保存后退出,若为:wq!,则为强制保存后退出(常用):w [filename]                      将编辑数据保存为另一个文件(类似另存新文档):r [filename]                      在编辑的数据中,读入另一个论据的数据,亦即将filename这                                   个文件内容加到光标所在行的后面:set nu                            显示行号,设定之后,会在每一行的前面显示该行的行号:set nonu                          与set nu相反,为取消行号n1,n2 w [filename]                 将n1到n2的内容保存为filename 这个文件

FD2796GF(探索FD2796GF的未来前景及其在科技行业的性影响)

金立金刚2手机使用体验报告(深入评析金立金刚2手机的性能、功能和用户体验)

尼康85mm1.8g镜头——专业摄影的选择(一款性价比高的人像摄影利器)

友情链接

滇ICP备2023006006号-33