每天都在用的Launch和Shut Off,你真的看懂了吗?
做OpenStack运维的兄弟应该都有这种体会:平时用的最多的操作,往往不是那些复杂的迁移、高可用、热升级,反而是最基础的虚拟机启动和关机。就拿Launch和Shut Off这两个操作来说,命令行敲下去不过一秒,但背后整个Nova组件的调度、计算节点的资源分配、Hypervisor的状态流转,全都要跟着跑一遍。这两招都没吃透,后面玩透OpenStack基本是空谈。
这篇内容主要面向刚接触OpenStack的运维新手,也包括那些已经搭好环境、每天在Horizon面板上点来点去但没深究过内部机制的朋友。我会从实例状态机讲起,拆解Launch和Shut Off分别在Nova里做了什么、计算节点上发生了什么,再结合实操命令和问题排查,把这层窗户纸捅破。
1. 从一张表看懂实例的完整生命周期
1.1 为什么状态机设计是运维的“红绿灯”
OpenStack把一台虚拟机从生到死的所有阶段定义成了一套状态机,就像红绿灯一样指挥着整个云平台的调度逻辑。你在命令行里执行openstack server list看到的ACTIVE、SHUTOFF、ERROR这些状态,并不是凭空定义的,而是Nova组件在每一阶段结束后主动上报的结果。
从运维角度看,这套状态机直接影响你的日常操作决策。比如一台实例状态是SHUTOFF,你执行openstack server start它就能正常开机;但如果状态已经变成ERROR,你再怎么执行start也白搭,大概率要先排查底层Hypervisor的问题。所以读懂状态,等于读懂了实例的健康报告。
OpenStack实例的主状态主要经历这么几个节点:BUILD(正在创建)、ACTIVE(正常运行)、SHUTOFF(已关闭)、SUSPENDED(已挂起)、RESIZED(已调整规格)、ERROR(异常)。另外还有VERIFY_RESIZE、REBUILD等过渡状态,这里我只挑最核心的几个展开。
1.2 Launch、Start、Shut Off、Stop的关系到底怎么理
很多新手最容易混淆的就是Launch和Start、Shut Off和Stop这四兄弟。其实在OpenStack语境里,这四者经常混用,但各自的使用场景有微妙差异。
先明确一点:Launch指的是一台新实例从无到有的完整创建过程,对应API是POST /servers,底层会经历镜像调度、网络配置、磁盘创建、Hypervisor启动等一系列动作。而Start指的是对一台已存在的、处于SHUTOFF状态的实例执行开机操作,对应API是POST /servers/{server_id}/action,请求体里写明"os-start": null。
Shut Off和Stop则基本是一回事,都是把实例关机。区别在于OpenStack内部有个概念叫OS-EXT-STS:task_state,如果你看到实例的task_state是powering-off,说明关机动作还在执行中;如果vm_state已经变成stopped,那就代表Shut Off已经完成。在Horizon面板上,你可能看到的是“关闭实例”按钮,而命令行则是openstack server stop。
这张表建议保存下来:
| 操作 | 底层API动作 | 对应CLI命令 | 实际效果 |
|---|---|---|---|
| Launch | POST /servers | openstack server create | 创建全新实例 |
| Start | os-start | openstack server start | 启动已关机的实例 |
| Shut Off | os-stop | openstack server stop | 优雅关机 |
| 强制关机 | os-stop, force | openstack server stop --force | 直接断电 |
1.3 好记性不如烂笔头:主动掌握状态转换
在排障实践中,我发现很多兄弟只看openstack server list的Status列,但这一列信息量太少。强烈建议把实例的完整状态字段拉出来看,用这个命令:
bash复制openstack server show <server_id> -c status -c vm_state -c task_state -c power_state
status是Nova对外展示的主状态,vm_state是实例的内部虚拟状态,task_state表示Nova当前正在执行的异步任务,power_state则是从Hypervisor上报的ACPI电源状态,0表示无状态、1表示运行中、4表示关机。实际排障时,四列信息配合着看,基本能定位出问题出在调度层、网络层还是Hypervisor层。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. Launch背后,Nova到底在忙什么
2.1 Nova的脑力劳动与体力劳动
拿到openstack server create之后,Nova内部并不是一个进程干完所有事,而是由多个服务分工协作。凡是涉及决策、状态管理、数据库交互的,都是“脑力劳动”,由nova-conductor和nova-scheduler负责;涉及真实物理节点的操作,比如调用KVM创建虚拟机,就是“体力劳动”,由nova-compute负责。
完整链路大概是这样的:API请求先到nova-api,它做了最基础的项目校验、配额检查和参数合法性校验;接下来请求交给nova-conductor,conductor再让nova-scheduler去过滤和选择合适的主机;最后scheduler选定计算节点后,对应的nova-compute才真正动手,通过libvirt驱动调用底层虚拟化接口。
2.2 调度器选主机的核心逻辑
nova-scheduler选计算节点并不是随机抽签,而是走了一套过滤加权重的流程。nova.conf里的scheduler_default_filters参数决定了有哪些Filter参与过滤,常见的包括RetryFilter、AvailabilityZoneFilter、ComputeFilter、ComputeCapabilitiesFilter、ImagePropertiesFilter、CoreFilter、RamFilter,还有较新的NUMATopologyFilter和PCIWeigher。
跑一个最简单的CoreFilter算给你看:nova-scheduler会遍历所有计算节点,把每个节点上可用的vCPU核数算出来,对比要创建的实例规格里要求的vcpus数。比如一个计算节点总核数是32,已经分配出去20核,剩余可用12核,而新实例要求4核,那这个节点在CoreFilter这一步就通过了。但如果剩余只有2核,这个节点就会被剔除。
当然这只是过滤阶段,过滤完之后还有RamWeigher这类权重计算,优先选择剩余内存较多的节点,实现简单的负载均衡。正因如此,Launch的结果落到哪台计算节点,是由调度器决定的,不是你想指定就指定。除非你在创建时指定了--availability-zone和--host,那约束条件就直接卡死了。
2.3 计算节点上的一次真实Launch拆解
当nova-compute收到创建任务后,它会按顺序做下面几件事:
第一,通过glance的API把选中镜像下载到本地,同时完成格式转换和缓存。这一步极其依赖网络和存储性能,如果镜像源在远端,而计算节点本地磁盘又是机械盘,下载几个GB的镜像会明显拖慢Launch速度。
第二,创建实例的虚拟磁盘。默认情况下,nova-compute会在/var/lib/nova/instances目录下生成UUID命名的目录,里面有disk文件。如果你配置了Cinder后端,这个环节会变成从Cinder挂载块设备,不走本地文件。
第三,准备网络资源。Neutron会分配端口、创建网卡,并把它绑定到对应的虚拟网络上。这一步如果DHCP或Metadata服务异常,实例起来后极有可能拿不到IP。
第四,调用libvirt的define接口,把实例的XML定义文件写进Hypervisor,然后执行create启动虚拟机。到这里,实例的状态从BUILD变成ACTIVE,Launch的完整流程才算走完。
bash复制# 查看计算节点上真实的libvirt域
virsh list --all
# 这个命令在OpenStack计算节点上直接执行,能看到Nova创建出来的虚拟机
3. Shut Off没那么简单,关机和断电是两码事
3.1 优雅关机与强制关机的底层差异
日常使用中,openstack server stop默认是走ACPI优雅关机流程。Nova会通过libvirt向QEMU发送ACPI shutdown请求,让客户机操作系统里的systemd或init收到关机信号,然后正常关闭所有进程、卸载文件系统、停止服务。整个过程就像是你在Windows开始菜单里点了“关机”,安全、干净。
但有些时候客户机操作系统已经卡死,或者网卡驱动异常导致ACPI信号传不进去,实例就会一直处于powering-off状态。这时候你就得考虑用--force参数强制关机。强制关机在物理世界里等价于直接拔掉电源线,数据没有落盘、文件系统没来得及卸载,有一定概率损坏系统盘数据。所以我的建议是:能优雅关机就绝不强关,强关之前最好先确认一下是不是业务真的没救了,可以让业务方在客户机内部先自行关机或保存数据。
3.2 Shut Off在OpenStack层面的处理流程
执行openstack server stop之后,流程并没有到libvirt直接发ACPI这么简单。Nova同样要走状态机:先把实例的task_state置为powering-off,再把请求通过nova-conductor转发到实例所在的nova-compute,最后由nova-compute调用libvirt的destroy接口(注意,libvirt的destroy对应的是强制关机,但Nova封装了一层,先尝试ACPI shutdown)。
这里有一个关键设计:Nova会等待客户机真正关闭后才把状态更新为SHUTOFF。如果超时时间到了客户机还没关,Nova会把状态回退到ACTIVE,同时产生一条日志告警。这种情况下你要是再看openstack server list,会发现实例还是ACTIVE,容易误以为关机操作没生效,其实是客户机没响应ACPI而已。
3.3 关机之后的资源消耗与成本计算
很多刚玩OpenStack的兄弟以为实例关机了就不消耗计算资源了,其实并不完全对。SHUTOFF状态下,vCPU和内存确实已经被释放,可以分配给其他实例用,所以计算资源的配额占用会下降。但虚拟机对应的系统盘仍然存在于存储后端,假如你是用Cinder创建了一块根卷,这块卷依然占着你的存储配额。
更隐蔽的是:关机状态下,实例的浮动IP仍然被占用,你在Neutron里查询端口,这个IP还是绑定在实例的port上,并没有释放回地址池。也就是说,如果业务场景是“临时不用但不想销毁”,建议你先看看自己的IP和存储配额够不够用,毕竟两个资源还在你名下占着。想彻底释放,只有删除实例或者把相关端口解绑。
4. 实操篇:Launch和Shut Off的命令级玩法
4.1 用命令行完成一次Launch并验证
先给一条标准的创建命令,参数按生产环境的常见配置来:
bash复制openstack server create \
--flavor m1.small \
--image cirros-0.6.2-x86_64 \
--network internal-net \
--security-group default \
--key-name my-keypair \
my-first-instance
创建后立刻看状态:
bash复制openstack server show my-first-instance -c status -c vm_state -c task_state -c power_state
如果一切正常,你会看到类似status=ACTIVE、vm_state=active、power_state=1。这里有个小经验:刚执行完create命令,状态大概率是BUILD,因为创建流程需要时间,千万别以为卡住了。
实例创建完成后,想验证网络通不通,最简单的办法是拿到控制台日志,看DHCP有没有分配IP:
bash复制openstack console log show my-first-instance
日志末尾能看到udhcpc获取IP的信息,或者直接看openstack server list里的IP列。
4.2 Lance里的“隐藏参数”:user-data和flavor
生产环境上Launch,光给镜像、规格、网络还不太够,user-data是云初始化最喜欢用的一招。用--user-data参数传一个cloud-init脚本进去,实例首次启动时自动执行写主机名、装软件、配SSH等操作。
还有一个容易忽视的是--flavor的选择。Flavor里定义的磁盘大小和内存大小不一定等于最终规格,如果你指定的镜像有min_disk或min_ram要求,Nova在调度时会自动校验,不满足就直接报No valid host found。所以我一般建议先在Glance里把镜像的min_disk和min_ram属性查清楚再选flavor:
bash复制openstack image show cirros-0.6.2-x86_64 -c min_disk -c min_ram
4.3 Shut Off的命令操作与验证
关机命令很简单,一行搞定:
bash复制openstack server stop my-first-instance
关键在验证。过几秒再查一次:
bash复制openstack server show my-first-instance -c status -c vm_state -c task_state -c power_state
你希望看到的结果是这样的:
status:SHUTOFFvm_state:stoppedtask_state:Nonepower_state:4
这四个字段若全部符合,说明关机流程已经彻底走完。假如你看到task_state还是powering-off,说明还在等客户机响应;等很久还不动,就到计算节点上看日志。
如果操作系统卡死,决定强制关机,命令是:
bash复制openstack server stop --force my-first-instance
不过强烈建议使用nova stop --force的旧命令之前先确认底层Hypervisor是否支持,部分版本会有驱动兼容问题。
4.4 一条命令搞定批量关机
运维场景中常有批量操作,比如一批测试机下班前全关掉。用Shell循环就能搞定:
bash复制for id in $(openstack server list --status ACTIVE -f value -c ID); do
openstack server stop $id
done
这里把--status ACTIVE作为过滤条件,防止对已经关机的实例重复执行stop。如果你只想关闭某个项目下的机器,再加--project参数即可。批量操作务必先小范围验证,别直接全量跑,万一命令写错影响面就大了。
5. 常见的Launch和Shut Off失败,这样查最有效
5.1 实例一直卡在BUILD或ERROR状态
创建实例卡住不动,多半是调度或者资源的问题。先在控制节点上查看nova-scheduler日志:
bash复制tail -100 /var/log/nova/nova-scheduler.log
常见报错是No valid host found,原因通常有三个:计算节点资源不足、镜像与flavor约束不匹配、主机聚合或可用域配置不对。逐个排查就能接近真相。
如果是ERROR状态,请第一时间去计算节点看nova-compute.log:
bash复制tail -100 /var/log/nova/nova-compute.log
我遇到过最多的情况是磁盘格式不兼容、/var/lib/nova/instances目录权限异常,以及Cinder后端连接超时。这些日志里都会打出具体堆栈,照着修就行。
另外一个容易被忽略的坑是:计算节点的libvirtd服务挂掉了。nova-compute跟libvirtd通信失败后,所有Launch请求都会失败。用systemctl status libvirtd检查一下,顺手再virsh list --all看能不能正常返回。
5.2 关机老失败,实例一直处于powering-off
这个问题的根源,绝大多数在于客户机没有响应ACPI关机信号。先在计算节点上试试手动向虚拟机发送ACPI shutdown:
bash复制virsh shutdown <nova实例的UUID>
如果执行后客户机依然不关,那就基本确认是客户机内部问题。接下来进入客户机,用virsh console登录进去看是否卡死、是否有关机相关进程阻塞。如果客户机已经完全失联,只能强关收尾:
bash复制virsh destroy <nova实例的UUID>
但注意,手动virsh destroy之后,Nova的数据库状态可能和Hypervisor实际状态对不上,最好再到控制节点执行一次openstack server stop --force,让Nova重新同步状态。
5.3 排障前先养成看日志的好习惯
OpenStack排障,日志是第一生产力。不同节点、不同组件,日志路径各不一样,这里列一张速查表:
| 组件 | 日志路径 | 常见排查场景 |
|---|---|---|
| nova-api | /var/log/nova/nova-api.log | API请求参数、错误返回 |
| nova-scheduler | /var/log/nova/nova-scheduler.log | 调度失败、No valid host |
| nova-conductor | /var/log/nova/nova-conductor.log | 数据库交互问题 |
| nova-compute | /var/log/nova/nova-compute.log | 创建/删除/关机实例的核心日志 |
| neutron-server | /var/log/neutron/server.log | Port创建失败、DHCP异常 |
| libvirt/qemu | /var/log/libvirt/qemu/ | 虚拟机XML和QEMU状态 |
看日志时我习惯先搜关键字,比如ERROR、Traceback、NoValidHost、timeout,比逐行翻正文高效得多。
6. 把Launch和Shut Off玩出花:云主机的扩展操作
6.1 配合快照实现关机备份
生产环境里,我经常用Shut Off配合快照做一次干净的备份。实例运行中的快照虽然也能做,但文件系统一致性没保障;关机状态下的磁盘文件处于静止状态,快照安全性更高。而且关机备份更容易对齐后面的恢复测试流程。
bash复制openstack server stop my-instance
openstack image create --server my-instance my-instance-backup
openstack server start my-instance
这个流程适合业务低峰期操作,先把实例停掉,做了快照再拉起来。要注意的是,openstack image create创建出来的其实是快照镜像,你可以用它再Launch新实例,也可以用它做整机恢复的种子。
6.2 用Launch和Shut Off快速搭建一套测试环境
在开发测试场景,Launch和Shut Off组合拳非常实用。比如我在本地维护了一套自动化脚本,一键批量创建三台测试实例,跑完用例后一键关机,次日需要再一键开机。整个过程不销毁实例,保留现场数据和环境,比每天从零创建快得多,也省去了重复初始化配置的麻烦。
code复制
# 准备一个简单脚本模板
for i in 1 2 3; do
openstack server create \
--flavor m1.small \
--image centos-7 \
--network int-net \
test-node-$i
done
跑完测试后统一stop,下次start起来就行,环境原封不动。
6.3 运维管理的“三位一体”检查法
跟Launch和Shut Off打交道一年多之后,我沉淀出一套自己的“三位一体”检查法:每次处理完实例状态问题,都要同时查OpenStack数据库状态、计算节点真实Hypervisor状态,以及客户机操作系统内部状态。这三个层面任何一个不同步,都会给后面埋雷。
具体来说,OpenStack层面的状态看openstack server show,Hypervisor层面的状态看virsh list --all,客户机内部状态看virsh console。三处对齐了,才算真正做到“心里有数”。如果发现状态漂移,优先用openstack server reset state进行修正,但记住这个命令只能在紧急时刻用,因为它会跳过Nova的正常状态机校验。
写在最后
做了这几年OpenStack运维,我最大的感受是:越是基础的操作,越值得花时间反复琢磨。Launch和Shut Off看似简单,但背后藏着Nova的架构设计、调度器的决策逻辑、KVM的电源管理机制、Neutron的网络生命周期。把这些点串起来,以后再遇到OpenStack其他问题,你会有一种豁然开朗的感觉。下次你在控制台点“关机”按钮的时候,可以试着在计算节点上同步开着virsh list --all,看看实际发生了什么,那种一眼看穿全局的掌控感,真的很爽。
