找回密码
 立即注册
首页 业界区 业界 OpenStack Nova 创建虚拟机

OpenStack Nova 创建虚拟机

擘塞 2025-10-1 17:15:03
创建虚拟机的过程是一个经典的分布式、异步、状态驱动的工作流。其核心设计哲学是:API 接收请求 -> 调度决策 -> 资源分配 -> 虚拟化层执行。整个过程涉及多个 Nova 服务以及外部组件(Glance, Neutron, Cinder, Keystone)。
1、基本流程

sequenceDiagram    participant User    participant nova-api    participant DB as Nova DB    participant MQ as Message Queue    participant Scheduler    participant Conductor    participant Compute    participant Libvirt    participant Glance    participant Neutron    participant Cinder    User->>nova-api: 1. POST /servers (创建实例)    nova-api->>DB: 2. 创建初始实例记录(state: BUILDING)    nova-api->>MQ: 3. cast(run_instance to scheduler)    Scheduler->>MQ: 4. 获取消息    Scheduler->>DB: 5. 查询资源    Scheduler->>MQ: 6. cast(build_and_run_instance to compute.X)    Compute->>MQ: 7. 获取消息    Compute->>Conductor: 8. 请求资源(镜像、网络等)    Conductor->>DB: 9. 查询数据    Conductor-->>Compute: 10. 返回信息    Compute->>Glance: 11. 下载镜像    Compute->>Neutron: 12. 分配网络    Compute->>Cinder: 13. 挂接卷(如适用)    Compute->>Libvirt: 14. 定义并启动域(XML)    Libvirt-->>Compute: 15. 成功    Compute->>DB: 16. 更新状态(state: ACTIVE)    Compute->>MQ: 17. 发送状态事件流程可分为三大阶段:

  • API 阶段 (nova-api):接收并验证请求,创建数据库记录,立即返回响应,将后续任务异步下发。
  • 调度阶段 (nova-scheduler):决策虚拟机在哪个计算节点上启动。
  • 构建阶段 (nova-compute):与各类服务交互准备资源,调用 Hypervisor 真正创建虚拟机。
2、详细流程源码分析

2.1 API请求入口

nova/api/openstack/compute/servers.py
  1. # nova/api/openstack/compute/servers.py (Caracal版本)
  2. class ServersController(wsgi.Controller):
  3.     @wsgi.response(202)
  4.     @validation.schema(schema_server_create_v242, '2.42')
  5.     def create(self, req, body):
  6.         """处理创建虚拟机API请求"""
  7.         context = req.environ['nova.context']
  8.         server = body['server']
  9.         
  10.         # 1. 参数校验与提取
  11.         name = server['name']
  12.         image_ref = server.get('imageRef')
  13.         flavor_ref = server.get('flavorRef')
  14.         
  15.         # 2. 创建实例对象
  16.         instance = objects.Instance(context=context)
  17.         instance.display_name = name
  18.         instance.image_ref = image_ref
  19.         
  20.         # 3. 调用Compute API
  21.         (instances, resv_id) = self.compute_api.create(
  22.             context,
  23.             instance_type=flavor_ref,
  24.             image_href=image_ref,
  25.             # ...其他参数
  26.         )
  27.         
  28.         # 4. 返回202 Accepted响应
  29.         return wsgi.ResponseObject({}, status=202)
复制代码
2.1 核心创建逻辑

nova/compute/api.py
  1. # nova/compute/api.py (Caracal版本)
  2. class API(base.Base):
  3.     @check_instance_create
  4.     @wrap_exception()
  5.     def create(self, context, instance_type, image_href, **kwargs):
  6.         # 1. 配额检查(使用Placement API)
  7.         self._check_quotas(context, requested_cores, requested_ram, ...)
  8.         
  9.         # 2. 创建RequestSpec对象
  10.         request_spec = objects.RequestSpec(
  11.             context=context,
  12.             flavor=flavor,
  13.             image=image_meta,
  14.             num_instances=num_instances,
  15.             # ...其他参数
  16.         )
  17.         
  18.         # 3. 安全组处理(使用Neutron API)
  19.         security_groups = self._get_requested_security_groups(context, ...)
  20.         
  21.         # 4. 异步调用Conductor
  22.         self.compute_task_api.schedule_and_build_instances(
  23.             context,
  24.             request_spec=request_spec,
  25.             security_groups=security_groups,
  26.             # ...其他参数
  27.         )
