03 · 计算管理 Nova
本篇是 OpenStack 七大模块中最核心的一篇:Nova 负责把"镜像 + 规格 + 网络"变成一台真正可运行的虚拟机。学好 Nova,就等于抓住了 OpenStack 的主干。
本篇导读
- 一句话定位:Nova = OpenStack 的"计算引擎 / 虚拟机工厂",负责虚拟机全生命周期管理。
- 两条主线 :① 一台 VM 从用户点"创建"到真正跑起来,系统内部发生了什么(29 步时序 );② 系统凭什么决定把这台 VM 放在哪台物理机上(调度器:过滤 + 权重)。
- 三个高频考点:调度过滤器、暂停/挂起/废弃的区别、资源超分比例。
- 学法建议:先建立"组件地图",再追"创建 VM 时序",最后用 Dashboard + CLI 两条路径把每个操作各做一遍。
学习目标
学完本篇,你应当能够:
- 说出 Nova 的六大组件(API / Scheduler / Compute / Conductor / Placement / DB)各自职责与通信方式(oslo.messaging / RPC)。
- 讲清 nova-conductor 被引入的三大理由(安全、解耦升级、并发性能)。
- 默写默认
enabled_filters六个过滤器,并能结合实验解释 AZ、主机聚合、server group 如何影响调度。 - 记住资源超分默认比例:
cpu=16、ram=1.5、disk=1。 - 完整复述创建 VM 的 6 步简化流程与 Step1--Step29 详细时序。
- 区分 Pause / Suspend / Shelve / Lock / Rebuild / Resize / Snapshot 的状态、资源占用与适用场景。
- 用 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 :
bashscheduler_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)
- admin 登录,管理员 > 计算 > 虚拟机管理器,看概览;"计算主机"页签看计算节点。
- 管理员 > 计算 > 主机聚合 > 创建主机聚合 :名称
HostAggr_web,可用分区nova;"管理聚合内的主机"加入controller。 - 验证 1(同一主机能否加入不同 AZ) :建
HostAggr_web_test,AZ 设为AZ_web,加主机controller。 - 验证 2(同一主机能否加入不同主机聚合) :把
HostAggr_web_test的 AZ 改回nova,再"管理主机"加controller。 - "管理主机"把主机移回左侧可用列表 → 保存;勾选
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_zonemetadata 的聚合就表现为 AZ。一个主机可以属于多个主机聚合,但在 AZ 维度上最终归属一个 AZ(实验中需先改 AZ 才能重复加入);聚合还可挂自定义 metadata 配合调度。
8.2 规格(Flavor)管理
Dashboard :管理员 > 计算 > 实例类型 > 创建实例类型。填名称 Flavor_web、VCPUs=1、RAM=128MB、Root Disk=1GB;"实例类型使用权"选择项目 Project_web。若不选任何项目,则默认对所有项目可用(Public)。
验证(移除项目后是否变 Public?) :点"修改使用权",把已选项目移除 → 保存。
结论:
- 规格仍为 Private ------移除所有项目只表示"没有任何项目可用它"(admin 能看不能用,其他用户连看都看不到),并不是 Public。
- 规格创建后不支持变更 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 分步)
- 项目 > 计算 > 实例 > 创建实例:名称
Instance_web_01,AZ 选nova,数量 1。 - "源"页签:创建新卷选"否",把镜像
Img_web加到"已分配"。 - "实例类型"页签:选
Flavor_web_test。 - "网络"页签:确认网络已分配。
- "Key Pair"页签:选
KeyPair_web。 - "服务器组"页签:选
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。
本篇小结
- Nova 是计算引擎,六大组件 API / Scheduler / Compute / Conductor / Placement / DB 经 oslo.messaging(RabbitMQ) 以"无共享"RPC 协作。
- conductor 三理由:安全(compute 不直连库)、解耦升级、RPC 绿色线程友好提并发。
- 调度 = 过滤(6 个默认 filter)+ 权重(默认空闲内存);RetryFilter 排第一、重试 3 次;Ram/Disk/CoreFilter 默认关闭。
- 超分比例 CPU 16 / 内存 1.5 / 磁盘 1。
- 创建 VM 记牢 29 步时序:认证→建记录→call 调度→cast 给 compute→conductor 取信息→Glance/Neutron/Cinder→KVM 建机。
- 实例操作分清 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 一点五内存磁盘一比一。"
自测题(附答案)
- Nova 负责什么、不负责什么?
答:负责虚拟机及其它计算资源生命周期;不负责物理主机自身管理与全面系统监控。 - 引入 nova-conductor 的三个理由?
答:安全(compute 不直连数据库)、方便升级(DB 与 compute 解耦)、性能(RPC 绿色线程友好,避免阻塞并发)。 - 默认的六个 enabled_filters 是哪些?哪几个资源类过滤器默认没启用?
答:AvailabilityZoneFilter、ComputeFilter、ComputeCapabilitiesFilter、ImagePropertiesFilter、ServerGroupAntiAffinityFilter、ServerGroupAffinityFilter;RamFilter、DiskFilter、CoreFilter 默认未启用。 - cpu/ram/disk 超分默认比例?8 vCPU 节点被当成多少?
答:16 / 1.5 / 1;8×16=128 vCPU。 - RetryFilter 的作用?重试几次?
答:刷掉之前调度失败过的节点;scheduler_max_attempts默认 3。 - Weight 默认按什么打分?
答:按计算节点空闲内存,空闲越多分越高。 - 完整创建 VM 的 29 步中,compute 分别向哪三个服务取资源?对应步骤号?
答:Glance(20-22 镜像)、Neutron(23-25 网络)、Cinder(26-28 持久化存储),Step29 调 KVM 建机。 - Pause 与 Suspend 三点区别?
答:① 存内存 vs 存磁盘、Pause 恢复快;② 状态 Paused vs Shut Down;③ 恢复内部叫 Unpause vs Resume。 - Shelve 做了什么?与 Suspend 最大不同?
答:把实例存成 Glance 镜像并删除节点实例、释放预留资源;Suspend 仍保留资源。 - 普通用户默认为什么能解锁 admin 锁定的实例?如何禁止?
答:nova_policy.json 中 unlock 默认是rule:admin_or_owner;改为rule:admin_api并清网页缓存即可。 - 同一主机能否加入不同 AZ / 不同主机聚合?
答:主机可属于多个主机聚合;AZ 维度需先调整(改 AZ),最终表现一个主机在 AZ 上归属一个可用分区。 - flavor 移除所有项目授权后是否就变 Public?
答:不是,仍是 Private;Public/Private 创建后不可改,只能删了重建。