openstack创建instance的流程

综述

启动一个新的instance涉及到很多openstack nova里面的组件

  • API server:处理客户端的请求,并且转发到cloud control
  • Cloud control:处理compute节点,网络控制节点,API server和scheduler中间连接
  • Scheduler:选择一个host去执行命令
  • compute worker:启动和停止实例,附加和删除卷 等操作
  • network controller:管理网络资源,分配固定IP,配置vlans

 

  1.API server将消息发送到Cloud Controller

  2. Authertication 保用户有权限,然后Cloud Controller将消息发送给Scheduler

  3. Scheduler caste 一个消息给一个选择好的host要求他启动一个实例

  4.compute worker(选择的那个host)获取到消息

  5.6.7.8 compute worker需要一个固定的ip去启动一个实例,所以向network controller发送消息

 

下面我将详细说明一下:

 

API

1.可以在dashboard网页上面进行

2.可以用命令行 euca-add-keypair        euca-run-instances

 

  用户的请求发送到nova-api,有两种方式

  第一种:通过openstack api (nova/api/servers.py 类 class Controller(object))create方法

    def create(self, req, body):

        """ Creates a new server for a given user """

        if 'server' in body:

            body['server']['key_name'] = self._get_key_name(req, body)

 

        extra_values = None

        extra_values, instances = self.helper.create_instance(

                req, body, self.compute_api.create)

 

  第二种:通过ec2 api (nova/api/cloud.py 中类 CloudController )

  调用def run_instances(self, context, **kwargs):

        ...

        (instances, resv_id) = self.compute_api.create(context,

            instance_type=instance_types.get_instance_type_by_name(

                kwargs.get('instance_type', None)),

        ...

 

最终调用的Compute API create():

  • 查看这种类型的instance是否达到最大值
  • 如果不存在安全组,就创建个
  • 生成MAC地址和hostnames
  • 给scheduler发送一个消息去运行这个实例

 

CAST

当然maxCount为1(默认值为1)的时候 调用RPC.cast方法向scheduler发送运行实例的消息

在openstack中通过RPC.cast来发送消息,消息的分发通过RabbitMQ。消息发送方(Compute API)往

topic exchange(scheduler topic)发送一个消息,消息消费者(Scheduler worker)从队列中获得消息,

cast调用不需要返回值。

[python] view plaincopyprint?

  1. def _schedule_run_instance(self,  
  2.         ...  
  3.         return rpc_method(context,  
  4.                 FLAGS.scheduler_topic,  
  5.                 {"method""run_instance",  
  6.                  "args": {"topic": FLAGS.compute_topic,  
  7.                           "request_spec": request_spec,  
  8.                           "admin_password": admin_password,  
  9.                           "injected_files": injected_files,  
  10.                           "requested_networks": requested_networks,  
  11.                           "is_first_time"True,  
  12.                           "filter_properties": filter_properties}})  

Scheduler

scheduler接收到消息,然后通过设定的scheduler策略选择一个目的host,如:zone scheduler

选择一个主机在特定的可获取的zone上面。最后发送一个cast消息到特定的host上面

[python] view plaincopyprint?

  1. def cast_to_compute_host(context, host, method, update_db=True, **kwargs):  
  2.     """Cast request to a compute host queue"""  
  3.   
  4.     if update_db:  
  5.         # fall back on the id if the uuid is not present   
  6.         instance_id = kwargs.get('instance_id'None)  
  7.         instance_uuid = kwargs.get('instance_uuid', instance_id)  
  8.         if instance_uuid is not None:  
  9.             now = utils.utcnow()  
  10.             db.instance_update(context, instance_uuid,  
  11.                     {'host': host, 'scheduled_at': now})  
  12.     rpc.cast(context,  
  13.             db.queue_get_for(context, 'compute', host),  
  14.             {"method": method, "args": kwargs})  
  15.     LOG.debug(_("Casted '%(method)s' to compute '%(host)s'") % locals())  

Compute

compute worker进程接收到消息执行方法(nova/compute/manager.py)

[python] view plaincopyprint?

  1. def _run_instance(self, context, instance_uuid,  
  2.                       requested_networks=None,  
  3.                       injected_files=[],  
  4.                       admin_password=None,  
  5.                       is_first_time=False,  
  6.                       **kwargs):  
  7.         """Launch a new instance with specified options."""  
  8.         context = context.elevated()  
  9.         try:  
  10.             instance = self.db.instance_get_by_uuid(context, instance_uuid)  
  11.             self._check_instance_not_already_created(context, instance)  
  12.             image_meta = self._check_image_size(context, instance)  
  13.             self._start_building(context, instance)  
  14.             self._notify_about_instance_usage(instance, "create.start")  
  15.             network_info = self._allocate_network(context, instance,  
  16.                                                   requested_networks)  
  17.             try:  
  18.                 block_device_info = self._prep_block_device(context, instance)  
  19.                 instance = self._spawn(context, instance, image_meta,  
  20.                                        network_info, block_device_info,  
  21.                                        injected_files, admin_password)  
  22.         ...  

  • 检查instance是否已经在运行
  • 分配一个固定的ip地址
  • 如果没有设置vlan和网桥,设置一下
  • 最后通过虚拟化的driver spawn一个instance

 

network controller

network_info = self._allocate_network(context, instance,

                                                  requested_networks)

调用network的API的allocate_for_instance方法

[python] view plaincopyprint?

  1. def allocate_for_instance(self, context, instance, **kwargs):  
  2.         """Allocates all network structures for an instance. 
  3.  
  4.         :returns: network info as from get_instance_nw_info() below 
  5.         """  
  6.         args = kwargs  
  7.         args['instance_id'] = instance['id']  
  8.         args['instance_uuid'] = instance['uuid']  
  9.         args['project_id'] = instance['project_id']  
  10.         args['host'] = instance['host']  
  11.         args['rxtx_factor'] = instance['instance_type']['rxtx_factor']  
  12.   
  13.         nw_info = rpc.call(context, FLAGS.network_topic,  
  14.                            {'method''allocate_for_instance',  
  15.                              'args': args})  
RPC.call 与RPC.cast最大的不同 就是call方法需要一个response

 

Spawn instance

接下来我要说的就是虚拟化的driver spawn instance,我们这里使用的是libvirt(nova/virt/libvirt/lconnection.py)

[python] view plaincopyprint?

  1. def spawn(self, context, instance, image_meta, network_info,  
  2.               block_device_info=None):  
  3.         xml = self.to_xml(instance, network_info, image_meta, False,  
  4.                           block_device_info=block_device_info)  
  5.         self.firewall_driver.setup_basic_filtering(instance, network_info)  
  6.         self.firewall_driver.prepare_instance_filter(instance, network_info)  
  7.         self._create_image(context, instance, xml, network_info=network_info,  
  8.                            block_device_info=block_device_info)  
  9.   
  10.         self._create_new_domain(xml)  
  11.         LOG.debug(_("Instance is running"), instance=instance)  
  12.         self._enable_hairpin(instance)  
  13.         self.firewall_driver.apply_instance_filter(instance, network_info)  
  14.   
  15.         def _wait_for_boot():  
  16.             """Called at an interval until the VM is running."""  
  17.             try:  
  18.                 state = self.get_info(instance)['state']  
  19.             except exception.NotFound:  
  20.                 LOG.error(_("During reboot, instance disappeared."),  
  21.                           instance=instance)  
  22.                 raise utils.LoopingCallDone  
  23.   
  24.             if state == power_state.RUNNING:  
  25.                 LOG.info(_("Instance spawned successfully."),  
  26.                          instance=instance)  
  27.                 raise utils.LoopingCallDone  
  28.   
  29.         timer = utils.LoopingCall(_wait_for_boot)  
  30.         return timer.start(interval=0.5, now=True)  

  • 通过libvirt xml文件,然后根据xml文件生成instance
  • 准备network filter,默认的fierwall driver是iptables 
  • image的创建(详细情况以后再介绍)
        def _create_image(self, context, instance, libvirt_xml, suffix='',

                      disk_images=None, network_info=None,

                      block_device_info=None):

         ...

  •    最后虚拟化driver的spawn()方法中调用driver 的creatXML()

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值