我刚接触OpenStack那阵子,最劝退我的不是各种Linux命令,而是那一串串“模块清单”:Keystone、Nova、Neutron、Cinder、Glance、Swift、Heat、Octavia……每一个名字都像是一个独立的品牌,光记住它们干嘛的就能耗掉我半管血。后来真正在一套环境里从镜像上传跑到创建云主机、挂卷、配置网络之后才明白,OpenStack之所以拆成这么多模块,不是因为设计者闲得慌,而是因为它本质上就是一套“数据中心物业公司”——每个模块负责一项专门职能,模块之间通过API和消息队列互相配合。这篇东西我尽量用大白话把OpenStack常见模块的定位、分工、调用关系,以及生产环境里最容易踩的坑一次性讲透。不管你是刚入门想搭一套实验环境,还是工作中要维护现有云平台,都应该能从中找到直接能用的东西。
1. 把OpenStack当物业公司看:先弄清“模块”这个词到底指什么
很多教程一上来直接列模块,很容易让人忽略一个关键问题:所谓“模块”,到底是一个程序、一台机器上的进程,还是一整套服务?
在真实运维中,这个词其实有三种用法。第一种是指顶层服务,比如Nova提供计算能力,Neutron提供网络能力,Cinder提供块存储能力;第二种是指某个服务内部拆出来的子组件,比如Nova就不只是一个服务,它包含nova-api、nova-conductor、nova-scheduler、nova-compute等一堆进程;第三种则会把MySQL、RabbitMQ这类支撑组件也算进“模块”。所以当你看到“某个模块挂了”这种描述,先要确认说的是哪一层,不然排查方向很容易跑偏。
我自己习惯用一个比喻来理解OpenStack的整体架构:把它想象成一个大型物业公司。
- Keystone是门口保安兼前台,负责验证你是谁、给你发临时门禁卡。
- Horizon是访客大厅里那块触摸屏,你通过它提交各种申请,但它自己不做决策。
- Nova是物业客服和工程队的调度中枢,专门负责“给你开一间房”以及后续的上下电、搬迁。
- Neutron是网络施工队,管所有房间的网线、交换机、路由和隔离策略。
- Cinder是硬盘库房,负责给你提供“移动硬盘”,可以插到任意一台云主机上。
- Glance是系统安装盘库房,存着一堆现成的ISO/系统镜像,Nova装系统时去这里取。
- Swift像公司内部的公共网盘,适合存文件,但不适合当数据库磁盘用。
- Heat像装修公司,可以一次按图纸把所有房间、网络、存储全部布置好。
- Octavia像大楼入口的流量分配闸机,负责把请求分摊到多台应用服务器上。
下面这个表更直观,看的时候建议先只看第一列和中间一列,不用急着记进程名。
| 模块/服务 | 大白话定位 | 真实职责 |
|---|---|---|
| Keystone | 前台门卫 | 身份认证、权限校验、服务地址目录 |
| Horizon | 大厅触摸屏 | 提供Web操作界面,本质是API客户端 |
| Nova | 物业调度中心 | 管理虚拟机全生命周期 |
| Placement | 房源空位表 | 记录各计算节点有多少CPU、内存、GPU可分配 |
| Neutron | 网络施工队 | 管理网络、子网、端口、路由、负载均衡、安全组 |
| Glance | 系统安装盘仓库 | 管理虚拟机镜像的元数据和存储位置 |
| Cinder | 移动硬盘库房 | 提供可挂载的块存储卷 |
| Swift | 公共网盘 | 提供对象存储服务 |
| Manila | 共享文件夹 | 提供多台云主机可同时挂载的文件共享 |
| Heat | 装修公司 | 通过模板批量创建和编排整组云资源 |
| Octavia | 流量闸机 | 提供负载均衡服务 |
| Ironic | 裸机出租 | 直接管理物理服务器,不装虚拟化层 |
看这个表可以看出一个规律:OpenStack并不是一个“大而全”的软件,而是把云平台常见的需求一个个拆成独立服务。这个拆法带来两大好处,一是每个模块都能独立升级、独立扩展,计算不够就加计算节点,网络瓶颈就横向扩网络节点;二是模块与模块之间通过API交互,生态好,你可以用其他开源方案替换某个模块。坏处也显而易见——入门成本变高了,排查问题时经常需要跨多个模块看日志。
1.1 先分清楚:服务和组件是两个层级
每个顶层服务内部其实是一群组件在协作。举Nova做例子:你调用创建云主机接口时,请求先到nova-api,它校验权限然后把任务丢给nova-conductor,nova-conductor去数据库和调度器那确认该在哪台物理节点执行,最后消息落到目标节点的nova-compute上,真正动手把虚拟机拉起来。
这里每个nova-xxx都是一个独立进程,部署时可以按角色拆分。比如控制节点可以只跑nova-api和nova-conductor,计算节点只跑nova-compute。这就解释了为什么有时候你用openstack service list看服务状态都是UP,但云主机还是创建失败——问题很可能出在某个计算节点的nova-compute进程状态异常,而不是顶层服务没注册。
看日志的时候也要先分清服务层和组件层。比如Nova相关日志一般在/var/log/nova/下面,里面会按组件分成nova-api.log、nova-compute.log、nova-conductor.log等。我在排障时最常犯的一个错误就是只盯着nova-api.log看,结果真正报错在nova-compute.log里,绕了一大圈才找到原因。
1.2 支撑它们的“基础设施”也别忽略
除了前面那些模块,还有两个隐形基础:数据库和消息队列。几乎每个OpenStack模块都要连MySQL保存自己的业务状态,模块之间有很多异步操作不是靠HTTP同步等结果,而是通过RabbitMQ/AMQP发消息。
还是举例:nova-compute要在某台计算节点创建虚拟机,但nova-api不是直接等虚拟机创建完再返回。实际过程是nova-api把请求写进数据库,然后通过消息队列把任务发给nova-scheduler,调度器算完再把目标主机通过消息队列发给nova-compute。虚拟机最终状态从BUILD变成ACTIVE,是nova-compute异步更新的。
所以如果RabbitMQ出现了积压或连接异常,你看到的典型现象就是“状态一直卡在BUILD半天没反应”,或者“OpenStack页面操作没报错但实际没生效”。这个经验很重要,遇到莫名其妙的任务卡住,第一件事先看RabbitMQ队列有没有堆积,比纠结单个模块日志快得多。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. Keystone和Horizon:“进门”这件小事没搞懂,后面全堵车
在OpenStack里,几乎每个请求都要经过Keystone校验。你可以把它想成公司门口的保安加前台:所有访客先登记,拿着临时工牌进出各个办公区;而对各个办公区来说,工牌上盖了哪个章、有没有对应权限,决定了你能进哪个门、能做哪些操作。
但Keystone真正厉害的不只是“登录认证”,它还有另一个经常被忽略的功能——服务目录。OpenStack各模块在安装完成后,会把各自的API地址注册到Keystone里,比如Nova的endpoint是http://控制节点IP:8774/v2.1,Cinder的endpoint是http://控制节点IP:8776/v1/项目ID。当Horizon或者命令行客户端需要调用某个模块时,第一步不是直接请求目标模块,而是先去问Keystone“Cinder在哪”,然后才拿着这个地址去访问。
所以你会遇到一个很有意思的坑:某模块的配置文件里端口写错了,但你直接访问它可能没问题,因为客户端是先查Keystone服务目录拿到旧地址再访问。改了服务实际监听地址后,一定记得同步更新Keystone里的endpoint,否则很多客户端会一直访问老地址。像命令openstack endpoint list就是用来排查这类问题的。
2.1 Domain、Project、User、Role、Token——五个一次性讲清
这些词是初学OpenStack时最容易混乱的五个概念,我用公司模型来解释:
- Domain:相当于一个集团公司。默认有一个Default域,大多数实验环境里你根本不需要关心多域,但企业级多租户隔离往往通过域实现。
- Project:相当于集团下的一个项目组或子公司,OpenStack里也有“租户”这个老叫法。资源配额是落在Project上的,而不是落在某个用户身上的。
- User:就是登录系统的自然人或者服务账号。同一个用户可以被加入多个Project。
- Role:相当于你在项目组里的岗位,比如admin、member、reader。它决定了你在某个Project里能调用哪些API。
- Token:门禁卡。用用户名密码换来的临时凭证,有效期过了就要重新认证。
最容易被绕晕的就是“一个用户属于多个项目”的情况。比如热搜里有人问“openstack 一个用户属于多个项目”,实际操作很简单:你创建一个用户后,可以把它分别加入Project A和Project B,并且在每个Project里分别授予不同角色。
bash复制# 把用户 alice 添加到 project-a,授予 member 角色
openstack role add --user alice --project project-a member
# 把用户 alice 添加到 project-b,授予 admin 角色
openstack role add --user alice --project project-b admin
# 查看 alice 在所有项目里的角色分配
openstack role assignment list --user alice --names
但注意:用户登录时需要用参数指定要进入哪个Project,否则即使他在两个项目里都有角色,也要先选一个。
bash复制openstack login --project project-a
登录后你看到的资源配额、虚拟机列表都只是当前Project范围内的。很多新手问“为什么我同一个账号,在A项目能建机器,切到B项目就不能建”,其实不是账号权限问题,而是B项目自己的配额或者网络资源没准备好。
2.2 Horizon只是“窗户”,不是“大脑”
Horizon是OpenStack提供的Web控制台,它本质上是一个调用API的展示层。你点击“创建云主机”,它会替你拼接JSON请求发给Nova的API;你看到状态显示ACTIVE,其实是前端不断轮询后端API拿到的结果。
所以遇到问题了,别只盯着Horizon页面报什么错。页面上的错误提示有时候很笼统,真正详细信息要看后端模块的日志,或者直接在命令行用--debug参数重新执行一次API调用,看它到底请求了哪个URL、拿到了什么响应。实践中最快定位问题的方式,永远是绕开图形界面、直接用OpenStack CLI或者curl去看原始API返回,浏览器页面好看,但不适合排障。
3. Nova不是“一个”软件:计算模块内部是一整条流水线
Nova是OpenStack里负责计算资源管理的核心模块,也被称作OpenStack Compute。它做的事情用大白话说,就是“创建一台云主机、管理它的生命周期”。但Nova内部绝不是一个单体进程,而是由多个分工明确的组件组成。
我在这里先给一张最常见的服务对照表,后面排障时会反复提到它们:
| Nova组件 | 角色 | 日志文件 |
|---|---|---|
| nova-api | 对外提供REST API,接收创建虚拟机的HTTP请求 | /var/log/nova/nova-api.log |
| nova-conductor | 处理业务逻辑,访问数据库,协调其他服务 | /var/log/nova/nova-conductor.log |
| nova-scheduler | 从中选择合适计算节点(和Placement配合) | /var/log/nova/nova-scheduler.log |
| nova-compute | 部署在每个计算节点上的代理,真正生成/销毁虚拟机 | /var/log/nova/nova-compute.log |
| nova-novncproxy | 提供浏览器VNC登录窗口 | /var/log/nova/nova-novncproxy.log |
看到这张表,你会发现OpenStack的分布式设计逻辑:你以为你只是在请求“创建一台虚拟机”,实际上这条请求被拆成很多步,每一步都有一个组件在接力。
3.1 Nova各组件是怎么协作的
拿创建一台2核4G内存的云主机举例。你在命令行输入:
bash复制openstack server create --flavor m1.small --image cirros --network demo-net my-vm
这条命令会先经过Keystone拿到token,然后以post方式请求nova-api的/servers接口。
nova-api收到请求后做两件事:校验token是否有效,检查当前用户在目标项目里是否有创建云主机的权限。通过后,它会把请求写入数据库,并把一个“创建实例”的任务通过消息队列发给nova-conductor。
nova-conductor相当于业务逻辑的协调者。它要先去数据库查这个项目的配额还能不能继续建机器,再结合你给的flavor、镜像、网络参数,去询问Placement有哪些节点满足资源要求,还可能调用nova-scheduler做最终的节点选择。
选定目标计算节点后,nova-conductor把消息发到那个计算节点上的nova-compute。接着nova-compute开始干重活:下载或拷贝镜像、准备好存储、让Neutron把网络端口准备好、通过libvirt库去调用KVM创建虚拟机、在数据库里更新状态。到你看到命令行返回VM状态为ACTIVE,中间可能已经过了十几秒甚至几十秒。
3.2 为什么要单独搞一个Placement
很多人在看Nova组件时容易漏掉Placement,因为以前Nova里根本没有这个单独服务。老版本里,调度器是直接查询数据库里计算节点的可用资源来判断能不能放。后来资源种类越来越多,除了CPU、内存,还要考虑GPU、FPGA、共享存储池、NUMA拓扑、PCI设备等,继续把资源统计塞在Nova的数据库里会很笨重,于是社区把“资源管理和分配”这个职责抽成了一个独立服务,叫Placement。
Placement更像一本“房源空位账本”。每个计算节点会定期把自己的可用资源(vCPU、内存、磁盘空间,还可以加自定义资源)上报到这个账本里。Nova要选一台物理机时,会问Placement:“哪些节点还能放下2个vCPU和4GB内存?”Placement给出候选列表后,nova-scheduler再根据可用域、flavor等策略做过滤,最后确定落到哪台机器。
所以如果某个新加的计算节点迟迟不能创建虚拟机,第一件事别急着换网络,先用命令看它是否在Placement里正确上报了资源:
bash复制openstack compute service list
openstack resource provider list
如果计算节点的nova-compute服务没有正常运行,或者资源上报周期还没到,Placement给出的候选列表里就不会有它。
3.3 nova-compute到底在计算节点上做了什么
nova-compute是Nova里唯一真正与控制虚拟化底层打交道的组件。它自己并不会直接启动一个虚拟机,而是通过libvirt去控制本机的hypervisor,通常就是KVM。你可以把libvirt理解成一套通用的“虚拟化遥控器”,nova-compute拿着它发出指令:定义一台虚拟机、给虚拟机加一块虚拟网卡、把某块存储卷挂载上去。
日常维护中,如果你想在物理机上手动查看Nova到底为某台云主机做了什么,最直接的办法是登录计算节点,用virsh命令查看libvirt里的domain列表:
bash复制virsh list --all
virsh dumpxml <instance-id>
当云主机状态显示ERROR,但页面上的错误信息只有一行“No valid host was found”,这时第一个动作往往就是去nova-compute.log里搜索实例ID或“No valid host”关键词,看具体是哪条约束条件没满足。我遇到过很多次是镜像格式不匹配、内存不足、或者是计算节点上存储空间不够,而不是Nova服务本身崩溃。
3.4 让Nova“看不见节点”的常见原因
生产环境里经常碰到的一种现象:明明有多个计算节点,但新创建虚拟机总是被调度到同一批节点上,其他节点“闲置”。要排查这类问题,我一般按下面顺序做:
- 检查nova-compute服务状态是不是UP,用openstack compute service list。
- 检查节点是否处于维护状态或禁用状态,注意disabled节点不会参与调度。
- 检查flavor和镜像的可用域配置,有些部署会限制节点归属。
- 检查Placement上报的资源是否正常,尤其是新节点注册后要确认它出现在openstack resource provider list里。
多数情况下,问题并不是Nova“偏心”,而是节点没有成功上报资源,或者处于维护状态。这一点对新手特别容易踩。
4. Neutron网络模块白话拆解:一张虚拟网的日常
如果把OpenStack比作物业公司,Neutron就是那个管全楼网络布线、交换机、路由、IP地址和隔离策略的施工队。很多人在理解网络模块时会有一个错觉,觉得Neutron是把数据包转发出去的那个组件。不是这样的。Neutron更像一个“控制中心”,它本身很少直接转发数据包,而是通过API和各种Agent去配置不同节点上的虚拟交换机、路由命名空间和安全组规则。
比如你在界面上创建一个网络,Neutron会创建对应的逻辑对象,并通知不同节点上的Agent去执行具体的配置动作。实际虚拟机之间的二层流量,通常走的是节点上的Open vSwitch或Linux Bridge,而不是Neutron主进程。所以Neutron服务挂了,可能网络还在转发,但新的端口分配、路由配置都会停摆。
4.1 provider网络和self-service网络:两种最核心的落地形态
理解Neutron之前,我建议先看懂两种网络层级。它们经常把新手绕晕:
- Provider网络:也叫物理网络直连模式。管理员预先在Neutron里定义好一个网络,直接映射到物理网卡或物理VLAN。这种网络简单高效,虚拟机拿到的是和物理网络同一个网段的地址,适合对性能要求高、又不希望太复杂的场景。缺点是租户不能自己去划分任意网段。
- Self-service网络:也就是租户自服务网络。租户可以自己创建网络和子网,出于多租户隔离,通常会使用VXLAN或GRE这种隧道技术把流量封装起来,底层网络只需要能转发封装后的包即可。虚拟机要访问外部网络时,需要经过一个虚拟路由器做NAT,通常还会配一个浮动IP来实现从外部访问虚拟机。
一个最简的落地架构通常是这样:控制节点/网络节点上跑着neutron-server、DHCP Agent、L3 Agent、Metadata Agent;计算节点上只需要跑二层Agent(Open vSwitch Agent或Linux Bridge Agent)来处理虚拟机的虚拟网卡,以及安全组规则。如果想自己安装一套最小网络环境,不需要一次性把所有Agent都部署在同一个节点上,只要保证各节点之间能通信、数据库和消息队列正常,Neutron就能工作。
4.2 网络、子网、端口、路由器、安全组——五个概念一次串联
如果用办公室场景来类比:
- 网络(Network)就像一整栋写字楼的网线规划,是一个二层的隔离域。在OpenStack里,不同网络之间默认互相隔离。
- 子网(Subnet)是给这个网络分配具体的IP地址段,比如192.168.100.0/24。一个网络下可以有多个子网。
- 端口(Port)相当于墙上的一个网口,在OpenStack里,一台云主机的虚拟网卡就是绑定在某个端口上的。DHCP分配IP、安全组规则、浮动IP都可以绑定到端口上。
- 路由器(Router)用来连接不同网络之间、或者连接租户网络和外部网络。它通常以Linux网络命名空间的形式运行在L3 Agent所在节点上。
- 安全组(Security Group)是一组端口级别的出入方向规则,相当于给每一张虚拟网卡配一个独立的访问控制策略。默认情况下,OpenStack安全组会允许所有出方向流量,拒绝所有入方向流量,除非你在规则里显式放行。
很多新手创建完云主机后,从控制台登录发现ping不通、SSH连不上,第一反应是网络模块坏了,其实很大概率只是安全组没放行22端口或icmp协议。我个人的排查习惯是先看安全组规则,再看网络拓扑,最后才去翻Agent日志,因为安全组配置问题比底层网络故障常见得多。
4.3 DHCP、Metadata和L3 Agent之间什么关系
在Neutron里,有几个常见的Agent,每个管一片事:
- DHCP Agent:负责给租户网络里的虚拟机动态分配IP地址。它管理着多个dnsmasq进程,每个网络一个。虚拟机获取不到IP时,先看这个Agent状态,再到对应网络节点上看对应dnsmasq进程是否正常、端口是否创建出来。
- Metadata Agent:负责让虚拟机通过特殊地址169.254.169.254访问实例的元数据,比如主机名、SSH公钥、userdata等。没有它,cloud-init可能拿不到初始化信息。
- L3 Agent:负责路由和浮动IP功能。虚拟机要出网、或者外部要访问浮动IP,都需要它的虚拟路由器参与。它偶尔会出问题导致外部访问不通。
我建议刚上手时先用一个非常简单的小实验理解Neutron:创建两个网络,每个网络各建一台云主机,然后把两台主机分别挂在同一个虚拟路由器上,观察它们能否互通,再尝试给其中一台绑定浮动IP后从物理机访问。真实环境的网络问题大多是多种因素叠加,但把这些Agent都认识一遍,后面排查会省下大量时间。
5. 存储三兄弟(外带一个Manila):镜像、盘和对象别再搞混
存储模块是OpenStack里另一个容易把人绕晕的点。很多人分不清Glance、Cinder、Swift到底谁负责什么,其实可以用三个生活物品来对应:
- Glance像一个“系统安装盘仓库”。它保存各种虚拟机镜像,比如一个已经装好Ubuntu的qcow2镜像。当你用某镜像创建云主机时,Nova会从Glance里拿到镜像。
- Cinder像一个“移动硬盘库房”。它提供的是块存储卷,也就是一块可以被格式化、分区、挂载到一个云主机上的虚拟硬盘。这块卷可以被卸载,再挂载到另一台云主机上,这就很像你在一台电脑上拔下移动硬盘插到另一台电脑上。
- Swift像一个“公共网盘”,它提供的是对象存储,通常通过HTTP API上传/下载文件。你可以往里塞图片、备份包、日志等海量文件,但不能像块设备那样直接格式化出文件系统给操作系统使用。
Manila则是共享文件系统服务,它提供的是像NFS或SMB那样的共享文件夹,多台云主机可以同时挂载同一个目录,适合做共享目录、分布式应用的共享配置等。
5.1 Glance并不一定真正保存镜像的每一个字节
这个点很反直觉,但它对理解架构很重要:Glance本身的核心功能是管理镜像的“元数据”,比如镜像ID、名称、磁盘格式、可见性等,而镜像数据实际保存在哪个后端,是可以灵活配置的。
常见后端包括:
- 普通文件系统:镜像直接存在控制节点或者专门的Glance存储节点上,路径一般是/var/lib/glance/images。
- Swift对象存储:把Glance配置成使用Swift后端,镜像数据就落进对象存储里,适合大规模分布。
- Ceph RBD:这是很多生产环境的选择,镜像作为块设备直接存在Ceph中。这样用镜像创建虚拟机时,可以基于Ceph的clone特性秒级复制,而不是先下载整个镜像文件再创建。
所以排障时如果看到“镜像上传成功,但创建虚拟机很慢”,不要只盯着Glance看,先看看Glance后端是什么。如果后端是NFS或普通文件共享,还需要确认网络存储路径各计算节点是否都能访问。
5.2 Cinder卷是怎么一步步创建出来的
Cinder的服务端通常由cinder-api、cinder-scheduler、cinder-volume几部分组成。cinder-api接收创建卷请求,cinder-scheduler根据卷类型和可用域决定把卷放到哪台后端设备,cinder-volume在最终选定的存储后端上执行创建操作。
最简单的命令是:
bash复制openstack volume create --size 10 --type lvm my-volume
这里的--type对应卷类型,比如lvm类型表示后端是LVM逻辑卷,ceph类型表示后端是Ceph。如果你在创建卷时指定了特定可用域,Cinder会尽量把卷放在该可用域对应的后端存储上。
创建完成后,如果你想把它挂到某台云主机上,执行:
bash复制openstack server add volume my-vm my-volume --device /dev/vdb
nova-compute收到挂载请求后,会通过libvirt给虚拟机热插拔一块新磁盘。如果是iSCSI后端,计算节点需要先建立iSCSI连接;如果后端是Ceph,计算节点配置好Ceph密钥后通过RBD协议挂载。挂载后你在云主机里执行lsblk就能看到新磁盘。
5.3 从镜像启动和从卷启动的区别
很多新手会问:我创建云主机时已经选了镜像,为什么还要单独创建卷?
这取决于Nova的启动方式。默认情况下,Nova会把Glance镜像拷贝到计算节点的本地磁盘上作为系统盘,这样云主机和卷没有强关联。删除这台云主机后,本地临时系统盘会被清理,数据丢失。如果不想丢数据,就需要额外挂载Cinder卷,并手动把它初始化和格式化。
另一种方式是“boot from volume”,也就是直接从Cinder卷启动。流程是这样的:先创建一块卷,指定它的来源是某个镜像,然后让Nova用这块卷作为云主机的系统盘。这样即使你删除了云主机,只要卷还在,数据就还在,之后可以用卷再启动一台新主机。
判断一台云主机是从卷启动还是镜像启动,可以看它的存储信息:
bash复制openstack server show my-vm
看volumes_attached字段,以及该卷是不是有bootable标记为true。如果卷显示bootable且状态为in-use,那它很可能就是系统盘。
5.4 Cinder卷分离失败:一个绕不开的经典故障
我在热搜里看到“openstack yoga cinder卷分离失败bug”这种话题,瞬间就想起自己之前在环境里反复折腾的经历。卷分离失败的表现通常是:云主机已经处于关机或删除状态,但卷的状态仍然是in-use,执行nova volume-detach一直报错。
我先给一套通用排查思路:
- 先确认卷和云主机的当前状态,别直接在两端乱执行命令。
bash复制openstack volume show <volume-id>
openstack server show <server-id>
看卷的attach_status和status,以及云主机状态。
-
到计算节点看nova-compute日志,搜错误关键词,比如“detach”“volume”“timed out”。如果是hypervisor层的设备还在占用,大概率会看到libvirt相关报错。
-
手工在计算节点上确认是否还有对应磁盘映射关系。如果是iSCSI后端,可以查看iscsi session;如果是Ceph/RBD,则用rbd命令看一下设备是否还被watcher占着。
-
在确认云主机确实已经不再需要该卷、且没有IO读写的前提下,可以考虑执行强制分离:
bash复制nova volume-detach <server-id> <volume-id> --force
或者在cinder层面把卷状态重置为available:
bash复制openstack volume set --state available <volume-id>
需要提醒的是:强制分离是有风险的操作,如果云主机还在运行且文件系统正在写入,强制卸载极易损坏数据。我踩过这个坑,后来就养成一个习惯——先在云主机内部卸载文件系统、停止使用该卷的进程,再执行OpenStack层面的分离动作。
5.5 Swift和Manila的应用边界
Swift作为一个对象存储,适合保存很少修改但需要长期保留的数据,比如备份文件、日志归档、用户上传的图片。它不能像块设备一样挂载成磁盘,应用程序需要通过Swift的API来上传下载对象。
Manila则解决了另一个问题:多台云主机要共享同一份数据。比如你搭建了一个集群,每个节点都要读同一个配置目录,那用Cinder卷就不合适,因为一块Cinder卷默认是单机挂载的。Manila提供共享文件系统,可以同时给很多台云主机挂载。生产里常见的场景是创建NFS共享,然后让多个云主机通过mount命令挂载到本地目录。
如果你只搭实验环境,可以先不用Manila,但至少要知道:当出现“需要多台机器共享目录”的需求时,Cinder解决不了,得找Manila。
6. 从创建一个云主机开始,把所有模块串成一条线
讲了这么多模块,很多人还是会问:这些模块到底是怎么配合起来的?最好的方式是把创建云主机的一次完整流程拆开看。我建议每个初学者都亲手做一次“从页面创建一台云主机”的实验,同时开着API日志和数据库观察窗口,你看完一次全链路下来,之前记不住的那些模块名基本都活了。
下面是一台镜像启动云主机的完整请求链路,按步骤拆解。
-
认证阶段。你在Horizon登录时,Horizon向Keystone提交用户名密码,换回一个token。Keystone同时返回服务目录,Horizon知道Nova API的地址在哪。
-
提交创建请求。Horizon向nova-api发送POST /v2.1/服务器 的请求,请求体里包含flavor、镜像、网络、可用域、密钥等信息。这个请求会带着之前拿到的token。
-
nova-api校验身份和权限。nova-api内置的keystone中间件会把token发回给Keystone做校验,确认用户身份,并通过策略文件判断用户在当前项目有没有创建云主机的权限。如果权限不足,马上返回403。
-
nova-conductor检查配额和调度。nova-api把这个请求写入数据库,然后通过RabbitMQ让nova-conductor处理。nova-conductor去查当前项目剩余实例数、CPU核数、内存容量等配额,如果配额不够就直接拒绝。
-
调度选节点。nova-scheduler和Placement联手决定哪台计算节点能接收这个任务。Placement查询哪台节点还剩足够的vCPU和内存;nova-scheduler再结合可用域、flavor等属性做最终选择。选定后,消息被发送到目标计算节点上的nova-compute。
-
计算节点执行子流程。这一步最复杂,nova-compute依次做下面若干件事:
- 先从Glance获取镜像元数据和下载地址,把镜像文件落到本地。
- 如果网络端口还没创建,则调用Neutron API申请一个端口,拿到MAC和IP地址。
- 如果指定了卷启动,则调用Cinder创建卷或挂载卷。
- 用libvirt拼出虚拟机的XML描述文件,真正调用KVM创建虚拟机。
- 虚拟机启动后,通过DHCP Agent拿到IP,再访问Metadata服务获取密钥、主机名、userdata等初始化信息。
- 前端轮询状态。Horizon通过API定期查看云主机状态,直到它进入ACTIVE。
这个流程里有一个很值得体会的点:模块之间大量使用异步消息。nova-api不是直接等nova-compute干活干完再给Horizon返回最终状态,而是先返回一个“创建中”的状态,后续由nova-compute更新数据库状态,面向前端的API再查询到最新状态。理解了这一点,你就明白为什么很多任务会卡在中间状态,因为每一步都是异步的,任何一环卡住,后面的状态
