03 · OpenStack的计算管理 Nova

03 · 计算管理 Nova

本篇是 OpenStack 七大模块中最核心的一篇:Nova 负责把"镜像 + 规格 + 网络"变成一台真正可运行的虚拟机。学好 Nova,就等于抓住了 OpenStack 的主干。

本篇导读

  • 一句话定位:Nova = OpenStack 的"计算引擎 / 虚拟机工厂",负责虚拟机全生命周期管理。
  • 两条主线 :① 一台 VM 从用户点"创建"到真正跑起来,系统内部发生了什么(29 步时序 );② 系统凭什么决定把这台 VM 放在哪台物理机上(调度器:过滤 + 权重)。
  • 三个高频考点:调度过滤器、暂停/挂起/废弃的区别、资源超分比例。
  • 学法建议:先建立"组件地图",再追"创建 VM 时序",最后用 Dashboard + CLI 两条路径把每个操作各做一遍。

学习目标

学完本篇,你应当能够:

  1. 说出 Nova 的六大组件(API / Scheduler / Compute / Conductor / Placement / DB)各自职责与通信方式(oslo.messaging / RPC)。
  2. 讲清 nova-conductor 被引入的三大理由(安全、解耦升级、并发性能)。
  3. 默写默认 enabled_filters 六个过滤器,并能结合实验解释 AZ、主机聚合、server group 如何影响调度。
  4. 记住资源超分默认比例:cpu=16、ram=1.5、disk=1。
  5. 完整复述创建 VM 的 6 步简化流程与 Step1--Step29 详细时序。
  6. 区分 Pause / Suspend / Shelve / Lock / Rebuild / Resize / Snapshot 的状态、资源占用与适用场景。
  7. 用 Dashboard 和 CLI 两套命令完成规格、镜像、网络、密钥对、主机聚合、实例的创建与生命周期管理。

一、Nova 的定位与作用

1.1 Nova 负责什么、不负责什么

类别 内容
Nova 负责 ① 虚拟机(Instance)生命周期管理;② 其他计算资源的生命周期管理
Nova 不负责 ① 承载虚拟机的物理主机自身的管理(硬件、BIOS、带外管理);② 全面的系统状态监控(监控交给 Ceilometer/Gnocchi 等)

记忆点:Nova 管"虚拟机这层",不管"物理服务器这层"。网络归 Neutron、块存储归 Cinder、镜像归 Glance、身份归 Keystone,Nova 通过 RPC/HTTP 与它们协作,而不是自己实现。


二、核心概念(先把名词搞清楚)

概念 英文 / 命令关键词 含义
实例 / 虚拟机 Instance / Server 一台运行中的虚拟机,openstack server
规格 / flavor Flavor / 实例类型 定义一台 VM 的 vCPU、内存、根磁盘大小模板,用户创建时只需指定 flavor
镜像 Image 虚拟机的系统盘模板,存放在 Glance,cirros-0.5.2 是常用测试镜像
网络 Network VM 接入的虚拟网络,归 Neutron;最小创建实例需"规格 + 镜像 + 网络"三样
密钥对 Keypair SSH 公钥,创建时注入 VM,用于免密登录
可用分区 Availability Zone / AZ 把计算节点按容灾/隔离划分的逻辑域,默认名 nova
主机聚合 Host Aggregate 把计算节点分组的机制,可携带 metadata,用于调度;AZ 是其特例
服务器组 Server Group / 实例组 针对实例(而非主机)的分组,定义亲和/反亲和策略
超分 Overcommit 物理资源不足时,按比例"虚报"可用资源,提高利用率

最小创建实例三要素:规格(flavor)+ 镜像(image)+ 网络(network)。实验中创建按钮如果是灰的,点"下一项"去找已选网络即可。


三、Nova 系统架构与组件

3.1 架构总览图

#mermaid-svg-QowlO64iTt3CxCVS{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-QowlO64iTt3CxCVS .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-QowlO64iTt3CxCVS .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-QowlO64iTt3CxCVS .error-icon{fill:#552222;}#mermaid-svg-QowlO64iTt3CxCVS .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-QowlO64iTt3CxCVS .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-QowlO64iTt3CxCVS .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-QowlO64iTt3CxCVS .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-QowlO64iTt3CxCVS .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-QowlO64iTt3CxCVS .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-QowlO64iTt3CxCVS .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-QowlO64iTt3CxCVS .marker{fill:#333333;stroke:#333333;}#mermaid-svg-QowlO64iTt3CxCVS .marker.cross{stroke:#333333;}#mermaid-svg-QowlO64iTt3CxCVS svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-QowlO64iTt3CxCVS p{margin:0;}#mermaid-svg-QowlO64iTt3CxCVS .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-QowlO64iTt3CxCVS .cluster-label text{fill:#333;}#mermaid-svg-QowlO64iTt3CxCVS .cluster-label span{color:#333;}#mermaid-svg-QowlO64iTt3CxCVS .cluster-label span p{background-color:transparent;}#mermaid-svg-QowlO64iTt3CxCVS .label text,#mermaid-svg-QowlO64iTt3CxCVS span{fill:#333;color:#333;}#mermaid-svg-QowlO64iTt3CxCVS .node rect,#mermaid-svg-QowlO64iTt3CxCVS .node circle,#mermaid-svg-QowlO64iTt3CxCVS .node ellipse,#mermaid-svg-QowlO64iTt3CxCVS .node polygon,#mermaid-svg-QowlO64iTt3CxCVS .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-QowlO64iTt3CxCVS .rough-node .label text,#mermaid-svg-QowlO64iTt3CxCVS .node .label text,#mermaid-svg-QowlO64iTt3CxCVS .image-shape .label,#mermaid-svg-QowlO64iTt3CxCVS .icon-shape .label{text-anchor:middle;}#mermaid-svg-QowlO64iTt3CxCVS .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-QowlO64iTt3CxCVS .rough-node .label,#mermaid-svg-QowlO64iTt3CxCVS .node .label,#mermaid-svg-QowlO64iTt3CxCVS .image-shape .label,#mermaid-svg-QowlO64iTt3CxCVS .icon-shape .label{text-align:center;}#mermaid-svg-QowlO64iTt3CxCVS .node.clickable{cursor:pointer;}#mermaid-svg-QowlO64iTt3CxCVS .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-QowlO64iTt3CxCVS .arrowheadPath{fill:#333333;}#mermaid-svg-QowlO64iTt3CxCVS .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-QowlO64iTt3CxCVS .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-QowlO64iTt3CxCVS .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-QowlO64iTt3CxCVS .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-QowlO64iTt3CxCVS .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-QowlO64iTt3CxCVS .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-QowlO64iTt3CxCVS .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-QowlO64iTt3CxCVS .cluster text{fill:#333;}#mermaid-svg-QowlO64iTt3CxCVS .cluster span{color:#333;}#mermaid-svg-QowlO64iTt3CxCVS div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-QowlO64iTt3CxCVS .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-QowlO64iTt3CxCVS rect.text{fill:none;stroke-width:0;}#mermaid-svg-QowlO64iTt3CxCVS .icon-shape,#mermaid-svg-QowlO64iTt3CxCVS .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-QowlO64iTt3CxCVS .icon-shape p,#mermaid-svg-QowlO64iTt3CxCVS .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-QowlO64iTt3CxCVS .icon-shape .label rect,#mermaid-svg-QowlO64iTt3CxCVS .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-QowlO64iTt3CxCVS .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-QowlO64iTt3CxCVS .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-QowlO64iTt3CxCVS :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 计算节点 controller(兼做计算)
计算节点 compute
控制节点(Controller)
RPC
用户 / Dashboard / CLI
Keystone 认证
nova-api(入口,接收 HTTP/REST)
nova-scheduler(过滤+权重选主机)
nova-conductor(数据库代理 / 协调构建与调整)
nova-consoleauth / novncproxy(控制台代理)
placement(跟踪资源库存与用量)
SQL 数据库:nova / nova_api
RabbitMQ 消息队列(oslo.messaging)
nova-compute(VM 真正执行者)
libvirt / KVM Hypervisor
nova-compute
libvirt / KVM Hypervisor
Glance 镜像
Neutron 网络
Cinder 块存储

3.2 六大组件职责(教材原文要点)

组件 职责
DB 用于数据存储的 SQL 数据库
API(nova-api) 接收 HTTP 请求、转换命令,并通过 oslo.messaging 队列或 HTTP 与其他组件通信;处理 REST 请求、做数据库读写、把 RPC 消息发给其他 Nova 服务,并生成 REST 响应
Scheduler(nova-scheduler) 为虚拟机选择合适的物理主机(过滤 + 权重两步)
Compute(nova-compute) 虚拟机生命周期和复杂流程控制,是 VM 操作的真正执行者
Conductor(nova-conductor) 处理需要协调的请求(构建 / 调整大小 resize),充当数据库代理,或处理对象转换
Placement 跟踪**资源提供者(Resource Provider)**的库存(inventory)和使用情况(usage)
RPC Remote Procedure Call,远程过程调用:允许一台计算机上的程序调用另一台计算机的子程序,程序员无需为交互额外编程

3.3 通信机制:oslo.messaging 与"无共享"架构

  • RPC 消息传递通过 **oslo.messaging** 库完成,它是消息队列(RabbitMQ)之上的抽象层。
  • Nova 使用基于消息传递的 "无共享(shared-nothing)"架构:大多数主要组件都可以在多台服务器上运行,每个组件都有一个监听 RPC 消息的 Manager。
  • 好处:组件可水平扩展、解耦;某个组件多实例即可分担负载。

