ARTICLE DETAIL

资讯详情

深耕编程入门与网站建设的一线实战洞察。

OpenStack实例生命周期管理:Terminate与Pause/Resume深度解析

OpenStack实例生命周期管理:Terminate与Pause/Resume深度解析 1. 为什么实例生命周期管理是OpenStack运维的硬功夫先聊点实际的。OpenStack这块大泥潭里很多刚入门的朋友喜欢追着网络节点、存储后端这些大件折腾但真正到了生产环境天天跟你打交道的其实是实例的生命周期操作。虚拟机建起来、跑业务、出问题、被回收这一整条链路里Terminate Instance和Pause/Resume Instance几乎是出现频率最高的两个操作也是最容易在晚上十点把你从被窝里叫醒的两件事。我之前带团队维护过一套规模不算小的云平台几十个计算节点、上千台云主机跑着生产业务。刚开始那会儿大家觉得删个实例嘛不就是nova delete一下嘛挂起恢复也就是点两下按钮的事。结果真的上了生产各种踩坑实例状态卡在deleting不动了、后端存储里的云硬盘残留、Pause之后虚拟机死活恢复不了、甚至因为误操作把正在跑业务的实例给terminate了。这些坑每一个背后都是对生命周期管理理解不够深。这篇文章就围绕Terminate Instance和Pause/Resume Instance这两个操作把原理、命令、排查方法全部过一遍。不管你是刚接触OpenStack的运维新人还是已经被线上故障折磨过几轮的老兵这篇文章的目标是让你看完之后再碰到实例生命周期的问题心里有底手上不慌。2. Terminate Instance删除实例背后的事远比想象中多2.1 从一条命令看Nova的完整调用链先说Terminate Instance。很多教程上讲删除实例就是一条nova delete server_id或者openstack server delete server_id然后实例就没了。但这条命令的背后是一整套多组件协作的流程。你敲下命令后请求先进到Nova APIAPI层做基础的项目权限校验和参数检查然后丢给Nova Conductor。Conductor是Nova的大脑它负责协调整个删除流程通过消息队列把任务分发到对应的Nova Compute节点。Compute节点上跑的nova-compute服务收到指令后会先通过libvirt去调用底层的虚拟化技术把虚拟机从运行状态转为关闭状态——注意这里的关闭还不是删除只是把Guest OS先停下来。虚拟机停止之后Compute节点开始做资源清理。CPU和内存资源直接释放掉就好但存储这块要单独说。如果实例用的是本地磁盘比如用local类型的后端或者默认的ephemeral磁盘nova-compute负责把本地磁盘文件删掉。如果挂载的是云硬盘Cinder卷事情就复杂了——默认情况下nova delete只会把实例和卷的关联关系解除卷本身不会删它还在Cinder里躺着。除非你创建实例的时候设置了delete_on_terminationTrue否则删了实例之后卷还在费用还在计。这一点很多新手甚至部分老手都会忽略。2.2 Terminate和Force Delete什么时候该用哪个Nova里删除实例其实有优雅删除和强制删除两个路径对应OpenStack CLI就是openstack server delete和openstack server delete --force或者早期Nova命令里的nova force-delete。区别在哪里优雅删除会走完整的停机和清理流程nova-compute会调用libvirt的shutdown接口尝试让虚拟机内的操作系统正常关机。这个流程通常有超时时间如果虚拟机内的系统卡死、或者有进程不响应关机信号优雅删除就会卡住。很多朋友在生产环境遇到过删实例删了半天状态还是deleting的问题多半就是这个原因。Force Delete就简单粗暴了它不做优雅关机直接让nova-compute把虚拟机的底层资源干掉类似于直接拔电源。force delete适合的场景是实例所在的计算节点宕机了、虚拟机内部系统完全失去响应、或者优雅删除已经超时卡死。但要注意强删意味着Guest OS没有正常走关机流程如果有数据还没来得及落盘那部分数据大概率就丢了。所以能用优雅删除尽量用优雅删除只有确认业务已经停止或者数据已经备份了才考虑强制删除。2.3 删除实例时的网络和存储资源清理细节继续往深了挖。实例删除之后网络资源是怎么回收的如果实例用的是OpenStack Neutron管理的网络实例删除后它的虚拟网卡会从Open vSwitch或Linux Bridge上摘下来对应的端口port会在数据库里标记为down然后按照网络的配置决定是否彻底删除。这里有个容易踩坑的点如果端口上绑定了浮动IPFloating IP删除实例默认会把Floating IP也释放掉。如果这个IP是你公网地址池里的稀缺资源释放了倒还好但如果你的网络配置了allowed_address_pairs或者端口级别的安全组规则这些配置会一起被清掉重新建实例就得重配一遍。存储这块刚才提到了Cinder卷的问题再补充一个细节delete_on_termination这个属性不仅仅在建实例时可以设置如果你用的是Terraform或者Heat来编排模板里也要显式声明。我在实际运维中遇到过不止一次开发同事用脚本批量建实例、批量删实例结果Cinder里堆了一堆available状态的孤儿卷容量全被吃掉了。后来我们专门写了一个定期巡检脚本去清理这些残留卷才把这个坑填上。提示检查实例是否配置了delete_on_termination可以用openstack server show server_id看volumes_attached字段或者直接查Cinder的API看卷的delete_on_termination属性。3. Pause/Resume Instance挂起和恢复到底动了什么3.1 Pause和Suspend的本质区别别再搞混了讲Pause/Resume之前必须先花点篇幅把Pause和Suspend这两个容易混淆的操作分清楚因为它们的底层机制完全不同适用场景也完全不同。Pause挂起是把虚拟机当前的内存状态保留在物理机的内存里然后暂停虚拟机的CPU执行。用生活里的话说就像你看电影按了暂停键画面卡在那里演员的姿势、场景的光线全都定格了等你按播放键从暂停的那一帧继续播。Pause的速度非常快因为不用把内存写到磁盘但它的代价是——物理机的内存一直被占着不能释放出来给别的实例用。Suspend休眠则不同它会把虚拟机的内存状态完整地写入宿主机的磁盘里然后释放掉内存资源。这就像你把电影关掉、电脑睡眠下次再打开的时候恢复到你离开时的画面。Suspend的速度比Pause慢得多因为需要把几十GB的内存数据刷到磁盘上去但它释放了内存适合长时间不用的实例。在OpenStack的命令行里这两个操作分开得很清楚openstack server pause对应的是Pauseopenstack server suspend对应的是Suspend。Resume对应的恢复操作是openstack server unpause和openstack server resume。我在招人和带人的时候特别喜欢问这个问题因为很多人嘴上说知道实际上手操作的时候经常搞混。3.2 Pause/Resume在Libvirt层面的实现原理让你从运维角度理解一下底层。OpenStack默认的虚拟化后端是KVMnova-compute通过libvirt来管理虚拟机Pause操作在libvirt层面对应的是virDomainSuspend。这个调用会向QEMU发送一个停止指令虚拟机内部的vCPU立刻停止执行但内存数据完全留在物理主机上。此时你在宿主机上用virsh list --all仍然能看到这个实例状态显示为paused。Resume操作对应的是libvirt的virDomainResumeQEMU收到指令后恢复vCPU的执行虚拟机就继续跑了。这里有个值得注意的细节Pause期间虚拟机的时间是停止的但如果宿主机的CPU支持某些虚拟化特性比如KVM的kvm-clock恢复之后虚拟机的系统时间会自动校准一般不会出现明显的时间跳变。而Suspend在这种机制下要重得多。它调用的不是简单的挂起接口而是通过QEMU的savevm或者migration to file机制把整个虚拟机状态打包成文件存在宿主机的磁盘上。这个文件的大小基本等于虚拟机内存的大小8GB内存的机器suspend一次就要写8GB数据到磁盘。磁盘慢的话一等就是好几十分钟期间实例状态一直卡在suspended用户那边的体验就是这个按钮点了没反应。3.3 什么时候用Pause什么时候用Suspend从实际经验出发我给团队定的规则是这样的Pause适合短时间的临时挂起比如你要给宿主机做一次快速维护预计几分钟就能搞定用Pause最合适。或者你在做数据库迁移之前需要先把应用层服务暂停一下又不想把整个虚拟机关掉用Pause也很顺手。Suspend适合中长时间的冷冻比如某个测试环境下个季度才用一次你把实例Suspend掉内存资源释放出来宿主机可以跑更多业务实例。还有一些场景是宿主机要做在线迁移或者计划性维护先把实例Suspend到磁盘关键时刻可以降低风险面因为虚拟机的状态已经从内存挪到了磁盘上宿主机即使宕机只要磁盘数据还在实例就能恢复到之前的状态。但有一点要特别注意Pause不适合长时间挂起。为什么因为内存数据一直躺在物理机上一旦宿主机意外宕机这些内存数据直接丢失恢复之后虚拟机就只能从磁盘镜像冷启动了之前内存里未落盘的数据全没。而Suspend因为状态已经写到磁盘了宿主机重启之后还有机会用virsh restore把状态恢复回来数据安全性更高。所以超过半小时以上的挂起我都建议用Suspend而不是Pause。4. 实操过程与核心环节实现4.1 环境准备与常用命令速查不废话先列一下最常用的命令假设你已经配置好了openrc或者clouds.yaml环境变量。# 查看实例列表 openstack server list # 查看单个实例的详细信息 openstack server show server_id # 优雅删除实例 openstack server delete server_id # 强制删除实例慎用 openstack server delete --force server_id # 挂起实例Pause openstack server pause server_id # 恢复挂起的实例Unpause openstack server unpause server_id # 休眠实例Suspend openstack server suspend server_id # 从休眠中恢复实例Resume openstack server resume server_id在动手操作之前我强烈建议你先确认几个事情当前实例所在的计算节点是否健康实例是否绑定了云硬盘是否有浮动IP需要保留如果是数据库、消息队列这类的有状态服务删除或挂起之前一定要确认业务侧已经做好了处理比如数据库已经flush了事务日志、应用已经切走了流量。4.2 Terminate实例的完整操作示例下面演示一个带云的实例删除流程覆盖大多数生产场景。第一步确认实例当前的挂载卷和网络端口# 查看实例详情重点关注volumes_attached和addresses字段 openstack server show d4c7b0a8-1a2b-4c3d-9e8f-6a7b8c9d0e1f # 查看所有挂载的云硬盘 openstack volume list --server d4c7b0a8-1a2b-4c3d-9e8f-6a7b8c9d0e1f第二步手动备份或者迁移需要保留的数据。如果要保留云硬盘的数据那就先openstack server remove volume server_id volume_id把卷从实例上摘下来。注意这个操作要在删除实例之前做。第三步执行删除# 正常删除 openstack server delete d4c7b0a8-1a2b-4c3d-9e8f-6a7b8c9d0e1f # 如果卡住先查看实例状态 openstack server show d4c7b0a8-1a2b-4c3d-9e8f-6a7b8c9d0e1f # 如果状态一直是DELETING说明删除流程可能卡住了第四步删除之后的验证# 确认实例已经从列表消失 openstack server list --all-projects # 检查网络端口是否清理干净应该找不到对应的端口了 openstack port list | grep d4c7b0a8 # 检查Cinder卷的状态如果卷的delete_on_termination是False卷还在 openstack volume list如果你发现实例删完了Cinder里的卷还躺在那里别慌这是符合预期的。只有设置了delete_on_termination的卷才会跟着实例一起删掉其他的卷会保留。这种设计本身是保护数据但从资源管理的角度确实容易造成存储浪费所以定期清理孤儿卷是运维必修课。4.3 Pause和Resume的完整操作示例Pause操作相对简单但有一些细节值得注意# 挂起指定实例 openstack server pause d4c7b0a8-1a2b-4c3d-9e8f-6a7b8c9d0e1f # 查看实例状态应该变为PAUSED openstack server show d4c7b0a8-1a2b-4c3d-9e8f-6a7b8c9d0e1f在Pause之后实例的vCPU和内存并没有释放它仍然占着宿主机的物理资源。你可以登录到计算节点上用virsh list --all看一下会看到实例状态是paused。恢复的时候# 恢复实例 openstack server unpause d4c7b0a8-1a2b-4c3d-9e8f-6a7b8c9d0e1f # 确认状态回到ACTIVE openstack server show d4c7b0a8-1a2b-4c3d-9e8f-6a7b8c9d0e1fPause和Unpause的操作很快正常情况下几秒钟内就该完成。如果你发现Unpause之后实例长时间卡在PAUSED说明宿主机或者QEMU出了问题需要去计算节点查看nova-compute的日志。Suspend操作对比一下# 休眠实例 openstack server suspend d4c7b0a8-1a2b-4c3d-9e8f-6a7b8c9d0e1f # 查看状态正常情况下会从ACTIVE变为SUSPENDED openstack server show d4c7b0a8-1a2b-4c3d-9e8f-6a7b8c9d0e1f如果实例内存比较大比如32GBSuspend操作可能会持续几分钟。这期间实例状态会一直显示为suspending不要重复执行命令也不要直接从数据库层去改状态。恢复的操作# 从休眠恢复 openstack server resume d4c7b0a8-1a2b-4c3d-9e8f-6a7b8c9d0e1f恢复的时候同样可能有几分钟的延迟因为宿主机要从磁盘上把之前保存的内存状态文件读回来。如果恢复过程中宿主机的磁盘IO本身很满这个过程会被拉得更长。4.4 解决Pause和Suspend在Web界面上的假死问题用HorizonOpenStack的Web界面操作Pause或Suspend的时候偶尔会遇到按钮点了没反应、实例状态一直转圈的情况。很多新手以为是自己网络问题或者界面卡了疯狂刷新结果并发请求把Nova API都压住了。其实这种情况大概率是操作本身还在执行中Pause可能几秒就完成了但界面上的状态刷新周期比较慢Suspend则可能要等好几分钟。正确做法用命令行去验证实例的实时状态不要依赖Web界面。在计算节点上用virsh list --all看到的才是第一手状态。Web界面显示有延迟这是架构决定的不是Bug。你只需要记住判断实例状态以API返回和libvirt实际状态为准。5. 常见问题与排查技巧实录5.1 实例删除后卡在DELETING状态怎么办这是运维最常遇到的坑没有之一。造成这个状态的原因通常有三类第一底层libvirt清理超时。虚拟机停了但QEMU进程没有完全退出或者有文件句柄没释放导致nova-compute等了半天清理不干净。可以在计算节点上看进程# 找到对应的QEMU进程 ps -ef | grep instance_uuid # 如果进程还在但状态是Z僵尸确认之后可以用kill强制清理第二Cinder卷分离失败。实例挂着卷卷的分离操作一直不成功整个删除流程就卡住了。这种时候去Cinder的日志里翻一下看有没有Fail to detach volume之类的报错多半是存储后端的iscsi或者rbd连接没有正常断开。第三Neutron端口清理失败。虚拟网卡从OVS桥上摘除超时或者DHCP租约没有释放也会导致整个删除流程卡住。遇到卡在DELETING的实例我从上到下的排查顺序是这样的# 1. 看Nova数据库里实例当前的状态和task_state mysql -u nova -p -e SELECT uuid, vm_state, task_state, power_state FROM nova.instances WHERE uuidserver_id; # 2. 查nova-conductor和nova-compute的日志定位卡在哪一步 grep server_id /var/log/nova/nova-compute.log | tail -50 # 3. 查计算节点上实例是否真的还存在 virsh list --all | grep server_id如果确认虚拟机的QEMU进程已经没了、卷已经摘干净了、端口也释放了就是数据库状态卡住了这时候才考虑用openstack server delete --force去强制清理。注意force delete仍然依赖nova-compute去清理如果nova-compute服务本身已经挂了这个命令也救不了你得手动在数据库层修正状态——这个操作风险极高动之前一定要备份数据库。5.2 Pause之后无法Resume实例一直卡在PAUSED状态这个问题的根因绝大多数情况是宿主机层面的问题。常见的有这么几种一是QEMU进程异常。Pause之后QEMU进程收到了挂起信号但恢复的时候信号没有正确送达进程卡在了一个中间状态。在计算节点上执行virsh resume instance_name看libvirt怎么响应。如果libvirt返回错误多半是QEMU自身出了问题可能得考虑重启nova-compute服务这会影响到该节点上所有实例要做就挑维护窗口做。二是CPU特性集变更。如果宿主机的CPU型号支持某些特性比如VMX/SVM嵌套虚拟化而Pause期间有人改动了宿主机的BIOS设置或者内核参数恢复的时候QEMU检测到CPU特性集不一致就会拒绝恢复。这种问题在运维层面挺难搞的因为改完之后宿主机的CPU能力变了虚拟机CPU配置不匹配。最好在修改宿主机BIOS之前把上面所有运行的实例都迁走或者关机。三是Nova和libvirt版本不匹配导致的状态同步问题。Nova会在数据库里记录实例的power_state而libvirt才是实际状态的管理者。因为网络分区、消息堆积等原因Nova的定时任务可能把实例状态同步错了。这种时候nova reset-state --active server_id可以帮你把数据库状态强制拉回active但前提是libvirt层面实例真的是跑着的。千万别在libvirt层面还paused的时候用reset-state那只会带来更多状态不一致的坑。5.3 快查速记表我把常见问题和对应的第一反应整理成了下表直接收藏用。场景表象第一反应删除实例卡在DELETING任务执行超时查看nova-compute日志确认QEMU进程和Cinder卷状态删除实例时卷被误删卷跟着没了检查delete_on_termination属性确认是否有备份强制删除后端口残留网络端口无法释放手动清理Neutron端口确认OVS桥上没有流表残留Pause后Unpause失败实例一直PAUSED在计算节点上virsh resume确认libvirt报错信息Suspend恢复特别慢RESUME卡了很久检查宿主机的磁盘IO和内存状态文件大小实例状态和实际不一致数据库显示ACTIVE但实际关了reset-state之前先确认libvirt里的真实状态5.4 一条避免99%误删的实操习惯文章最后聊一个习惯问题。Terminate Instance的破坏力是直接的Pause/Resume虽然不破坏数据但操作不当也会造成业务中断。我自己在团队里定了一条铁律任何对生产实例的删除、挂起、休眠操作都必须先走一个变更申请哪怕是自己开发的脚本调用API也要打日志、留记录、设置审批。具体执行起来就是三步第一步操作前拉一遍实例的详细信息把卷、端口、IP记录下来重要数据确认有备份或者快照第二步操作完成后立刻检查实例状态、卷状态、网络端口状态确认和预期一致第三步把操作记录归档特别是失败了要保留现场日志。这套流程看着很简单但严格执行下来可以帮你避开绝大多数的低级事故——我见过太多次凌晨三点删错实例的悲剧了根源都不是技术问题是习惯问题。根据我个人经验处理实例生命周期操作技术上最难的部分其实不是命令怎么敲、参数怎么配而是你心里对这台虚拟机现在到底是什么状态、它依赖哪些资源、删掉之后会影响谁要有清晰的判断。把这个判断能力练出来你才算真正玩明白了OpenStack里的虚拟机和运维。
返回列表