前面已经对nova创建instance和其他操作讲了不少,回到detail上,
在nova中,api,conductor,scheduler,compute都有对应的manager,在cmd包中启动各种service时,除了api是WSGI service,其他的都是Service,
更直接一点儿的话启动的是RPC的service,但这些服务中,compute的地位是不一样的,特别是启动时,做了很多工作,下面从细节上trace一下看看。
至于启动rpc service时候rpc server对应的target是什么,收到message处理的逻辑是什么,之前都讲过,主要看三个动作:
1. self.manager.init_host()
2. self.manager.pre_start_hook()
3. self.manager.post_start_hook()
对nova-compute来说这里manage自然是compute-manager,先看init_host:
self.driver.init_host(host=self.host)
#self.driver默认情况为libvirt.LibvirtDriver,因此执行libvirt driver的init_host方法,其他的driver也需要执行对应的init_host, 传入的参数
host=self.host,host从nova.netconf中读出,在compute node则是读取配置文件中的host,而driver的init_host又执行了一大串动作:
initialize:注册driver的error handler,并将libvirt产生的event进行dispatch并处理,即不同的event对应不同的处理方式,比如连接失败之类的
_do_quality_warnings:连接libvirt driver得到cpu feature,分析cpu架构,若配置的virt type不是qemu或者kvm,或者cpu 的arch不是“arch.I686, arch.X86_64”,
给出警告的log
接下来对不同的virt type做不同的处理,若是lxc则判断容器是否有user/group 的namespace,若不是kvm则不进行kvm 加速,检查libvirt version的版本,不能
过低等。
context = nova.context.get_admin_context()
#得到admin的context,user/project都是null,要的是admin context去objects里面做一些数据库的查询
instances = objects.InstanceList.get_by_host(
context, self.host, expected_attrs=['info_cache'])
#得到host中包含的instance list,如果是boot from image,只有临时数据,临时数据之类的都会存在coompute node上,boot from volume则存在volume所在处,
其临时数据?
if CONF.defer_iptables_apply:
self.driver.filter_defer_apply_on()
#执行firewall driver的filter_defer_apply_on, 对LibVirtDriver来说,默认的是IptablesFirewallDriver, 最终执行:
self.iptables.defer_apply_on(), self.iptables=linux_net.iptables_manager
只是将iptables_apply_deferred置为True,置为True之后,推迟使用当前iptable rule(当L3 driver使用linux_net作为backend时候,会调到
linux_net.metadata_forward(),应用防火墙规则,若这里defer了的话,就暂时不apply了)
self.init_virt_events()
#若配置CONF.workarounds.handle_virt_lifecycle_events, 注册对virt driver的event listener
try:
# checking that instance was not already evacuated to other host
self._destroy_evacuated_instances(context)
#这一段逻辑比较绕,先获得本机现有的所有instance(virt driver在本机获得),然后判断每个instance现在的host还是否是当前的host,如果不是,
但是instance的task state属于迁移/resize相关的状态,则不删除该instance; 如果设置CONF.workarounds.destroy_after_evacuate是False,警告,修改为True
之后重启方可;否则获得instance的网络/block device/共享存储,之后删除该instance
for instance in instances:
self._init_instance(context, instance)
#初始化所有的instance,这个判断的种类非常多, 很多种情况,针对不对情况,初始化虚机。
finally:
if CONF.defer_iptables_apply:
self.driver.filter_defer_apply_off()
self._update_scheduler_instance_info(context, instances)
#最后,应用iptables,并执行nova.scheduler.client.query.SchedulerQueryClient.update_instance_info,即通过scheduler去update instance(
对应HostManager中的_instance_info)信息
再来看看pre_start_hook:
只有一句:self.update_available_resource(nova.context.get_admin_context()),注意到这个方法是period_task,
想起ironic里面的period_task:@periodic_task.periodic_task(spacing=CONF.update_resources_interval)
compute_nodes_in_db = self._get_compute_nodes_in_db(context, use_slave=True)
#首先根据self.host拿到host中的所有compute_node(可能使用虚机做hypervisor?不然一个host如何多个compute node?),
nodenames = set(self.driver.get_available_nodes())
#拿到hypervisor对应的host name,然后根据host,driver,hostname对每个node得到一个resource tracker:
rt = self._get_resource_tracker(nodename)
rt.update_available_resource(context)
在resource tracker中,根据前面传入的driver,获得实际available resource(使用libvirt拿到一系列的值),这些数据包括vcpu,memory,local_gb,
vcpu_used等等,使用log记录(report),最重要的是执行_update_available_resource(注意前面有下划线),这里的最重要的步骤是:
_init_compute_node:
#如果compute不存在数据库中,就创建它,所以如果新加入的节点,经过一段时间或者重启nova-compute之后会自检测出来
主要更新的信息包括:
self.stats = importutils.import_object(CONF.compute_stats_class)
self.tracked_instances = {}
self.tracked_migrations = {}
最后看post_start_hook:
不是所有的manager都实现了,cellmanager实现了一些功能