#mermaid-svg-zbVvRqbH8dEBMwlO{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-zbVvRqbH8dEBMwlO .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-zbVvRqbH8dEBMwlO .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-zbVvRqbH8dEBMwlO .error-icon{fill:#552222;}#mermaid-svg-zbVvRqbH8dEBMwlO .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-zbVvRqbH8dEBMwlO .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-zbVvRqbH8dEBMwlO .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-zbVvRqbH8dEBMwlO .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-zbVvRqbH8dEBMwlO .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-zbVvRqbH8dEBMwlO .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-zbVvRqbH8dEBMwlO .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-zbVvRqbH8dEBMwlO .marker{fill:#333333;stroke:#333333;}#mermaid-svg-zbVvRqbH8dEBMwlO .marker.cross{stroke:#333333;}#mermaid-svg-zbVvRqbH8dEBMwlO svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-zbVvRqbH8dEBMwlO p{margin:0;}#mermaid-svg-zbVvRqbH8dEBMwlO .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-zbVvRqbH8dEBMwlO .cluster-label text{fill:#333;}#mermaid-svg-zbVvRqbH8dEBMwlO .cluster-label span{color:#333;}#mermaid-svg-zbVvRqbH8dEBMwlO .cluster-label span p{background-color:transparent;}#mermaid-svg-zbVvRqbH8dEBMwlO .label text,#mermaid-svg-zbVvRqbH8dEBMwlO span{fill:#333;color:#333;}#mermaid-svg-zbVvRqbH8dEBMwlO .node rect,#mermaid-svg-zbVvRqbH8dEBMwlO .node circle,#mermaid-svg-zbVvRqbH8dEBMwlO .node ellipse,#mermaid-svg-zbVvRqbH8dEBMwlO .node polygon,#mermaid-svg-zbVvRqbH8dEBMwlO .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-zbVvRqbH8dEBMwlO .rough-node .label text,#mermaid-svg-zbVvRqbH8dEBMwlO .node .label text,#mermaid-svg-zbVvRqbH8dEBMwlO .image-shape .label,#mermaid-svg-zbVvRqbH8dEBMwlO .icon-shape .label{text-anchor:middle;}#mermaid-svg-zbVvRqbH8dEBMwlO .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-zbVvRqbH8dEBMwlO .rough-node .label,#mermaid-svg-zbVvRqbH8dEBMwlO .node .label,#mermaid-svg-zbVvRqbH8dEBMwlO .image-shape .label,#mermaid-svg-zbVvRqbH8dEBMwlO .icon-shape .label{text-align:center;}#mermaid-svg-zbVvRqbH8dEBMwlO .node.clickable{cursor:pointer;}#mermaid-svg-zbVvRqbH8dEBMwlO .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-zbVvRqbH8dEBMwlO .arrowheadPath{fill:#333333;}#mermaid-svg-zbVvRqbH8dEBMwlO .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-zbVvRqbH8dEBMwlO .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-zbVvRqbH8dEBMwlO .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-zbVvRqbH8dEBMwlO .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-zbVvRqbH8dEBMwlO .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-zbVvRqbH8dEBMwlO .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-zbVvRqbH8dEBMwlO .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-zbVvRqbH8dEBMwlO .cluster text{fill:#333;}#mermaid-svg-zbVvRqbH8dEBMwlO .cluster span{color:#333;}#mermaid-svg-zbVvRqbH8dEBMwlO div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-zbVvRqbH8dEBMwlO .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-zbVvRqbH8dEBMwlO rect.text{fill:none;stroke-width:0;}#mermaid-svg-zbVvRqbH8dEBMwlO .icon-shape,#mermaid-svg-zbVvRqbH8dEBMwlO .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-zbVvRqbH8dEBMwlO .icon-shape p,#mermaid-svg-zbVvRqbH8dEBMwlO .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-zbVvRqbH8dEBMwlO .icon-shape .label rect,#mermaid-svg-zbVvRqbH8dEBMwlO .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-zbVvRqbH8dEBMwlO .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-zbVvRqbH8dEBMwlO .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-zbVvRqbH8dEBMwlO :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} rpc.call(需等待返回)
rpc.cast(异步投递)
nova-api
RabbitMQ
nova-scheduler
nova-conductor
nova-compute

rpc.call:同步调用,等待对方返回(绿色线程友好,不阻塞其他线程);rpc.cast:异步单向投递,发完即走。创建 VM 时序中两者都会出现。

3.4 物理部署与查看服务

  • 控制节点通常跑:nova-api、nova-scheduler、nova-conductor、nova-consoleauth、nova-novncproxy、placement-api。
  • 计算节点跑:nova-compute。
  • Nova 各组件可分布式部署 ,并通过 virtDriver 对接不同虚拟化平台(KVM / VMware / Xen / Ironic 等)。

检查 RabbitMQ 是否正常:

bash 复制代码
[root@controller ~(keystone_admin)]# systemctl status rabbitmq-server.service

查看 Nova 组件分布与状态(在控制节点导入 admin 环境变量后):

bash 复制代码
[root@controller ~]# source keystonerc_admin
[root@controller ~(keystone_admin)]# openstack compute service list

典型回显(Binary / Host / Zone / Status / State):

ID Binary Host Zone Status State
1 nova-conductor controller internal enabled up
2 nova-scheduler controller internal enabled up
5 nova-compute controller nova enabled up
6 nova-compute compute nova enabled up

注意:conductor / scheduler 的 Zone 是 internal,compute 的 Zone 是 nova。State 为 up 表示服务心跳正常。

3.5 重点组件逐一说明

3.5.1 nova-api

统一的 REST 入口,做认证校验、参数校验、写数据库初始化记录、然后把活儿通过消息队列派发出去。它是用户唯一直接打交道的 Nova 服务。

3.5.2 nova-conductor(高频考点:为什么引入它)

引入 nova-conductor 之前,每个 nova-compute 都直接访问数据库。引入后,compute 不再连库,而是通过 RPC 向 conductor 要数据。三大理由:

维度 说明
安全性 若某计算节点被攻陷,攻击者就能拿到数据库全部权限、肆意操作数据库。conductor 作为数据库代理,把 compute 与数据库隔开。
方便升级 将数据库与 nova-compute 解耦,数据库 schema 改变时,nova-compute 不必升级。
性能(并发) 以前 compute 里直接访问数据库是阻塞性 的;而 nova-compute 只有一个 OS 线程,一个绿色线程访问数据库时会阻塞其他绿色线程,无法并发。改为 RPC 调用后是绿色线程友好 的:一个 rpc.call 返回前不会阻塞其他绿色线程,从而提高并发。

数据库连接由 nova.conf 中两行决定:

bash 复制代码
[root@controller ~(keystone_admin)]# vim /etc/nova/nova.conf
# 第 1132 行:nova_api 库
1132 connection=mysql+pymysql://nova_api:d247d6a4c7f14f2f@192.168.108.10/nova_api
# 第 1763 行:nova 主库
1763 connection=mysql+pymysql://nova:d247d6a4c7f14f2f@192.168.108.10/nova

补充:新版本 Nova 把 API 库(nova_api)与主库(nova)拆开,进一步解耦。

3.5.3 nova-scheduler

决定 VM 分配到哪台物理机,分**过滤(filter)和权重(weight)**两步,详见下一章。

3.5.4 nova-compute
  • 虚拟机生命周期操作的真正执行者,会调用对应 hypervisor 的 driver。
  • 底层对接不同虚拟化平台(KVM / VMware / XEN / Ironic 等)。
  • 内置周期性任务,完成资源刷新、虚拟机状态同步等。
  • 资源管理模块 resource_tracker 配合插件机制完成资源统计。

计算节点配置驱动:

bash 复制代码
[root@compute ~]# vim /etc/nova/nova.conf
53 compute_driver=libvirt.LibvirtDriver

[root@compute ~]# cd /usr/lib/python3.6/site-packages/nova/virt/
[root@compute virt]# ls
# 可见 arch.py driver.py hyperv ironic powervm vmwareapi zvm libvirt ...

补充:compute_driver=libvirt.LibvirtDriver 表示通过 libvirt 间接管理 KVM/QEMU。libvirt 是统一的虚拟化管理 API/守护进程,KVM 是内核态虚拟化模块,QEMU 是用户态模拟器------三者关系:QEMU 模拟硬件,KVM 在内核态加速 QEMU,libvirt 统一指挥 QEMU/KVM。

3.5.5 控制台代理(nova-console)

用户有多种方式访问虚拟机控制台:

代理 访问方式
nova-novncproxy 基于 Web 浏览器的 VNC 访问(最常用)
nova-spicehtml5proxy 基于 HTML5 浏览器的 SPICE 访问
nova-xvpnvncproxy 基于 Java 客户端的 VNC 访问

补充:此外还有 serial proxy(nova-serialproxy)提供串口控制台,适合网络完全不通时排障。


四、Placement 与资源超分(Overcommit)

4.1 资源超分默认比例(必背)

为提高资源利用率,Nova 允许计算节点"虚报"可用资源,由 nova.conf 三个参数控制:

参数 默认值 含义 配置行示例
cpu_allocation_ratio 16 一个 8 vCPU 的节点,调度时视为 128 个 vCPU 203 cpu_allocation_ratio=16.0
ram_allocation_ratio 1.5 物理 10GB 内存按 15GB 算 210 ram_allocation_ratio = 1.5
disk_allocation_ratio 1 磁盘不超分(1:1) 216 #disk_allocation_ratio=

举例(教材原文):若把 ram_allocation_ratio 从 1.5 改成 5:

bash 复制代码
210 ram_allocation_ratio=5

则一台物理内存 10GB 的计算节点,OpenStack 会认为它有 50GB(10×5) 内存可用。