复制代码
2.3 调度决策

nova/scheduler/manager.py
  1. # nova/scheduler/manager.py (Caracal版本)
  2. class SchedulerManager(manager.Manager):
  3.     @messaging.expected_exceptions(exception.NoValidHost)
  4.     def select_destinations(self, context, request_spec, ...):
  5.         # 1. 获取所有主机状态(从Placement)
  6.         hosts = self.host_manager.get_all_host_states(context)
  7.         
  8.         # 2. 应用过滤器链
  9.         filter_properties = self._get_filter_properties(request_spec)
  10.         hosts = self.host_manager.get_filtered_hosts(hosts, filter_properties)
  11.         
  12.         # 3. 权重计算
  13.         weighed_hosts = self.host_manager.get_weighed_hosts(
  14.             hosts, request_spec, filter_properties)
  15.         
  16.         # 4. 选择目标主机
  17.         selections = []
  18.         for i in range(request_spec.num_instances):
  19.             if not weighed_hosts:
  20.                 raise exception.NoValidHost(reason="")
  21.             chosen_host = weighed_hosts.pop(0).obj
  22.             selections.append(chosen_host)
  23.         
  24.         return selections
复制代码
2.4 计算节点执行

nova/compute/manager.py
  1. # nova/compute/manager.py (Caracal版本)
  2. class ComputeManager(manager.Manager):
  3.     @wrap_exception()
  4.     @wrap_instance_fault
  5.     def build_and_run_instance(self, context, instance, request_spec, ...):
  6.         # 1. 准备网络(使用Neutron API)
  7.         network_info = self.network_api.allocate_for_instance(
  8.             context, instance, requested_networks, ...)
  9.         
  10.         # 2. 处理块设备(使用Cinder API)
  11.         block_device_info = self._prep_block_device(
  12.             context, instance, bdms, ...)
  13.         
  14.         # 3. 获取镜像元数据
  15.         image_meta = self._get_image_metadata(context, instance.image_ref)
  16.         
  17.         # 4. 调用Driver创建虚拟机
  18.         self.driver.spawn(
  19.             context, instance, image_meta,
  20.             injected_files=injected_files,
  21.             admin_password=admin_password,
  22.             network_info=network_info,
  23.             block_device_info=block_device_info)
  24.         
  25.         # 5. 更新实例状态
  26.         instance.vm_state = vm_states.ACTIVE
  27.         instance.task_state = None
  28.         instance.save()
复制代码
2.5 Hypervisor交互

nova/virt/libvirt/driver.py
  1. # nova/virt/libvirt/driver.py (Caracal版本)
  2. class LibvirtDriver(driver.ComputeDriver):
  3.     def spawn(self, context, instance, image_meta, **kwargs):
  4.         # 1. 准备磁盘(支持多种后端)
  5.         disk_info = self._create_image(context, instance, image_meta)
  6.         
  7.         # 2. 生成安全启动配置
  8.         secure_boot = self._get_secure_boot_config(instance)
  9.         
  10.         # 3. 生成Libvirt XML
  11.         # /var/lib/nova/instances/<instance-uuid>/libvirt.xml
  12.         xml = self._get_guest_xml(
  13.             context, instance, disk_info,
  14.             network_info=kwargs['network_info'],
  15.             block_device_info=kwargs['block_device_info'],
  16.             secure_boot=secure_boot)
  17.         
  18.         # 4. 定义并启动虚拟机
  19.         guest = self._host.get_guest()
  20.         guest.create(xml, flags=libvirt.VIR_DOMAIN_START_PAUSED)
  21.         
  22.         # 5. 注入元数据
  23.         self._inject_data(instance, network_info=kwargs['network_info'])
  24.         
  25.         # 6. 恢复虚拟机运行
  26.         guest.resume()
