zoukankan      html  css  js  c++  java
  • OpenStack Nova启动实例流程

    1、概述

             启动一个新的实例,会涉及到OpenStack Nova中的多个组件:

    API服务器,接收用户端的请求,并且将其传递给云控制器。

    云控制器,处理计算节点、网络控制器、API服务器和调度器之前的通信。

    调度器,选择一个执行命令的主机。

    计算节点,管理计算实例:启动/终止实例,添加/删除卷…

    网络控制器,管理网络资源:分配固定IP地址,配置VLAN

     

             启动一个实例的流程如下:API服务器收到用户的run_instance命令,API服务器将消息传递给云控制器(1);对用户进行身份验证;云控制器将消息转发到调度器(2);调度器将消息扔给一个随机的一个主机,并通知它启动一个新实例(3);主机上的计算服务接收该消息;计算服务启动实例需要一个固定的IP,所以发送消息给网络控制器(5,6,7,8);之后,计算服务生产出一个新的实例。

     

    2、API

             可以使用OpenStack API或者EC2 API来启动新的实例。下面以EC2 API为例。添加一个新的key pair,并使用它启动一个新的m1.tiny类型的实例:

    cd /tmp/
    euca-add-keypair test > test.pem
    euca-run-instances -k test -t m1.tiny ami-tiny
    

             调用文件api/ec2/cloud.py中的run_instances()函数,在该函数中会调用文件compute/API.py中的compute API的create函数:

    def run_instances(self, context, **kwargs):
      ...
      instances = self.compute_api.create(context,
                instance_type=instance_types.get_by_type(
                    kwargs.get('instance_type', None)),
                image_id=kwargs['image_id'],
                ...
    

             compute API  create函数流程如下:

    检查此种类型的实例数是否已经达到最大值;

    如果不存在安全组,则创建一个;

    为新的实例创建MAC地址和主机名;

    发送消息给调度器以运行实例。

     

    3、消息投递

             发送消息给调度器,在OpenStack中,这种类型的消息传递定义为RPC投递,使用RabbitMQ进行传递。消息生产者(API)发送消息到一个topic exchange(scheduler  topic)。消费者(调度器)从队列中接收消息。因为是消息投递,所以无需响应消息。

             下面是消息投递的代码:

    LOG.debug(_("Casting to scheduler for %(pid)s/%(uid)s's"
            " instance %(instance_id)s") % locals())
    rpc.cast(context,
             FLAGS.scheduler_topic,
             {"method": "run_instance",
              "args": {"topic": FLAGS.compute_topic,
                       "instance_id": instance_id,
                       "availability_zone": availability_zone}})

           可见在消息投递时使用了scheduler topic,并且希望调度器在发送消息时,使用compute topic。

     

    4、调度器

             调度器接收消息,并且发”run_instance”消息给随机的主机。这里使用的是chance 调度器。还有其他类型的调度器,比如zone调度器(在一个特定的可用区域内随机选择主机)、简单调度器(选择最小负载的主机)。现在主机已经选择好了,接下来就是发送消息给该主机的计算服务了。

    rpc.cast(context,
             db.queue_get_for(context, topic, host),
             {"method": method,
              "args": kwargs})
    LOG.debug(_("Casting to %(topic)s %(host)s for %(method)s") % locals())
    

    5、计算节点

             计算节点接收消息,然后调用compute/manager.py中的run_instance方法:

    def run_instance(self, context, instance_id, **_kwargs):
      """Launch a new instance with specified options."""
      ...
    

             run_instance()的流程如下:

    检查实例是否已经运行;

    分配固定的ip低值;

    设置一个VLAN或者桥;

    使用virtualization driver产生一个实例。

     

    6、调用网络控制器

             在分配固定IP时,会用到RPC调用。RPC调用不同于RPC投递,它使用topic.hostexchange,表明它的目的地为特定主机,而且RPC调用需要响应。

     

    7、产生实例

             下面就是由virtualization driver执行产生实例的过程。以libvirt为例,代码在virt/libvirt_conn.py中。

             启动实例的第一件事就是创建libvirt xml。方法to_xml用来生成xml的内容。下面是我们实例的XML文件:

    <domain type='qemu'>
        <name>instance-00000001</name>
        <memory>524288</memory>
        <os>
            <type>hvm</type>
            <kernel>/opt/novascript/trunk/nova/..//instances/instance-00000001/kernel</kernel>
            <cmdline>root=/dev/vda console=ttyS0</cmdline>
            <initrd>/opt/novascript/trunk/nova/..//instances/instance-00000001/ramdisk</initrd>
        </os>
        <features>
            <acpi/>
        </features>
        <vcpu>1</vcpu>
        <devices>
            <disk type='file'>
                <driver type='qcow2'/>
                <source file='/opt/novascript/trunk/nova/..//instances/instance-00000001/disk'/>
                <target dev='vda' bus='virtio'/>
            </disk>
            <interface type='bridge'>
                <source bridge='br100'/>
                <mac address='02:16:3e:17:35:39'/>
                <!--   <model type='virtio'/>  CANT RUN virtio network right now -->
                <filterref filter="nova-instance-instance-00000001">
                    <parameter name="IP" value="10.0.0.3" />
                    <parameter name="DHCPSERVER" value="10.0.0.1" />
                    <parameter name="RASERVER" value="fe80::1031:39ff:fe04:58f5/64" />
                    <parameter name="PROJNET" value="10.0.0.0" />
                    <parameter name="PROJMASK" value="255.255.255.224" />
                    <parameter name="PROJNETV6" value="fd00::" />
                    <parameter name="PROJMASKV6" value="64" />
                </filterref>
            </interface>
    
            <!-- The order is significant here.  File must be defined first -->
            <serial type="file">
                <source path='/opt/novascript/trunk/nova/..//instances/instance-00000001/console.log'/>
                <target port='1'/>
            </serial>
    
            <console type='pty' tty='/dev/pts/2'>
                <source path='/dev/pts/2'/>
                <target port='0'/>
            </console>
    
            <serial type='pty'>
                <source path='/dev/pts/2'/>
                <target port='0'/>
            </serial>
    
        </devices>
    </domain>

             使用的虚机管理程序为qemu,客户机的内存为524字节,客户端OS从存储于主机OS中的内核和initrd启动。

             分配各客户机的虚拟CPU个数为1. 电源管理中使能了ACPI。还定义了多个设备:

             磁盘镜像为主机OS上的一个文件,使用qcow2驱动器,qcow2是一种qemu磁盘镜像的写时复制格式;

             网络接口是客户机可见的桥,定义了一系列网络过滤器参数,比如IP地址10.0.0.3意味着始终使用该地址作为源IP地址;

             日志文件,所有发送给字符设备的数据全部写入console.log中;

             伪终端,virsh控制台可用于连接本地串口。

     

             接下来是网络过滤器的配置。默认使用的防火墙driver是iptables。规则由IptablesFirewallDriver类的apply_ruleset方法定义。下面是本实例的防火墙规则:

    *filter
    ...
    :nova-ipv4-fallback - [0:0]
    :nova-local - [0:0]
    :nova-inst-1 - [0:0]
    :nova-sg-1 - [0:0]
    -A nova-ipv4-fallback -j DROP
    -A FORWARD -j nova-local
    -A nova-local -d 10.0.0.3 -j nova-inst-1
    -A nova-inst-1 -m state --state INVALID -j DROP
    -A nova-inst-1 -m state --state ESTABLISHED,RELATED -j ACCEPT
    -A nova-inst-1 -j nova-sg-1
    -A nova-inst-1 -s 10.1.3.254 -p udp --sport 67 --dport 68
    -A nova-inst-1 -j nova-ipv4-fallback
    -A nova-sg-1 -p tcp -s 10.0.0.0/27 -m multiport --dports 1:65535 -j ACCEPT
    -A nova-sg-1 -p udp -s 10.0.0.0/27 -m multiport --dports 1:65535 -j ACCEPT
    -A nova-sg-1 -p icmp -s 10.0.0.0/27 -m icmp --icmp-type 1/65535 -j ACCEPT
    COMMIT
    

             定义了防火墙规则之后,就是创建镜像,由方法_create_image()处理:

    def _create_image(self, inst, libvirt_xml, suffix='', disk_images=None):
      ...
    

             在该方法中,会根据上面的XML创建libvirt.xml;复制虚拟机管理程序要使用的randisk、initrd和磁盘镜像;如果使用flat网络管理器,则会将一个网络配置植入到客户端的OS镜像中。本例中使用VLAN管理器。

             实例的SSH key植入到镜像中,本过程是调用disk.inject_data方法:

    disk.inject_data(basepath('disk'), key, net,
                     partition=target_partition,
                     nbd=FLAGS.use_cow_images)
    

             basepath('disk')表示实例的磁盘镜像在主机OS中的位置,key是SSH key字符串,在我们的例子中不设置网络,因为不需要植入网络配置。因为使用的是内核镜像,所以没有分区,否则的话会使用分区的磁盘镜像。在inject_data内部:

             第一件事就是链接镜像到一个设备,这发生在_link_device中:

    device = _allocate_device()
    utils.execute('sudo qemu-nbd -c %s %s' % (device, image))
    # NOTE(vish): this forks into another process, so give it a chance
    #             to set up before continuuing
    for i in xrange(10):
        if os.path.exists("/sys/block/%s/pid" % os.path.basename(device)):
            return device
        time.sleep(1)
    raise exception.Error(_('nbd device %s did not show up') % device)
    

             _allocate_device()返回下一个可用的ndb设备:/dev/ndbx,其中x在0到15之间。qemu-nbd是一个QEMU磁盘网络块设备服务器。一旦该过程返回,则得到了设备,比如/dev/ndb0.

             对该设备禁用文件系统检查,这里的mapped_device是”/dev/ndb0”。

    out, err = utils.execute('sudo tune2fs -c 0 -i 0 %s' % mapped_device)

             将该文件系统挂载到临时目录,并将SSH KEY添加到authorized_keys文件中。

    sshdir = os.path.join(fs, 'root', '.ssh')
    utils.execute('sudo mkdir -p %s' % sshdir)  # existing dir doesn't matter
    utils.execute('sudo chown root %s' % sshdir)
    utils.execute('sudo chmod 700 %s' % sshdir)
    keyfile = os.path.join(sshdir, 'authorized_keys')
    utils.execute('sudo tee -a %s' % keyfile, '
    ' + key.strip() + '
    ')
    

             上面的代码中,fs就是临时目录。

             最后,unmount文件系统,删除设备。这就结束了镜像的创建和安装。

     

             在虚拟机化驱动器中的spawn方法中的下一步就是使用驱动器的createXML()加载实例,然后就是应用防火墙规则。


    原文:http://www.laurentluce.com/posts/openstack-nova-internals-of-instance-launching/

  • 相关阅读:
    windwos8.1英文版安装SQL2008 R2中断停止的解决方案
    indwows8.1 英文版64位安装数据库时出现The ENU localization is not supported by this SQL Server media
    Server Tomcat v7.0 Server at localhost was unable to start within 45 seconds
    SQL数据附加问题
    eclipse,myeclipse中集合svn的方法
    JAVA SSH 框架介绍
    SSH框架-相关知识点
    SuperMapRealSpace Heading Tilt Roll的理解
    SuperMap iserver manage不能访问本地目的(IE9)
    Myeclipse中js文件中的乱码处理
  • 原文地址:https://www.cnblogs.com/gqtcgq/p/7247109.html
Copyright © 2011-2022 走看看