记忆口诀:"CPU 狠超 16、内存轻超 1.5、磁盘不超 1"。磁盘不超分是因为磁盘写满会直接导致 VM 无法运行,风险最高。

4.2 Placement(补充)

  • Placement 是独立的小服务,作用是"资源账本":每个计算节点、共享存储、SR-IOV 网卡等都是一个 Resource Provider(资源提供者,RP)。
  • 关键概念(补充):
    • inventory(库存):RP 上各类资源的总量、预留值、步长。
    • allocation(分配):某台实例已经从某个 RP 消费了多少资源。
    • trait(特征) :给 RP 打的标签(如 HW_CPU_X86_AVX2、COMPUTE_STATUS_DISABLED)。
    • aggregate(资源聚合):把多个 RP 关联起来。
  • 现代 Nova 的资源量校验已交给 Placement:nova-compute 的 resource_tracker 周期性把本节点库存上报给 Placement,调度时 ComputeFilter 会去查 Placement 是否放得下。这也是 RamFilter / DiskFilter / CoreFilter 默认不再启用的原因------资源统计统一由 Placement 负责。

#mermaid-svg-OvkzHIPbGG7yrMAd{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-OvkzHIPbGG7yrMAd .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-OvkzHIPbGG7yrMAd .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-OvkzHIPbGG7yrMAd .error-icon{fill:#552222;}#mermaid-svg-OvkzHIPbGG7yrMAd .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-OvkzHIPbGG7yrMAd .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-OvkzHIPbGG7yrMAd .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-OvkzHIPbGG7yrMAd .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-OvkzHIPbGG7yrMAd .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-OvkzHIPbGG7yrMAd .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-OvkzHIPbGG7yrMAd .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-OvkzHIPbGG7yrMAd .marker{fill:#333333;stroke:#333333;}#mermaid-svg-OvkzHIPbGG7yrMAd .marker.cross{stroke:#333333;}#mermaid-svg-OvkzHIPbGG7yrMAd svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-OvkzHIPbGG7yrMAd p{margin:0;}#mermaid-svg-OvkzHIPbGG7yrMAd .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-OvkzHIPbGG7yrMAd .cluster-label text{fill:#333;}#mermaid-svg-OvkzHIPbGG7yrMAd .cluster-label span{color:#333;}#mermaid-svg-OvkzHIPbGG7yrMAd .cluster-label span p{background-color:transparent;}#mermaid-svg-OvkzHIPbGG7yrMAd .label text,#mermaid-svg-OvkzHIPbGG7yrMAd span{fill:#333;color:#333;}#mermaid-svg-OvkzHIPbGG7yrMAd .node rect,#mermaid-svg-OvkzHIPbGG7yrMAd .node circle,#mermaid-svg-OvkzHIPbGG7yrMAd .node ellipse,#mermaid-svg-OvkzHIPbGG7yrMAd .node polygon,#mermaid-svg-OvkzHIPbGG7yrMAd .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-OvkzHIPbGG7yrMAd .rough-node .label text,#mermaid-svg-OvkzHIPbGG7yrMAd .node .label text,#mermaid-svg-OvkzHIPbGG7yrMAd .image-shape .label,#mermaid-svg-OvkzHIPbGG7yrMAd .icon-shape .label{text-anchor:middle;}#mermaid-svg-OvkzHIPbGG7yrMAd .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-OvkzHIPbGG7yrMAd .rough-node .label,#mermaid-svg-OvkzHIPbGG7yrMAd .node .label,#mermaid-svg-OvkzHIPbGG7yrMAd .image-shape .label,#mermaid-svg-OvkzHIPbGG7yrMAd .icon-shape .label{text-align:center;}#mermaid-svg-OvkzHIPbGG7yrMAd .node.clickable{cursor:pointer;}#mermaid-svg-OvkzHIPbGG7yrMAd .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-OvkzHIPbGG7yrMAd .arrowheadPath{fill:#333333;}#mermaid-svg-OvkzHIPbGG7yrMAd .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-OvkzHIPbGG7yrMAd .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-OvkzHIPbGG7yrMAd .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-OvkzHIPbGG7yrMAd .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-OvkzHIPbGG7yrMAd .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-OvkzHIPbGG7yrMAd .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-OvkzHIPbGG7yrMAd .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-OvkzHIPbGG7yrMAd .cluster text{fill:#333;}#mermaid-svg-OvkzHIPbGG7yrMAd .cluster span{color:#333;}#mermaid-svg-OvkzHIPbGG7yrMAd div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-OvkzHIPbGG7yrMAd .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-OvkzHIPbGG7yrMAd rect.text{fill:none;stroke-width:0;}#mermaid-svg-OvkzHIPbGG7yrMAd .icon-shape,#mermaid-svg-OvkzHIPbGG7yrMAd .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-OvkzHIPbGG7yrMAd .icon-shape p,#mermaid-svg-OvkzHIPbGG7yrMAd .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-OvkzHIPbGG7yrMAd .icon-shape .label rect,#mermaid-svg-OvkzHIPbGG7yrMAd .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-OvkzHIPbGG7yrMAd .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-OvkzHIPbGG7yrMAd .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-OvkzHIPbGG7yrMAd :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 周期性上报库存 inventory
查:该节点还剩多少资源 allocation
上报 allocation 消费/释放
nova-compute(resource_tracker)
Placement API
Placement DB
nova-scheduler / ComputeFilter
Instance 启动/销毁


五、调度器(nova-scheduler):过滤 + 权重

5.1 调度两步走

#mermaid-svg-8gTzNgnTKnigz7mB{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-8gTzNgnTKnigz7mB .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-8gTzNgnTKnigz7mB .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-8gTzNgnTKnigz7mB .error-icon{fill:#552222;}#mermaid-svg-8gTzNgnTKnigz7mB .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-8gTzNgnTKnigz7mB .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-8gTzNgnTKnigz7mB .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-8gTzNgnTKnigz7mB .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-8gTzNgnTKnigz7mB .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-8gTzNgnTKnigz7mB .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-8gTzNgnTKnigz7mB .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-8gTzNgnTKnigz7mB .marker{fill:#333333;stroke:#333333;}#mermaid-svg-8gTzNgnTKnigz7mB .marker.cross{stroke:#333333;}#mermaid-svg-8gTzNgnTKnigz7mB svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-8gTzNgnTKnigz7mB p{margin:0;}#mermaid-svg-8gTzNgnTKnigz7mB .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-8gTzNgnTKnigz7mB .cluster-label text{fill:#333;}#mermaid-svg-8gTzNgnTKnigz7mB .cluster-label span{color:#333;}#mermaid-svg-8gTzNgnTKnigz7mB .cluster-label span p{background-color:transparent;}#mermaid-svg-8gTzNgnTKnigz7mB .label text,#mermaid-svg-8gTzNgnTKnigz7mB span{fill:#333;color:#333;}#mermaid-svg-8gTzNgnTKnigz7mB .node rect,#mermaid-svg-8gTzNgnTKnigz7mB .node circle,#mermaid-svg-8gTzNgnTKnigz7mB .node ellipse,#mermaid-svg-8gTzNgnTKnigz7mB .node polygon,#mermaid-svg-8gTzNgnTKnigz7mB .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-8gTzNgnTKnigz7mB .rough-node .label text,#mermaid-svg-8gTzNgnTKnigz7mB .node .label text,#mermaid-svg-8gTzNgnTKnigz7mB .image-shape .label,#mermaid-svg-8gTzNgnTKnigz7mB .icon-shape .label{text-anchor:middle;}#mermaid-svg-8gTzNgnTKnigz7mB .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-8gTzNgnTKnigz7mB .rough-node .label,#mermaid-svg-8gTzNgnTKnigz7mB .node .label,#mermaid-svg-8gTzNgnTKnigz7mB .image-shape .label,#mermaid-svg-8gTzNgnTKnigz7mB .icon-shape .label{text-align:center;}#mermaid-svg-8gTzNgnTKnigz7mB .node.clickable{cursor:pointer;}#mermaid-svg-8gTzNgnTKnigz7mB .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-8gTzNgnTKnigz7mB .arrowheadPath{fill:#333333;}#mermaid-svg-8gTzNgnTKnigz7mB .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-8gTzNgnTKnigz7mB .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-8gTzNgnTKnigz7mB .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-8gTzNgnTKnigz7mB .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-8gTzNgnTKnigz7mB .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-8gTzNgnTKnigz7mB .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-8gTzNgnTKnigz7mB .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-8gTzNgnTKnigz7mB .cluster text{fill:#333;}#mermaid-svg-8gTzNgnTKnigz7mB .cluster span{color:#333;}#mermaid-svg-8gTzNgnTKnigz7mB div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-8gTzNgnTKnigz7mB .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-8gTzNgnTKnigz7mB rect.text{fill:none;stroke-width:0;}#mermaid-svg-8gTzNgnTKnigz7mB .icon-shape,#mermaid-svg-8gTzNgnTKnigz7mB .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-8gTzNgnTKnigz7mB .icon-shape p,#mermaid-svg-8gTzNgnTKnigz7mB .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-8gTzNgnTKnigz7mB .icon-shape .label rect,#mermaid-svg-8gTzNgnTKnigz7mB .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-8gTzNgnTKnigz7mB .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-8gTzNgnTKnigz7mB .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-8gTzNgnTKnigz7mB :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} Host2、Host4 被刷掉
初始 6 个计算节点

Host1 ~ Host6
Filter 层层过滤

每个 filter 返回 True/False
候选主机

Host1, Host3, Host5, Host6
Weight 打分

默认按空闲内存
得分最高者