复制代码
3、常见问题

3.1 查看实例错误状态

第一步永远是查看实例的详细状态
  1. openstack server show b2c3d4e5-f6g7-8901-bcde-f12345678901 -c status -c fault
复制代码
  1. +--------+----------------------------------------------------------------------------------------------------+
  2. | Field  | Value                                                                                              |
  3. +--------+----------------------------------------------------------------------------------------------------+
  4. | fault  | {                                                                                                  |
  5. |        |   "message": "No valid host was found. There are not enough hosts available.",                     |
  6. |        |   "code": 500,                                                                                     |
  7. |        |   "details": "Exceeded maximum number of retries. Exception: No valid host was found. ...",        |
  8. |        |   "created": "2025-09-15T10:23:12Z"                                                                |
  9. |        | }                                                                                                  |
  10. | status | ERROR                                                                                              |
  11. +--------+----------------------------------------------------------------------------------------------------+
复制代码
fault 字段通常会给出比较直接的错误原因。
3.2 根据状态定位问题阶段


  • 长时间处于 SCHEDULING 状态

    • 问题:nova-scheduler 无法找到合适的主机。
    • 排查

      • 资源不足:检查目标主机是否有足够的 CPU、内存、磁盘。使用 openstack hypervisor stats show 和 openstack hypervisor show 。
      • 过滤器导致:检查 nova-scheduler 日志,看主机是如何被过滤掉的。常见于强制策略(如 DifferentHostFilter 找不到另一个实例)。
      • Placement 数据不同步:运行 nova-manage placement sync 同步数据。


  • 长时间处于 SPAWNING 状态或最终变为 ERROR

    • 问题:nova-compute 在目标节点上构建失败。
    • 排查

      • 查看计算节点日志:这是最重要的步骤!日志路径通常为 /var/log/nova/nova-compute.log。
      • 镜像下载失败:Glance 镜像 URL 不可达、镜像格式不支持(如 raw, qcow2)、磁盘空间不足(检查 /var/lib/nova/instances/_base)。
      • 网络问题:Neutron 无法分配端口(如 IP 耗尽、安全组规则错误)。查看 Neutron 相关日志 (/var/log/neutron/*.log)。
      • Hypervisor 问题:Libvirt 权限问题(检查 libvirtd 进程和 /var/lib/libvirt/ 权限)、QEMU 进程启动失败(检查 ps aux | grep qemu)、SElinux 或 AppArmor 策略限制。
      • 卷挂载失败:Cinder Volume 状态不是 available 或连接器(connector)信息有误。


  • 立即变为 ERROR

    • 问题:通常发生在 API 或调度阶段,是前置检查失败。
    • 排查

      • 查看 API 节点日志:/var/log/nova/nova-api.log。
      • 配额不足:检查项目配额 openstack quota show 。
      • 参数无效:指定的 Flavor、Image、Network 不存在或不可见。
      • Keystone 认证失败:Token 过期或权限不足。


3.3 核心排查工具与命令


  • 日志!:tail -f /var/log/nova/nova-*.log。使用 grep  过滤特定实例的日志,这是最强大的工具。
  • 虚拟化层检查

    • 登录到计算节点,检查 Libvirt 域:virsh list --all(看实例是否存在)。
    • 如果存在但有问题,查看其定义:virsh dumpxml 。
    • 查看虚拟机控制台日志:virsh console (需在镜像内启用 console)。

  • 网络命名空间:Neutron 使用 Linux Network Namespace。在计算节点上,使用 ip netns list 找到实例相关的命名空间(如 qrouter- 或 qdhcp-),然后 ip netns exec  bash 进入命名空间内部调试网络(ping, ip addr)。

来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!

相关推荐

昨天 02:19

举报

收藏一下   不知道什么时候能用到
您需要登录后才可以回帖 登录 | 立即注册