nova-compute负责管理虚拟机,单独运行于承载分配虚拟机的主机之上。nova-compute通过消息队列获取任务然后执行。
典型的业务流程是:nova-compute从消息队列获取分发给自己的消息,消息队列的消息体里定义了一系列的key/value值对,nova-compute需要对消息体进行解析。消息体中有个很重要的key是method,该key对应的value指明nova-compute需要完成的任务。以创建虚拟机为例,method对应的value为run_instance。run_instance指令要求nova-compute创建虚拟机。
首先nova-compute从Glance将虚拟机模板镜像下载到/var/lib/nova/instances/_base/文件夹下,文件名即为image,在对象存储上所对应的image_id,形如:
这里存储的还是原始模板镜像文件。随后,nova-compute会以这个镜像为模板,创建一个虚拟机真正使用的磁盘映像文件。以KVM作为Hypervisor举例,映像文件使用qcow2文件格式。
qemu-img create -f qcow1--o cluster_size=2M, backing_file=/var/lib/nova/ instances/_base/644208f3 /var/lib/nova/instances/instance-00000033/disk
如例所示,以644208f3这个镜像文件为模板,通过qemu-img程序创建虚拟机磁盘文件/var/lib/nova/instances/instance-00000033/disk,其中instance-00000033是nova-compute动态创建的目录,存放虚拟机实例相关信息,instance-00000033本身也是该虚拟机实例的instance-id。
随后nova-compute会向/var/lib/nova/instances/instance-00000033/disk这个虚拟机文件注入SSH登录的公钥,以支持虚拟机启动后通过私钥方式登录虚拟机。注入SSH公钥的步骤如下:
1)连接到虚拟机文件/var/lib/nova/instances/instance-00000033/disk,将之虚拟成字符设备。
sudo qemu-nbd -c /dev/nbd15 /var/lib/nova/instances/ instance-00000033/disk
2)挂载文件系统。
sudo tune2fs -c 0 -i 0 /dev/nbd15sudo mount /dev/nbd15 /tmp/tmpLoFGru
3)建立SSH登录环境目录。
sudo mkdir -p /tmp/tmpLoFGru/root/.sshsudo chown root /tmp/tmpLoFGru/root/.sshsudo chmod 700 /tmp/tmpLoFGru/root/.ssh
4)将公钥写入SSH的配置文件/tmp/tmpLoFGru/root/.ssh/authorized_keys。
sudo tee -a /tmp/tmp4kabqd/root/.ssh/authorized_keys
5)释放资源。
sudo umount /dev/nbd15rmdir /tmp/tmpLoFGrusudo qemu-nbd -d /dev/nbd15
通过该样例过程,可了解nova-compute是如何向虚拟机注入数据的。如果是向虚拟机注入固定IP,也是相同思路,无非就是挂接虚拟机的磁盘文件到文件系统上,修改其内部的网络配置文件。从H版本开始,这样的直接注入方式不是默认方式,Nova又引入了ConfigDrive机制和metadata服务,来实现针对虚拟机内部数据的修改。
对于AMI格式的虚拟机镜像,AMI格式的镜像只包含一个根文件系统。Kernel和ramdisk是单独另外存放的,不存放在镜像里面。为此,nova-compute也需要将Kernel和ramdisk从Glance上下载下来,复制到/var/lib/nova/instances/instance-00000033目录下,nova-compute会自动创建一个libvirt.xml文件,该文件即是该虚拟机实例的配置文件,nova-compute通过libvirt接口调用KVM,KVM会使用libvirt.xml虚拟机配置文件来启动虚拟机实例。最终,虚拟机运行实例动态目录下的文件如下:
[email protected]:/var/lib/nova/instances/instance-00000033# lsconsole.log disk disk.local kernel libvirt.xml [email protected]:/var/lib/nova/instances/instance-00000033#
虚拟机启动参数文件libvirt.xml样例如下:
<domain type=/'kvm/'> <name>instance-00000033</name> <memory>2097152</memory> <os> <type>hvm</type> <kernel>/var/lib/nova/instances/instance-00000033/kernel</kernel><cmdline>root=/dev/vda console=ttyS0</cmdline><initrd>/var/lib/nova/instances/instance-00000033/ramdisk</initrd> </os> <features> <acpi/> </features> <vcpu>1</vcpu> <devices><disk type=/'file/'> <driver type=/'qcow2/'/> <source file=/'/var/lib/nova/instances/instance-00000033/disk/'/> <target dev=/'vda/' bus=/'virtio/'/></disk> <disk type=/'file/'><driver type=/'qcow2/'/><source file=/'/var/lib/nova/instances/instance-00000033/disk.local/'/><target dev=/'vdb/' bus=/'virtio/'/> </disk><interface type=/'bridge/'> <source bridge=/'br100/'/> <mac address=/'02:16:3e:2b:29:cf/'/> <!-- <model type=/'virtio/'/> CANT RUN virtio network right now --> <filterref filter=/"nova-instance-instance-00000033-02163e2b29cf/"><parameter name=/"IP/" /><parameter name=/"DHCPSERVER/" /> </filterref></interface><!-- The order is significant here. File must be defined first --><serial type=/"file/"> <source path=/'/var/lib/nova/instances/instance-00000033/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><graphics type=/'vnc/' port=/'-1/' autoport=/'yes/' keymap=/'en-us/' listen=/'0.0.0.0/'/> </devices></domain>
以上,以典型的虚拟机实例创建过程,说明了nova-compute基本工作原理。nova-compute从消息队列获取的任务主要有以下几个:
·运行实例
·终止实例
·重启实例
·添加卷
·去除卷
·获得控制输出
·迁移实例
·诊断实例
·搁置