Host5 入选

  • 默认调度器是 FilterScheduler :

    bash 复制代码
    scheduler_driver=nova.scheduler.filter_scheduler.FilterScheduler
  • 调度两步:① 通过过滤器(filter)选出满足条件的计算节点(运行 nova-compute);② 通过权重为通过过滤的节点打分,在分值最高的节点上创建 Instance。

  • Nova 允许使用第三方 scheduler ,改 scheduler_driver 即可------体现 OpenStack 的开放性。

  • 配置项三件套:scheduler_driver、scheduler_available_filters、scheduler_default_filters。

5.2 过滤器配置

bash 复制代码
[root@controller ~]# vim /etc/nova/nova.conf
# 第 1931 行:可用过滤器(默认为所有 nova 自带 filter)
1931 available_filters=nova.scheduler.filters.all_filters
# 第 1938 行:真正启用的过滤器(按列表顺序依次过滤)
1938 enabled_filters=AvailabilityZoneFilter,ComputeFilter,ComputeCapabilitiesFilter,ImagePropertiesFilter,ServerGroupAntiAffinityFilter,ServerGroupAffinityFilter

默认 enabled_filters 六个(必背):AvailabilityZoneFilter、ComputeFilter、ComputeCapabilitiesFilter、ImagePropertiesFilter、ServerGroupAntiAffinityFilter、ServerGroupAffinityFilter。

注意:RetryFilter 通常排在第一个 (虽不在上面默认值列表里显示,但重试机制由它负责);RamFilter、DiskFilter、CoreFilter 默认未启用------资源校验已交给 Placement / ComputeFilter。

5.3 逐个过滤器详解

① RetryFilter(重试过滤)
  • 作用:刷掉之前已经调度过、但操作失败的节点。
  • 例子:A、B、C 都通过过滤,A 因权重最大被选中,但 A 上操作失败了。nova-scheduler 默认重新执行过滤(重试次数由 scheduler_max_attempts 指定,默认 3)。这时 RetryFilter 直接把 A 刷掉,避免再次失败。
  • 通常作为第一个 filter。
② AvailabilityZoneFilter(可用分区过滤)
  • 为提高容灾性、提供隔离服务,可把计算节点划分到不同 AZ。例如把一个机架上的机器划为一个 AZ。
  • OpenStack 默认有一个名为 **nova** 的 AZ,所有计算节点初始都在 nova 中;用户可自建 AZ。
  • 创建 Instance 时需指定部署到哪个 AZ;filtering 时该过滤器把不属于指定 AZ 的节点刷掉。

教材实验(gpu_az / nogpu_az):

步骤 操作
1 将 controller 节点加入 gpu_az;将 compute 节点加入 nogpu_az
2 创建 gpu_az 时选择 controller 节点
3 同理创建 nogpu_az 时选择 compute 节点
4 前置:先创建一个网络,供后面创建实例使用
5 创建规格、上传镜像(cirros-0.5.2)
6 创建 instance_gpu(要用 GPU)→ 选 gpu_az → 落到 controller
7 创建 instance_nogpu(用不到 GPU)→ 选 nogpu_az → 落到 compute

思考题结论:

  • 用 GPU 的实例选哪个 AZ?→ gpu_az → controller。
  • 不用 GPU 的实例选哪个 AZ?→ nogpu_az → compute。

开 debug 观察过滤日志:

bash 复制代码
[root@controller ~]# vim /etc/nova/nova.conf
694 debug=True
[root@controller ~]# systemctl restart openstack-nova*
[root@controller ~]# tail /var/log/nova/nova-scheduler.log -f
# 然后在 web 界面再建一台 VM,选择 AZ,观察 AvailabilityZoneFilter 命中现象

提醒:生产环境无故障时不要开 debug,浪费性能。

③ RamFilter(内存过滤)------默认未启用
  • 把不能满足 flavor 内存需求的节点刷掉。
  • 内存允许 overcommit,由 ram_allocation_ratio 控制(默认 1.5)。要启用需自行加入 scheduler_default_filters。
④ DiskFilter(磁盘过滤)------默认未启用
  • 把不能满足 flavor 磁盘需求的节点刷掉。磁盘 overcommit 由 disk_allocation_ratio 控制(默认 1)。
⑤ CoreFilter(vCPU 过滤)------默认未启用
  • 把不能满足 flavor vCPU 需求的节点刷掉。vCPU overcommit 由 cpu_allocation_ratio 控制(默认 16)。
  • 一个 8 vCPU 节点被视为 128 个 vCPU。
  • 注意 :nova-scheduler 默认 filter 列表里没有 CoreFilter;要用就把它加进 scheduler_default_filters。
⑥ ComputeFilter(计算服务过滤)------必选
  • 保证只有 nova-compute 服务正常工作的节点才能被调度。显然是必选 filter。
⑦ ComputeCapabilitiesFilter(节点能力过滤)
  • 按计算节点特性筛选,比较高级。
  • 例:节点有 x86_64 和 ARM 两种架构,想把 Instance 指定部署到 x86_64 节点。
  • 做法:flavor 中有 Metadata,Compute 的 Capabilities 就在 Metadata 中指定。"Compute Host Capabilities" 列出所有可设置项,点 "Architecture" 后的 "+" 在右边指定具体架构。
  • 规则:配好后调度时只筛出 x86_64 节点;若 flavor 没设 Metadata,该过滤器不起作用,所有节点都通过。
⑧ ImagePropertiesFilter(镜像属性过滤)
  • 按所选 image 的属性(metadata)筛选匹配节点。
  • 例:希望某镜像只能跑在 kvm 的 hypervisor 上,通过 "Hypervisor Type" 属性指定。点 "+" 选 "kvm"。
  • 规则:配好后只筛出 kvm 节点;若镜像没设 Metadata,该过滤器不起作用,所有节点都通过。
⑨ ServerGroupAntiAffinityFilter(反亲和)
  • 尽量把 Instance 分散部署到不同节点。
  • 例:inst1/inst2/inst3,节点 A/B/C:
bash 复制代码
# 1. 创建 anti-affinity 策略的 server group
nova server-group-create --policy anti-affinity group-1
# 2. 依次创建实例并放进 group-1
nova boot --image IMAGE_ID --flavor 1 --hint group=group-1 inst1
nova boot --image IMAGE_ID --flavor 1 --hint group=group-1 inst2
nova boot --image IMAGE_ID --flavor 1 --hint group=group-1 inst3
  • group-1 策略是 AntiAffinity,调度时把三台实例分散到 A、B、C 三个节点。
  • 注意 :server group 其实是 instance group(实例组),不是计算节点的 group。
  • 目前只能在 CLI 中通过 --hint group= 指定。创建实例时若没指定 server group,该过滤器直接通过、不过滤。
⑩ ServerGroupAffinityFilter(亲和)
  • 作用相反:尽量把 Instance 部署到同一节点。
bash 复制代码
nova server-group-create --policy affinity group-2
nova boot --image IMAGE_ID --flavor 1 --hint group=group-2 inst1
nova boot --image IMAGE_ID --flavor 1 --hint group=group-2 inst2
nova boot --image IMAGE_ID --flavor 1 --hint group=group-2 inst3
  • 同理,未指定 server group 时直接通过。

补充:实验手册里 ServerGroup 有 4 种策略:

策略 含义
关联 affinity 组内 VM 必须在同一主机
不关联 anti-affinity 组内 VM 必须分散到不同主机
软不关联 soft-anti-affinity 资源够就分散,不够则忽略规则
软关联 soft-affinity 资源够就放一起,不够则忽略规则

5.4 权重(Weight)

  • 通过过滤后若有多个候选主机,scheduler 对每个节点打分,得分最高者获胜。
  • 默认实现 :按计算节点空闲内存量打分------空闲内存越多权重越大,实例部署到空闲内存最多的节点。

实验观察日志:

bash 复制代码
# 开 debug、重启、记录实例 id 后:
[root@controller nova(keystone_admin)]# cat /var/log/nova/nova-scheduler.log | grep Filter
# 初始两个 host(controller、compute),依次过 6 个 filter,两个节点都通过

[root@controller nova(keystone_admin)]# cat /var/log/nova/nova-scheduler.log | grep weight
# compute ram: 15217MB disk: 58368MB io_ops: 0 instances: 0, weight: 3.0
# controller ram: 15217MB disk: 54272MB io_ops: 0 instances: 0, weight: 2.9298

[root@controller nova(keystone_admin)]# cat /var/log/nova/nova-scheduler.log | grep Select
# 最终选择 compute

结论 :因为 compute 的磁盘比 controller 多(58368 > 54272),权重值更大(3.0 > 2.928),最终选 compute。

说明:默认 Weight 虽然名义上"按空闲内存",但实际打分函数会综合 ram、disk、io_ops 等,实验里 ram 相同,于是 disk 大小成了决胜项。


六、创建虚拟机的完整流程

6.1 简化流程(6 步)

nova-conductor 计算节点A nova-compute nova-scheduler RabbitMQ nova-api 客户(用户/程序) nova-conductor 计算节点A nova-compute nova-scheduler RabbitMQ nova-api 客户(用户/程序) #mermaid-svg-9xuwhDYB5SVephq4{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-9xuwhDYB5SVephq4 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-9xuwhDYB5SVephq4 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-9xuwhDYB5SVephq4 .error-icon{fill:#552222;}#mermaid-svg-9xuwhDYB5SVephq4 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-9xuwhDYB5SVephq4 .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-9xuwhDYB5SVephq4 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-9xuwhDYB5SVephq4 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-9xuwhDYB5SVephq4 .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-9xuwhDYB5SVephq4 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-9xuwhDYB5SVephq4 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-9xuwhDYB5SVephq4 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-9xuwhDYB5SVephq4 .marker.cross{stroke:#333333;}#mermaid-svg-9xuwhDYB5SVephq4 svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-9xuwhDYB5SVephq4 p{margin:0;}#mermaid-svg-9xuwhDYB5SVephq4 .actor{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-9xuwhDYB5SVephq4 text.actor>tspan{fill:black;stroke:none;}#mermaid-svg-9xuwhDYB5SVephq4 .actor-line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-9xuwhDYB5SVephq4 .innerArc{stroke-width:1.5;stroke-dasharray:none;}#mermaid-svg-9xuwhDYB5SVephq4 .messageLine0{stroke-width:1.5;stroke-dasharray:none;stroke:#333;}#mermaid-svg-9xuwhDYB5SVephq4 .messageLine1{stroke-width:1.5;stroke-dasharray:2,2;stroke:#333;}#mermaid-svg-9xuwhDYB5SVephq4 #arrowhead path{fill:#333;stroke:#333;}#mermaid-svg-9xuwhDYB5SVephq4 .sequenceNumber{fill:white;}#mermaid-svg-9xuwhDYB5SVephq4 #sequencenumber{fill:#333;}#mermaid-svg-9xuwhDYB5SVephq4 #crosshead path{fill:#333;stroke:#333;}#mermaid-svg-9xuwhDYB5SVephq4 .messageText{fill:#333;stroke:none;}#mermaid-svg-9xuwhDYB5SVephq4 .labelBox{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-9xuwhDYB5SVephq4 .labelText,#mermaid-svg-9xuwhDYB5SVephq4 .labelText>tspan{fill:black;stroke:none;}#mermaid-svg-9xuwhDYB5SVephq4 .loopText,#mermaid-svg-9xuwhDYB5SVephq4 .loopText>tspan{fill:black;stroke:none;}#mermaid-svg-9xuwhDYB5SVephq4 .loopLine{stroke-width:2px;stroke-dasharray:2,2;stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-9xuwhDYB5SVephq4 .note{stroke:#aaaa33;fill:#fff5ad;}#mermaid-svg-9xuwhDYB5SVephq4 .noteText,#mermaid-svg-9xuwhDYB5SVephq4 .noteText>tspan{fill:black;stroke:none;}#mermaid-svg-9xuwhDYB5SVephq4 .activation0{fill:#f4f4f4;stroke:#666;}#mermaid-svg-9xuwhDYB5SVephq4 .activation1{fill:#f4f4f4;stroke:#666;}#mermaid-svg-9xuwhDYB5SVephq4 .activation2{fill:#f4f4f4;stroke:#666;}#mermaid-svg-9xuwhDYB5SVephq4 .actorPopupMenu{position:absolute;}#mermaid-svg-9xuwhDYB5SVephq4 .actorPopupMenuPanel{position:absolute;fill:#ECECFF;box-shadow:0px 8px 16px 0px rgba(0,0,0,0.2);filter:drop-shadow(3px 5px 2px rgb(0 0 0 / 0.4));}#mermaid-svg-9xuwhDYB5SVephq4 .actor-man line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-9xuwhDYB5SVephq4 .actor-man circle,#mermaid-svg-9xuwhDYB5SVephq4 line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;stroke-width:2px;}#mermaid-svg-9xuwhDYB5SVephq4 :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} ① 请求"帮我创建一个 Instance"② 必要处理后发消息"让 Scheduler 建实例"③ Scheduler 取消息,执行调度算法,选出节点 A④ 发消息"在节点 A 上创建 Instance"⑤ Compute 取消息,通过本节点 Hypervisor Driver 创建 Instance⑥ 需要查/更新数据库时发消息给 ConductorConductor 负责数据库访问

观察方法:在 nova.conf 打开 debug,分别 tail -f 四个组件日志(nova-api、nova-scheduler、nova-conductor、nova-compute),再创建实例,即可看到消息流转现象。

6.2 详细流程(Step1 -- Step29)

Cinder Neutron Glance nova-compute nova-conductor RabbitMQ nova-scheduler 数据库 nova-api Keystone Dashboard/CLI Cinder Neutron Glance nova-compute nova-conductor RabbitMQ nova-scheduler 数据库 nova-api Keystone Dashboard/CLI #mermaid-svg-zi1VDJcwsto32J91{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-zi1VDJcwsto32J91 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-zi1VDJcwsto32J91 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-zi1VDJcwsto32J91 .error-icon{fill:#552222;}#mermaid-svg-zi1VDJcwsto32J91 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-zi1VDJcwsto32J91 .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-zi1VDJcwsto32J91 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-zi1VDJcwsto32J91 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-zi1VDJcwsto32J91 .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-zi1VDJcwsto32J91 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-zi1VDJcwsto32J91 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-zi1VDJcwsto32J91 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-zi1VDJcwsto32J91 .marker.cross{stroke:#333333;}#mermaid-svg-zi1VDJcwsto32J91 svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-zi1VDJcwsto32J91 p{margin:0;}#mermaid-svg-zi1VDJcwsto32J91 .actor{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-zi1VDJcwsto32J91 text.actor>tspan{fill:black;stroke:none;}#mermaid-svg-zi1VDJcwsto32J91 .actor-line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-zi1VDJcwsto32J91 .innerArc{stroke-width:1.5;stroke-dasharray:none;}#mermaid-svg-zi1VDJcwsto32J91 .messageLine0{stroke-width:1.5;stroke-dasharray:none;stroke:#333;}#mermaid-svg-zi1VDJcwsto32J91 .messageLine1{stroke-width:1.5;stroke-dasharray:2,2;stroke:#333;}#mermaid-svg-zi1VDJcwsto32J91 #arrowhead path{fill:#333;stroke:#333;}#mermaid-svg-zi1VDJcwsto32J91 .sequenceNumber{fill:white;}#mermaid-svg-zi1VDJcwsto32J91 #sequencenumber{fill:#333;}#mermaid-svg-zi1VDJcwsto32J91 #crosshead path{fill:#333;stroke:#333;}#mermaid-svg-zi1VDJcwsto32J91 .messageText{fill:#333;stroke:none;}#mermaid-svg-zi1VDJcwsto32J91 .labelBox{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-zi1VDJcwsto32J91 .labelText,#mermaid-svg-zi1VDJcwsto32J91 .labelText>tspan{fill:black;stroke:none;}#mermaid-svg-zi1VDJcwsto32J91 .loopText,#mermaid-svg-zi1VDJcwsto32J91 .loopText>tspan{fill:black;stroke:none;}#mermaid-svg-zi1VDJcwsto32J91 .loopLine{stroke-width:2px;stroke-dasharray:2,2;stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-zi1VDJcwsto32J91 .note{stroke:#aaaa33;fill:#fff5ad;}#mermaid-svg-zi1VDJcwsto32J91 .noteText,#mermaid-svg-zi1VDJcwsto32J91 .noteText>tspan{fill:black;stroke:none;}#mermaid-svg-zi1VDJcwsto32J91 .activation0{fill:#f4f4f4;stroke:#666;}#mermaid-svg-zi1VDJcwsto32J91 .activation1{fill:#f4f4f4;stroke:#666;}#mermaid-svg-zi1VDJcwsto32J91 .activation2{fill:#f4f4f4;stroke:#666;}#mermaid-svg-zi1VDJcwsto32J91 .actorPopupMenu{position:absolute;}#mermaid-svg-zi1VDJcwsto32J91 .actorPopupMenuPanel{position:absolute;fill:#ECECFF;box-shadow:0px 8px 16px 0px rgba(0,0,0,0.2);filter:drop-shadow(3px 5px 2px rgb(0 0 0 / 0.4));}#mermaid-svg-zi1VDJcwsto32J91 .actor-man line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-zi1VDJcwsto32J91 .actor-man circle,#mermaid-svg-zi1VDJcwsto32J91 line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;stroke-width:2px;}#mermaid-svg-zi1VDJcwsto32J91 :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} Step1 以 REST API 申请创建 VM,请求授权1Step2 认证信息,生成 auth-token 返回2Step3 携带 auth-token,RESTful 请求 boot instance3Step4 发送认证请求,校验 token4Step5 验证 token 有效,返回认证与角色(权限)5Step6 认证通过,nova-api 与数据库通讯6Step7 初始化新建虚拟机的数据库记录7Step8 rpc.call 请求是否有创建资源(Host ID)8Step9 scheduler 监听队列,获取 nova-api 请求9Step10 查询计算资源情况,调度算法选出符合主机10Step11 更新数据库中 VM 对应的物理主机信息11Step12 rpc.cast 发送创建 VM 请求消息12Step13 compute 从队列获取创建 VM 请求消息13Step14 rpc.call 请求获取虚拟机信息14Step15 conductor 从队列拿到 compute 请求15Step16 根据消息查询虚拟机对应信息16Step17 从数据库获得虚拟机对应信息17Step18 把虚拟机信息发送到消息队列18Step19 从队列获取虚拟机信息消息19Step20 拿 token,HTTP 请求 glance-api 取镜像20Step21 glance 向 keystone 认证 token21返回验证结果22Step22 验证通过,获得镜像信息(URL)23Step23 拿 token,HTTP 请求 neutron-server 取网络信息24Step24 neutron 认证 token25返回验证结果26Step25 验证通过,获得网络信息27Step26 拿 token,HTTP 请求 cinder-api 取持久化存储28Step27 cinder 认证 token29返回验证结果30Step28 验证通过,获得持久化存储信息31Step29 根据 instance 信息调用虚拟化驱动(KVM)创建虚拟机32

Step1--29 文字要点(逐条对照):

阶段 步骤 关键动作
认证 Step1--2 用户向 Keystone 申请授权,获得 auth-token
API 受理 Step3--5 nova-api 带 token 接收 boot 请求,再向 Keystone 校验 token 与角色权限
建记录 Step6--7 nova-api 与数据库通讯,初始化 VM 数据库记录
调度 Step8--12 rpc.call 给 scheduler;scheduler 查库、算调度、更新主机信息;rpc.cast 派给 compute
取 VM 信息 Step13--19 compute 经 conductor 取数据库中的虚拟机信息(conductor 做数据库代理)
取镜像 Step20--22 compute 向 Glance 认证并拿到镜像 URL
取网络 Step23--25 compute 向 Neutron 认证并拿到网络信息
取存储 Step26--28 compute 向 Cinder 认证并拿到持久化存储信息
建机 Step29 compute 调用配置的虚拟化驱动(libvirt/KVM)真正创建虚拟机

记忆锚点:"认证→建记录→call 调度→cast 给 compute→经 conductor 取信息→分别找 Glance(20-22)、Neutron(23-25)、Cinder(26-28)→Step29 KVM 建机"。


七、实例生命周期与操作

7.1 实例操作总览(Dashboard + CLI 对照)

操作 Dashboard CLI 命令 结果状态
关闭 关闭实例 openstack server stop <名> 关机
启动 启动实例 openstack server start <名> 运行中
软重启 软重启实例 openstack server reboot <名>(=--soft) 运行
硬重启 硬重启实例 openstack server reboot --hard <名> 运行
暂停 暂停实例 openstack server pause <名> 状态"暂停"/电源"已暂停"
恢复(解暂停) 恢复实例 openstack server unpause <名> 运行
挂起 挂起实例 openstack server suspend <名> 状态"挂起"/电源"关闭"
恢复(解挂起) 恢复实例 openstack server resume <名> 运行
废弃 废弃实例 openstack server shelve <名> 状态"强制搁置"/电源"关闭"
取消废弃 取消废弃实例 openstack server unshelve <名> 运行
锁定 锁定实例 openstack server lock <名> 出现锁标志
解锁 解锁实例 openstack server unlock <名> 锁标志消失
快照 创建快照 openstack server image create --name <快照名> <名> 镜像列表新增"快照"
重建 重建实例 openstack server rebuild --image <镜像> <名> Active
调整规格 调整实例大小 openstack server resize --flavor <新规格> <名> "确认或放弃调整大小/迁移"
确认调整 确认调整大小/迁移 openstack server resize confirm <名> 运行
删除 删除实例 openstack server delete <名> 列表为空

查看状态:

bash 复制代码
openstack server show <实例名> | grep status
openstack server list | grep <实例名>

7.2 软重启 vs 硬重启

维度 soft reboot hard reboot
本质 只重启操作系统,整个过程 Instance 仍处于运行状态,相当于 Linux 里执行 reboot 重启 Instance,相当于关机之后再开机

7.3 暂停 Pause vs 挂起 Suspend(高频考点)

维度 Pause(暂停) Suspend(挂起)
状态保存位置 宿主机内存 宿主机磁盘
适用时长 短时间暂停 长时间暂停(类似休眠)
恢复速度 快(从内存读回) 慢(从磁盘读回)
Instance 状态 Paused(暂停) Shut Down(挂起/关闭)
恢复命令(内部) 叫 Unpause (unpause) 才是真正的 Resume (resume)
  • 相同点:都是暂停 Instance 运行并保存当前状态,之后都通过"恢复"操作回到运行态。
  • 不同点 :① 存内存 vs 存磁盘,Pause 恢复更快;② 状态分别是 Paused vs Shut Down;③ 两者虽都叫"恢复",Pause 对应的恢复内部叫 Unpause ,Suspend 对应的才叫真正 Resume,这在日志里能体现。
bash 复制代码
openstack server pause Instance_cli_01     # 暂停(状态 Paused)
openstack server unpause Instance_cli_01   # 恢复暂停
openstack server suspend Instance_cli_01   # 挂起(状态 Shut Down)
openstack server resume Instance_cli_01    # 恢复挂起

思考题(应用场景):

  • Pause 适合"几秒到几分钟内还要继续用、想立刻回到原状态"的临时冻结(如排障时希望 VM 保持现场又不想占用 CPU)。
  • Suspend 适合"几小时/几天不用、但不想丢内存现场"的长时间休眠,节省 CPU 但仍保留内存到磁盘。

7.4 废弃 Shelve(搁置)

  • Instance 被 Suspend 后虽处于 Shut Down,但 Hypervisor 仍在宿主机上为其预留资源,以便以后能成功 Resume。
  • 若想释放这些预留资源 ,用 Shelve :把 Instance 作为 image 保存到 Glance,然后在宿主机上删除该 Instance。
  • 恢复用 unshelve(取消废弃 / 解搁置)。
bash 复制代码
openstack server shelve Instance_cli_01     # 废弃:存为镜像并释放资源
openstack server unshelve Instance_cli_01 # 取消废弃

思考题(废弃的应用场景):与暂停/挂起相比,废弃适合"较长时间不用、希望立即释放计算/内存资源省钱,但以后还可能基于镜像找回这台 VM"的场景。它会把 VM 存成镜像后把节点资源完全还回去。

7.5 锁定 Lock(防误删)

场景 结果
管理员对已上锁实例,不解锁直接删除 能
管理员上锁后,普通用户直接删除 不能
管理员创建、不上锁的实例,普通用户直接删除 能
普通用户能否解锁 admin 锁定的实例 能(默认策略)

为什么普通用户能解锁?看 Dashboard 策略文件:

bash 复制代码
[root@controller ~(keystone_admin)]# cd /etc/openstack-dashboard/
[root@controller openstack-dashboard(keystone_admin)]# ls
# cinder_policy.json  glance_policy.json  keystone_policy.json  local_settings
# local_settings.d  neutron_policy.json  nova_policy.d  nova_policy.json
[root@controller openstack-dashboard(keystone_admin)]# vim nova_policy.json
69 "os_compute_api:os-lock-server:lock": "rule:admin_or_owner",
70 "os_compute_api:os-lock-server:unlock": "rule:admin_or_owner",
71 "os_compute_api:os-lock-server:unlock:unlock_override": "rule:admin_api",
  • 默认 unlock 策略是 admin_or_owner,所以普通用户(作为 owner)能解锁,解锁后就能删------等于"防误删"没防住。
  • 要让普通用户不能解锁 ,把第 70 行改为 rule:admin_api:
bash 复制代码
69 "os_compute_api:os-lock-server:lock": "rule:admin_or_owner",
70 "os_compute_api:os-lock-server:unlock": "rule:admin_api",
71 "os_compute_api:os-lock-server:unlock:unlock_override": "rule:admin_api",
  • 实验效果:切换到普通用户不能解锁,admin 能解锁(需清空网页缓存生效)。

7.6 快照 Snapshot 与重建 Rebuild

bash 复制代码
# 创建快照(自动跳到镜像列表,类型=快照,可见性=私有,受保护=否)
openstack server image create --name Instance_Snap_cli Instance_cli_01
openstack image list
# 重建(用快照/原镜像恢复)
openstack server rebuild --image Instance_Snap_cli Instance_cli_01
openstack server show Instance_cli_01 | grep image
  • 快照本质是把系统盘做成 Glance 镜像;若镜像长时间停在"已排队",刷新页面即可。
  • 思考题 :VM 运行中意外损坏、无法打开,如何恢复到快照前状态?→ 用 rebuild --image <快照> 重建,状态回到 Active、镜像名变为快照名,再到控制台验证能否登录。
  • 虚拟机崩溃了,也可以拿原有镜像直接重建。

7.7 调整规格 Resize(含迁移)

bash 复制代码
openstack server show Instance_cli_01 | grep flavor     # 看原规格
openstack flavor create --vcpus 1 --ram 156 --disk 1 Flavor_cli_new
openstack server resize --flavor Flavor_cli_new Instance_cli_01
# 状态变为"确认或放弃 调整大小/迁移"
openstack server resize confirm Instance_cli_01        # 确认
# 规格从 Flavor_cli 变为 Flavor_cli_new,即调整成功
  • 多节点环境下 resize 会伴随迁移 ,需要共享存储(NFS + Cinder 对接),相关配置在 Cinder 章节,本实验暂时看不到现象。
  • 验证思考题 :若把新规格 RAM 设为 64MB,Resize 能成功吗?→ 会失败,因为多节点 resize 本质要迁移,没有共享存储 NFS + Cinder 对接就迁不过去。

7.8 实例状态机(补充)

#mermaid-svg-XIbV6XNgEKdjdWe8{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-XIbV6XNgEKdjdWe8 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-XIbV6XNgEKdjdWe8 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-XIbV6XNgEKdjdWe8 .error-icon{fill:#552222;}#mermaid-svg-XIbV6XNgEKdjdWe8 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-XIbV6XNgEKdjdWe8 .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-XIbV6XNgEKdjdWe8 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-XIbV6XNgEKdjdWe8 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-XIbV6XNgEKdjdWe8 .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-XIbV6XNgEKdjdWe8 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-XIbV6XNgEKdjdWe8 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-XIbV6XNgEKdjdWe8 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-XIbV6XNgEKdjdWe8 .marker.cross{stroke:#333333;}#mermaid-svg-XIbV6XNgEKdjdWe8 svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-XIbV6XNgEKdjdWe8 p{margin:0;}#mermaid-svg-XIbV6XNgEKdjdWe8 .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-XIbV6XNgEKdjdWe8 .cluster-label text{fill:#333;}#mermaid-svg-XIbV6XNgEKdjdWe8 .cluster-label span{color:#333;}#mermaid-svg-XIbV6XNgEKdjdWe8 .cluster-label span p{background-color:transparent;}#mermaid-svg-XIbV6XNgEKdjdWe8 .label text,#mermaid-svg-XIbV6XNgEKdjdWe8 span{fill:#333;color:#333;}#mermaid-svg-XIbV6XNgEKdjdWe8 .node rect,#mermaid-svg-XIbV6XNgEKdjdWe8 .node circle,#mermaid-svg-XIbV6XNgEKdjdWe8 .node ellipse,#mermaid-svg-XIbV6XNgEKdjdWe8 .node polygon,#mermaid-svg-XIbV6XNgEKdjdWe8 .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-XIbV6XNgEKdjdWe8 .rough-node .label text,#mermaid-svg-XIbV6XNgEKdjdWe8 .node .label text,#mermaid-svg-XIbV6XNgEKdjdWe8 .image-shape .label,#mermaid-svg-XIbV6XNgEKdjdWe8 .icon-shape .label{text-anchor:middle;}#mermaid-svg-XIbV6XNgEKdjdWe8 .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-XIbV6XNgEKdjdWe8 .rough-node .label,#mermaid-svg-XIbV6XNgEKdjdWe8 .node .label,#mermaid-svg-XIbV6XNgEKdjdWe8 .image-shape .label,#mermaid-svg-XIbV6XNgEKdjdWe8 .icon-shape .label{text-align:center;}#mermaid-svg-XIbV6XNgEKdjdWe8 .node.clickable{cursor:pointer;}#mermaid-svg-XIbV6XNgEKdjdWe8 .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-XIbV6XNgEKdjdWe8 .arrowheadPath{fill:#333333;}#mermaid-svg-XIbV6XNgEKdjdWe8 .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-XIbV6XNgEKdjdWe8 .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-XIbV6XNgEKdjdWe8 .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-XIbV6XNgEKdjdWe8 .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-XIbV6XNgEKdjdWe8 .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-XIbV6XNgEKdjdWe8 .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-XIbV6XNgEKdjdWe8 .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-XIbV6XNgEKdjdWe8 .cluster text{fill:#333;}#mermaid-svg-XIbV6XNgEKdjdWe8 .cluster span{color:#333;}#mermaid-svg-XIbV6XNgEKdjdWe8 div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-XIbV6XNgEKdjdWe8 .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-XIbV6XNgEKdjdWe8 rect.text{fill:none;stroke-width:0;}#mermaid-svg-XIbV6XNgEKdjdWe8 .icon-shape,#mermaid-svg-XIbV6XNgEKdjdWe8 .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-XIbV6XNgEKdjdWe8 .icon-shape p,#mermaid-svg-XIbV6XNgEKdjdWe8 .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-XIbV6XNgEKdjdWe8 .icon-shape .label rect,#mermaid-svg-XIbV6XNgEKdjdWe8 .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-XIbV6XNgEKdjdWe8 .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-XIbV6XNgEKdjdWe8 .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-XIbV6XNgEKdjdWe8 :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 建机成功
失败
stop 关机
start 开机
pause
unpause
suspend 电源关
resume
shelve 存镜像并释放资源
unshelve
resize 待确认
confirm 确认
revert 回退
rebuild/reboot
delete
delete
BUILD(创建中)
Active 运行中
Error
Stopped
Paused
Suspended
Shelved
Resize_verify

补充:Nova 实际用三套状态描述一台实例:

  • vm_state :逻辑状态(active / error / build / stopped / paused / suspended / shelved / deleted 等);
  • power_state:电源状态(运行/关机/暂停等,来自 hypervisor);
  • task_state :当前正在执行的任务(scheduling、spawning、image_snapshot、resize_prep 等),是一个临时过渡态。

7.9 迁移相关(补充)

方式 别名 是否停机 存储要求 说明
冷迁移 cold migration migrate 短暂关机 共享/非共享均可 在不同计算节点间换主机,VM 短暂暂停
热迁移 live migration live-migration 业务不中断 通常要求共享存储(块迁移除外) 内存逐级拷贝,业务感知不到中断
resize 调规格 类似迁移 多节点需共享存储 换规格,本质"迁移到新规格"
evacuate 故障撤离 节点已挂 共享存储 计算节点故障宕机后,在其他节点基于共享存储重建实例

补充前提条件:热迁移要求源/目节点 CPU 兼容、时间同步、镜像/磁盘在共享存储上;非共享存储用块块迁移(block migration)。


八、Dashboard 与 CLI 完整操作步骤

8.1 主机聚合与可用分区(Dashboard)

  1. admin 登录,管理员 > 计算 > 虚拟机管理器,看概览;"计算主机"页签看计算节点。
  2. 管理员 > 计算 > 主机聚合 > 创建主机聚合 :名称 HostAggr_web,可用分区 nova;"管理聚合内的主机"加入 controller。
  3. 验证 1(同一主机能否加入不同 AZ) :建 HostAggr_web_test,AZ 设为 AZ_web,加主机 controller。
  4. 验证 2(同一主机能否加入不同主机聚合) :把 HostAggr_web_test 的 AZ 改回 nova,再"管理主机"加 controller。
  5. "管理主机"把主机移回左侧可用列表 → 保存;勾选 HostAggr_web_test → 删除主机聚合。

CLI 对照:

bash 复制代码
source kestonerc_admin                       # 教材原文如此拼写
openstack hypervisor list --long             # 查看 Hypervisor 列表
openstack host list                          # 查看主机列表
openstack aggregate create --zone nova HostAggr_cli
openstack aggregate add host HostAggr_cli controller

# 验证同一主机能否加入不同 AZ
openstack aggregate create --zone AZ_cli HostAggr_cli_test
openstack aggregate add host HostAggr_cli_test controller
# 验证同一主机能否加入不同主机聚合
openstack aggregate set --zone nova HostAggr_cli_test
openstack aggregate show HostAggr_cli_test
openstack aggregate add host HostAggr_cli_test controller

openstack aggregate remove host HostAggr_cli_test controller
openstack aggregate delete HostAggr_cli_test
openstack aggregate list

补充:AZ 是主机聚合的一种特例 ------带 availability_zone metadata 的聚合就表现为 AZ。一个主机可以属于多个主机聚合,但在 AZ 维度上最终归属一个 AZ(实验中需先改 AZ 才能重复加入);聚合还可挂自定义 metadata 配合调度。

8.2 规格(Flavor)管理

Dashboard :管理员 > 计算 > 实例类型 > 创建实例类型。填名称 Flavor_web、VCPUs=1、RAM=128MB、Root Disk=1GB;"实例类型使用权"选择项目 Project_web。若不选任何项目,则默认对所有项目可用(Public)。

验证(移除项目后是否变 Public?) :点"修改使用权",把已选项目移除 → 保存。

结论:

  1. 规格仍为 Private ------移除所有项目只表示"没有任何项目可用它"(admin 能看不能用,其他用户连看都看不到),并不是 Public。
  2. 规格创建后不支持变更 Public/Private,要变只能删掉重建。

CLI 对照:

bash 复制代码
# 私有、仅对 Project_cli 可见
openstack flavor create --vcpus 1 --ram 128 --disk 1 --private --project Project_cli Flavor_cli
openstack flavor unset --project Project_cli Flavor_cli   # 移除项目授权
openstack flavor show Flavor_cli                          # 仍不是 Public
openstack flavor delete Flavor_cli
# 不带 --private 创建,默认为 Public
openstack flavor create --vcpus 1 --ram 128 --disk 1 Flavor_cli

补充:flavor 还可设置 extra specs (如 hw:cpu_policy、pci_passthrough、与 ComputeCapabilitiesFilter 配合的架构约束)、metadata;实例启动时可注入 config drive 、通过 keypair 注入 SSH 公钥、通过安全组(security group)做访问控制。

8.3 密钥对与服务器组

bash 复制代码
# Dashboard:项目 > 计算 > 密钥对 > 创建密钥对 KeyPair_web,类型 SSH Key,下载私钥
openstack keypair create KeyPair_cli

# Dashboard:项目 > 计算 > 主机组 > 创建服务器组,4 策略:关联/不关联/软不关联/软关联
openstack server group create --policy affinity ServerGroup_cli   # 记录其 ID

8.4 创建网络与 shared 网络

  • Dashboard:项目 > 网络 > 网络,创建网络;可创建 shared(共享) 网络供多项目共用。CLI 中实验用 --network shared 指定。

8.5 发放实例(Dashboard 分步)

  1. 项目 > 计算 > 实例 > 创建实例:名称 Instance_web_01,AZ 选 nova,数量 1。
  2. "源"页签:创建新卷选"否",把镜像 Img_web 加到"已分配"。
  3. "实例类型"页签:选 Flavor_web_test。
  4. "网络"页签:确认网络已分配。
  5. "Key Pair"页签:选 KeyPair_web。
  6. "服务器组"页签:选 ServerGroup_web(含策略)→ 创建实例,状态为"运行"。

CLI 一条命令发放:

bash 复制代码
openstack server create \
  --availability-zone nova \
  --image Img_cli \
  --flavor Flavor_cli \
  --network shared \
  --key-name KeyPair_cli \
  --hint group=SERVER_GROUP_ID \
  Instance_cli_01

openstack server list          # 状态 Active 即创建成功

九、日志与排障

9.1 日志位置

组件 日志文件
nova-api /var/log/nova/nova-api.log
nova-scheduler /var/log/nova/nova-scheduler.log
nova-conductor /var/log/nova/nova-conductor.log
nova-compute /var/log/nova/nova-compute.log
bash 复制代码
# 开 debug(生产无故障勿开)
vim /etc/nova/nova.conf   # 694 debug=True
systemctl restart openstack-nova*
# 实时观察各组件
tail -f /var/log/nova/nova-api.log
tail -f /var/log/nova/nova-scheduler.log
tail -f /var/log/nova/nova-conductor.log
tail -f /var/log/nova/nova-compute.log
# 过滤调度关键日志
grep Filter  nova-scheduler.log
grep weight  nova-scheduler.log
grep Select  nova-scheduler.log

9.2 RabbitMQ 性能监控

bash 复制代码
systemctl status rabbitmq-server.service
# 默认只能用命令行:
rabbitmqctl list_queues
rabbitmqctl list_exchanges
# 启用图形管理插件
rabbitmq-plugins enable rabbitmq_management
# 开防火墙(实验环境直接清规则)
iptables -F
# 创建控制台用户并授权
rabbitmqctl add_user user_admin passwd_admin
rabbitmqctl set_user_tags user_admin administrator
rabbitmqctl set_permissions -p / user_admin ".*" ".*" ".*"
# 浏览器访问
# http://192.168.108.10:15672  (user_admin / passwd_admin)
  • Unacked Message = 还没被处理的消息,正常应为 0。
  • 若 Unacked 不为 0 且持续增长,说明 RabbitMQ 出问题、队列积压------严重信号。
  • 点开 Overview 后面的标签,定位到底是哪个 Connection / Channel / Exchange / Queue 在堆积,再分析根因。

补充:组件之间消息都走 RabbitMQ;若实例一直停在 BUILD/ERROR,先看 nova-compute.log 与 RabbitMQ 队列积压情况。


十、易混点对比表(速查)

易混点 区别
Pause vs Suspend Pause 存内存、状态 Paused、恢复叫 Unpause、快;Suspend 存磁盘、状态 Shut Down、恢复叫 Resume、慢
Shelve vs Suspend Suspend 仍保留资源;Shelve 存成 Glance 镜像并释放节点资源
Affinity vs Anti-affinity 同节点 vs 分散到不同节点
Host Aggregate vs Server Group 聚合管主机 (可带 metadata、可表现为 AZ);服务器组管实例(亲和策略)
AZ vs Host Aggregate AZ 是带 availability_zone 标记的特殊聚合
soft vs hard reboot 软重启 OS(仍运行)vs 硬重启(关机再开机)
RamFilter/DiskFilter/CoreFilter 资源类过滤器,默认未启用,资源校验已交给 Placement
ComputeFilter 必选,只调度 nova-compute 正常的节点
flavor Public vs Private 创建后不可改;不选项目≠Public,要 Public 须创建时不带 --private
rpc.call vs rpc.cast call 同步等返回;cast 异步单向

十一、补充内容(教材之外、但必须掌握)

  • Cells v2(补充):单集群规模过大时,Nova 用 Cells v2 做横向扩展------把计算节点按 cell 划分,每个 cell 有自己的消息队列和数据库;全局 cell(cell0)专门存放构建失败的实例,避免污染主调度。
  • Placement(补充):见 4.2,resource provider / inventory / allocation / trait / aggregate。
  • 实例状态机(补充):vm_state / power_state / task_state 三套状态,见 7.8。
  • 迁移(补充):cold migration / live migration(共享存储与非共享块迁移前提)、resize 与 revert、rebuild、snapshot、evacuate,见 7.9。
  • 主机聚合与 AZ 关系(补充):AZ 是聚合特例,metadata 调度,见 8.1。
  • flavor extra specs / metadata / config drive / keypair / 安全组注入(补充):见 8.2。
  • 控制台(补充):VNC(novncproxy)/ SPICE(spicehtml5proxy)/ serial proxy,见 3.5.5。
  • 配额 quota(补充):每个项目可限制 vCPU 数、实例数、内存、卷数等,防止单项目吃光资源。
  • QEMU / KVM / libvirt(补充):见 3.5.4。
  • NUMA / CPU pinning / 大页 huge pages(补充,进阶):为高性能/低延迟 VM 提供 NUMA 亲和、绑定物理 CPU、大页内存,通过 flavor extra specs 声明。
  • ServerGroup soft 策略(补充):soft-anti-affinity / soft-affinity,资源不足时忽略软规则,见 5.3。
  • Nova 与 Ceph(补充):实例的临时盘(ephemeral disk)可后端到 Ceph RBD,实现共享块存储、支撑热迁移与 evacuate。

本篇小结

  1. Nova 是计算引擎,六大组件 API / Scheduler / Compute / Conductor / Placement / DB 经 oslo.messaging(RabbitMQ) 以"无共享"RPC 协作。
  2. conductor 三理由:安全(compute 不直连库)、解耦升级、RPC 绿色线程友好提并发。
  3. 调度 = 过滤(6 个默认 filter)+ 权重(默认空闲内存);RetryFilter 排第一、重试 3 次;Ram/Disk/CoreFilter 默认关闭。
  4. 超分比例 CPU 16 / 内存 1.5 / 磁盘 1。
  5. 创建 VM 记牢 29 步时序:认证→建记录→call 调度→cast 给 compute→conductor 取信息→Glance/Neutron/Cinder→KVM 建机。
  6. 实例操作分清 Pause(内存)/ Suspend(磁盘)/ Shelve(释放资源存镜像)/ Lock(防误删,策略改 admin_api)。

重点速记

速记项 答案
超分比 cpu=16、ram=1.5、disk=1
8 vCPU 节点视为 128 vCPU
默认 enabled_filters AvailabilityZoneFilter / ComputeFilter / ComputeCapabilitiesFilter / ImagePropertiesFilter / ServerGroupAntiAffinityFilter / ServerGroupAffinityFilter
调度重试次数 scheduler_max_attempts = 3
默认 Weight 空闲内存越多分越高
Pause 恢复命令 openstack server unpause
Suspend 恢复命令 openstack server resume
Shelve 恢复 openstack server unshelve
最小建实例三要素 flavor + image + network
控制台地址 http://控制节点:15672(RabbitMQ 管理台)
过滤日志关键词 Filter / weight / Select

口诀:

"API 接单、调度过滤加权重、compute 干活、conductor 管库、Placement 记账;内存暂停磁盘挂,存镜像再废弃;十六 CPU 一点五内存磁盘一比一。"

自测题(附答案)

  1. Nova 负责什么、不负责什么?
    答:负责虚拟机及其它计算资源生命周期;不负责物理主机自身管理与全面系统监控。
  2. 引入 nova-conductor 的三个理由?
    答:安全(compute 不直连数据库)、方便升级(DB 与 compute 解耦)、性能(RPC 绿色线程友好,避免阻塞并发)。
  3. 默认的六个 enabled_filters 是哪些?哪几个资源类过滤器默认没启用?
    答:AvailabilityZoneFilter、ComputeFilter、ComputeCapabilitiesFilter、ImagePropertiesFilter、ServerGroupAntiAffinityFilter、ServerGroupAffinityFilter;RamFilter、DiskFilter、CoreFilter 默认未启用。
  4. cpu/ram/disk 超分默认比例?8 vCPU 节点被当成多少?
    答:16 / 1.5 / 1;8×16=128 vCPU。
  5. RetryFilter 的作用?重试几次?
    答:刷掉之前调度失败过的节点;scheduler_max_attempts 默认 3。
  6. Weight 默认按什么打分?
    答:按计算节点空闲内存,空闲越多分越高。
  7. 完整创建 VM 的 29 步中,compute 分别向哪三个服务取资源?对应步骤号?
    答:Glance(20-22 镜像)、Neutron(23-25 网络)、Cinder(26-28 持久化存储),Step29 调 KVM 建机。
  8. Pause 与 Suspend 三点区别?
    答:① 存内存 vs 存磁盘、Pause 恢复快;② 状态 Paused vs Shut Down;③ 恢复内部叫 Unpause vs Resume。
  9. Shelve 做了什么?与 Suspend 最大不同?
    答:把实例存成 Glance 镜像并删除节点实例、释放预留资源;Suspend 仍保留资源。
  10. 普通用户默认为什么能解锁 admin 锁定的实例?如何禁止?
    答:nova_policy.json 中 unlock 默认是 rule:admin_or_owner;改为 rule:admin_api 并清网页缓存即可。
  11. 同一主机能否加入不同 AZ / 不同主机聚合?
    答:主机可属于多个主机聚合;AZ 维度需先调整(改 AZ),最终表现一个主机在 AZ 上归属一个可用分区。
  12. flavor 移除所有项目授权后是否就变 Public?
    答:不是,仍是 Private;Public/Private 创建后不可改,只能删了重建。
相关推荐
IT召唤狮2 小时前
开源企业级零信任项目Pangolin,零信任能挡住PHP核弹漏洞吗?
开发语言·开源·php
Rover Ramble2 小时前
C++ 用互斥锁实现读写锁
开发语言·c++
huainingning2 小时前
Windows syslog日志服务器搭建与模拟器对接
运维·服务器·智能路由器
say_fall3 小时前
【Linux系统编程】Ext 文件系统:磁盘与存储、文件与目录、现代计算机究竟如何寻找文件
linux·运维·服务器·数据库·c++
码流子3 小时前
移动收费怎么做?手持终端+App+收费中心的架构实践
java·开发语言·架构
雪落漂泊3 小时前
C++算法 滑动窗口篇(下)
开发语言·c++
云创智城-yuncitys3 小时前
YunParking 4.0:JDK 17 与 Spring Boot 3.2 的停车云升级
java·开发语言·spring boot
郭小李3 小时前
openFeign入门
java·开发语言·前端
wacsii3 小时前
【Linux进程(一)】Linux 进程初探:操作系统如何管理进程?fork() 为什么返回两次?
linux·运维·服务器