云原生运维笔记:硬核拆解OpenStack计算与存储------从主机聚合到Cinder挂载全流程
前面的时间里,我们把Keystone的认证逻辑、Glance的镜像管理,以及那个神秘的"29步创建虚拟机"的黑盒流程里里外外扒了个遍,算是把OpenStack的"地基"和"仓库"给摸透了。但如果光有镜像和一套认证体系,我们连个毛线都跑不起来。今天算是正式进入了实战的深水区------OpenStack计算管理(Nova)与存储管理(Cinder)。
说实话,这两块的复杂度比前面高了一个量级。计算管理涉及到物理资源的划分、调度算法、实例规格的限制,以及虚拟机极其丰富的生命周期状态流转(暂停、挂起、搁置,傻傻分不清楚对吧?)。而存储管理更是重量级,Cinder的架构、后端LVM的对接、卷的挂载卸载、快照与扩容,每一个概念如果不搞清楚,后面搞生产环境绝对是一踩一个不吱声。
这篇博客当作我今天的实验复盘。我会严格按照实验手册以及补充的管理资料,把Dashboard上的图形化操作,和背后对应的CLI命令完整梳理一遍,并且把今天踩过的坑(比如主机聚合的AZ冲突、规格为什么变不成Public、卷处于in-use状态删不掉)统统记录在案。内容很长,但全都是实打实的干货,建议连同代码块一起直接复制进Typora当字典查。
一、 OpenStack计算管理(Nova)实操复盘
计算管理就是管"算力"。在Nova的世界里,我们要搞清楚谁在提供算力(Hypervisor)、算力怎么分组(主机聚合/可用域)、算力的套餐(实例类型/Flavor),以及虚拟机实例的完整生命周期。
1.1 Hypervisor 与 主机聚合(Host Aggregates)
首先得了解底层的物理资源。登录Dashboard后,进入管理员 -> 计算 -> 虚拟机管理器 。这里能直观看到我们实验环境里的两个计算节点:controller 和 compute。它们的状态都是"激活/启动",后面跟着它们所剩的VCPU和内存。
接下来是重头戏:主机聚合(Host Aggregate)。这个概念在考试和面试里经常和**可用域(Availability Zone, AZ)**放在一起问。简单来说,主机聚合是底层物理机的一个逻辑分组,而AZ是暴露给最终用户的逻辑概念。一个主机聚合通常会对应一个AZ,但一个主机可以加入多个主机聚合。
在界面上创建主机聚合:
- 进入 管理员 -> 计算 -> 主机聚合,点击"创建主机聚合"。
- 名称填入
HostAggr_web,可用域填入nova。 - 在"管理聚合内的主机"页签,把
controller移入选中的主机,点击"创建"。
踩坑记录:一个主机能不能加入不同的AZ?
手册里有个验证环节,我照着做了一下。我尝试再创建一个名为 HostAggr_web_test 的聚合,可用域设置为 AZ_web,然后把 controller 加进去。结果直接弹窗报错:"错误:向聚合中添加主机时出错"。这说明同一个物理主机在同一个时间点,只能属于一个AZ 。但是,如果你把 HostAggr_web_test 的AZ改回 nova(和第一个聚合一样),再添加 controller,是可以成功的。也就是说,同一个主机可以加入多个主机聚合,但这些聚合的AZ必须相同。
用命令行验证一下:
bash
[root@controller ~]# source keystonerc_admin
[root@controller ~(keystone_admin)]# openstack hypervisor list --long
# 这里会列出 controller 和 compute 的详细资源情况
# 创建主机聚合
[root@controller ~(keystone_admin)]# openstack aggregate create --zone nova HostAggr_cli
+-------------------+---------------------------+
| Field | Value |
+-------------------+---------------------------+
| availability_zone | nova |
| created_at | 2024-08-13T06:30:24.269570|
| id | 4 |
| name | HostAggr_cli |
| hosts | None |
+-------------------+---------------------------+
# 验证AZ冲突
[root@controller ~(keystone_admin)]# openstack aggregate create --zone AZ_cli HostAggr_cli_test
[root@controller ~(keystone_admin)]# openstack aggregate add host HostAggr_cli_test controller
# 报错:Cannot add host to aggregate 5. Reason: One or more hosts already in availability zone(s) ['nova', 'nova']. (HTTP 409)
这背后的逻辑其实很好理解,AZ往往对应着机架或者数据中心,防止单点故障。如果一台机器同时属于两个不同的AZ,那高可用调度的时候就彻底乱套了。
1.2 实例类型(Flavor)管理与公有/私有之惑
规格(Flavor)就是虚拟机的硬件套餐。创建虚拟机时,你只能选规格,不能自己随便填CPU和内存。
界面操作: 进入 管理员 -> 计算 -> 实例类型 ,点击"创建实例类型"。填入名称 Flavor_web,VCPU给1,RAM给128MB,根磁盘给1GB。在"实例类型使用权"页签,只勾选 Project_web,点击创建。这说明这个规格是私有的,只有Project_web能用。
踩坑记录:移除所有项目,规格会变成公有(Public)吗?
手册里特别提了一个验证题。如果我把刚才选中的 Project_web 移除,是不是等于所有项目都能用了?
答案是否定的。移除所有项目后,该规格不仅不是Public,反而变成了"谁都不能用(不可见)"。如果你想要一个Public的规格,在命令行创建时,直接不指定任何项目就行了。
bash
# 创建指定项目可见的规格
[root@controller ~(keystone_admin)]# openstack flavor create --vcpus 1 --ram 128 --disk 1 --private --project Project_cli Flavor_cli
+----------------------------+--------------------------------------+
| Field | Value |
+----------------------------+--------------------------------------+
| OS-FLV-DISABLED:disabled | False |
| name | Flavor_cli |
| os-flavor-access:is_public | False |
| ram | 128 |
| vcpus | 1 |
+----------------------------+--------------------------------------+
# 移除项目的可见性,它依然不是 Public
[root@controller ~(keystone_admin)]# openstack flavor unset --project Project_cli Flavor_cli
[root@controller ~(keystone_admin)]# openstack flavor show Flavor_cli | grep is_public
| os-flavor-access:is_public | False |
# 如何创建 Public 的规格?直接建,不加 --private
[root@controller ~(keystone_admin)]# openstack flavor create --vcpus 1 --ram 128 --disk 1 Flavor_cli_public
总结:规格一旦创建,就无法动态修改其属性(比如从Private变Public)。想改?只能删了重建,这是Nova的一个硬性规定。
1.3 密钥对与虚拟机组(Server Group)
密钥对(Key Pair)大家都很熟悉了,就是SSH登录凭证。在 项目 -> 计算 -> 密钥对 中,点击"创建密钥对",生成 KeyPair_web 并自动下载 .pem 文件。
虚拟机组(Server Group)是控制虚拟机调度的一种策略。我们在创建时,有几种策略可选:
- 关联(Affinity):组内的虚拟机必须挤在同一台物理机上。适合需要极低延迟通信的集群(比如HPC)。
- 不关联(Anti-Affinity):组内的虚拟机绝对不能在同一台物理机上。适合高可用场景,防止物理机宕机导致全军覆没。
- 软关联 / 软不关联:柔性策略,资源充足时遵守,不充足时妥协。
我们在界面创建一个名为 ServerGroup_web 的组,策略选择"关联"。
1.4 虚拟机实例的"一生":发放与状态流转
在界面 项目 -> 计算 -> 实例 中点击"创建实例",一路Next。选源(Img_web)、选规格(Flavor_web_test)、选网络(shared)、选密钥对,最后在服务器组里选中刚才创建的那个亲和性组,点击创建。
但这只是开始,真正的重头戏是虚拟机的生命周期管理。今天的实验里,我几乎把所有的状态都点了一遍:
- 关机 / 开机 :常规操作,
Status变为关机。 - 软重启 / 硬重启 :软重启只是重启OS(相当于Linux里的
reboot),硬重启是直接拔电源再开机。界面上执行软重启后,任务状态会显示"软重启中"。 - 锁定 / 解锁 :为了防止手滑误删实例,admin用户可以将实例"锁定"。踩坑点 :默认情况下,普通用户(非admin)是可以对admin锁定的实例进行"解锁"并删除的!这非常不安全。后来我跟着资料把
/etc/openstack-dashboard/nova_policy.json里面的unlock权限改为了rule:admin_api,普通用户就彻底懵了,完全动不了锁定的实例。 - 暂停(Pause)与 挂起(Suspend) :
- 暂停 :把虚拟机的状态直接保存在宿主机的内存里,电源状态变为"已暂停"。恢复(Unpause)极快。
- 挂起 :把状态保存到宿主机的磁盘上,电源状态变为"关闭"。恢复(Resume)需要从磁盘读回内存,相对较慢。
- 废弃(Shelve):这个最狠。它会把虚拟机变成Glance里的一个镜像,然后在宿主机上把它彻底删掉,释放所有资源。需要的时候(UnShelve)再重新创建出来。适合长期不用的僵尸机。
- 快照与重建:给运行中的机器打快照(本质上是变成一张新镜像),如果虚拟机系统崩了,可以选择"重建实例",选择刚才的快照,相当于一键还原。
用CLI看下实例列表和发放过程:
bash
[root@controller ~(keystone_admin)]# openstack server create --availability-zone nova --image Img_cli --flavor Flavor_cli --network shared --key-name KeyPair_cli Instance_cli_01
# 命令回显中会显示 OS-EXT-STS:task_state 为 scheduling,然后 building,最后 active
# 查看实例列表
[root@controller ~(keystone_admin)]# openstack server list
+--------------------------------------+----------------+--------+-----------------------+
| ID | Name | Status | Networks |
+--------------------------------------+----------------+--------+-----------------------+
| 0f0b35d5-4c7d-42dd-8edf-9655748a5013 | Instance_cli_01| ACTIVE | shared=192.168.233.186|
+--------------------------------------+----------------+--------+-----------------------+
1.5 调整实例大小(Resize)的坑
在实例的操作列表里,有个"调整实例大小"。我们试着把原本 128MB 内存的规格调整为 156MB 的 Flavor_web_new。
界面点击调整后,状态会变成 确认或放弃调整大小/迁移。你必须再点一次"确认调整大小/迁移",才算真正完成。
踩坑点:手册里提到,如果把内存调到"64MB"(比当前还小),或者环境里没有共享存储(NFS/Ceph)且是多节点环境,调整大小会失败。因为调整大小本质上是一个带迁移的动作,底层存储如果不在共享目录里,数据根本拉不过去。这为后面搞Cinder NFS存储埋下了伏笔。
二、 深入OpenStack存储管理(Cinder)
计算折腾完,终于来到了存储。按照资料里说的,OpenStack的持久化存储有三大类:块存储(Cinder)、对象存储(Swift)和文件系统存储(Manila)。今天重点折腾的是块存储Cinder。
2.1 Cinder 架构与核心概念
不要把Cinder当成一个真实的物理硬盘,它其实是一个抽象的中间层 。
架构上,cinder-api 负责收请求,cinder-scheduler 负责选后端节点,cinder-volume 负责真正干活,底层对接的可能是LVM、SAN、Ceph等。
默认的实验环境里,Cinder对接的后端就是LVM。具体来说,它是把Linux的物理卷(PV)做成卷组(VG),然后从中切出逻辑卷(LV)给虚拟机用。我们可以在控制节点执行 vgdisplay cinder-volumes 看到,系统切了 20GB 的空间作为存储池。
在创建卷之前,得先搞定**卷类型(Volume Type)**和 QoS(服务质量)。
- 界面操作:管理员 -> 卷 -> 卷类型 ,创建
VolumeType_web,勾选"公有"。 - 接着创建 QoS 规格
QoS_web,消费者选"后端"。 - 然后回到卷类型列表,把 QoS 关联到
VolumeType_web上。
用CLI走一遍:
bash
# 创建卷类型
[root@controller ~(keystone_admin)]# openstack volume type create --public VolumeType_cli
# 创建QoS
[root@controller ~(keystone_admin)]# openstack volume qos create --consume back-end QoS_cli
# 将QoS关联到卷类型
[root@controller ~(keystone_admin)]# openstack volume qos associate QoS_cli VolumeType_cli
2.2 卷的创建、挂载与卸载
这是最核心的日常操作。我们在 项目 -> 卷 -> 卷 里创建一个基于镜像的卷。
- 卷名称:
Volume_web_01 - 卷来源:镜像
- 使用镜像:
Img_web - 类型:
VolumeType_web - 大小:1GB
创建完成后,状态从"创建中"变为"可用"。接着,我们要把它挂载到刚才发放的虚拟机 Instance_web_01 上。
点击"管理连接",选择实例,点击"连接卷"。此时,卷的状态变为"正在使用",在实例内部,你会多出一块 /dev/vdb 的裸盘。
如果不需要了,点击"管理连接",点击"分离卷",状态重新回到"可用"。
CLI 操作流:
bash
# 创建卷
[root@controller ~(keystone_admin)]# openstack volume create --image Img_cli --type VolumeType_cli --size 1 Volume_cli_01
# 挂载给实例
[root@controller ~(keystone_admin)]# openstack server add volume Instance_cli_01 Volume_cli_01
# 查看卷挂载状态
[root@controller ~(keystone_admin)]# openstack volume list
| aa0caa97-3369-4310-b159-e5ade3eea939 | Volume_cli_01 | in-use | 1 | Attached to Instance_cli_01 on /dev/vdb |
# 卸载
[root@controller ~(keystone_admin)]# openstack server remove volume Instance_cli_01 Volume_cli_01
2.3 高级操作:上传、快照、扩容与基于快照建卷
Cinder的强大之处在于它的快照和克隆能力。
上传卷到镜像:如果我们把系统盘装好了环境,可以直接把这个卷打包成Glance镜像。在界面上点击卷的"上传镜像",填入名称,格式选QCOW2。在CLI下就是:
bash
[root@controller ~(keystone_admin)]# openstack image create --volume Volume_cli_01 --disk-format qcow2 Volume_Img_cli
创建卷快照 :点击卷的"创建快照",起名 Volume_Snap_web。注意,快照依赖原卷,如果原卷不删,快照就占着坑。
卷扩容:点击"扩展卷",把大小从1GB改成2GB。
bash
[root@controller ~(keystone_admin)]# openstack volume set --size 2 Volume_cli_01
注意:扩容后,只是Cinder层面的容量变大了,如果里面已经跑着文件系统,还需要在虚拟机内部执行 resize2fs 或 xfs_growfs 才能真正用上新增的空间。
基于卷快照创建卷 :在快照列表里,点击"创建卷",相当于恢复数据。
基于卷发放虚拟机实例:如果卷里已经有完整的OS,可以直接用这个卷当启动盘发虚拟机。
bash
# 使用已有卷创建实例
[root@controller ~(keystone_admin)]# openstack server create --volume Volume_cli_02 --flavor Flavor_cli Instance_cli_03
踩坑点 :如果这个卷被标记为"非启动卷"(--non-bootable),用它是建不了虚拟机的,直接报错 Block Device ... is not bootable。
2.4 删不掉!卷的删除依赖链
实验到最后,我想把创建的东西清理一下。结果发现卷删不掉。
系统报错:Invalid volume: Volume status must be available or error... and must not be migrating, attached, belong to a group, have snapshots...
这个报错信息其实极其精准:
- 卷现在是
in-use,必须先卸载(如果卸载报错说它是系统盘,那你只能先删虚拟机)。 - 卷还有快照,必须先删快照。
- 如果状态是
error,反而可以直接删。
删卷的顺序必须是:卸载卷 -> 删快照 -> 删卷。
bash
# 尝试直接删卷(失败)
[root@controller ~(keystone_admin)]# openstack volume delete Volume_cli_01
# 报错,因为有快照
# 删除快照
[root@controller ~(keystone_admin)]# openstack volume snapshot delete Volume_Snap_cli
# 再次删除卷(成功)
[root@controller ~(keystone_admin)]# openstack volume delete Volume_cli_01
2.5 扩展实战:配置 NFS 共享存储后端
手册最后提到了一个非常关键的配置项:配置NFS共享存储。因为我们在虚拟机调整大小(Resize)的时候,如果是多节点且没有共享存储,就一定会失败。为了彻底解决这个问题,我们需要把Cinder的后端从纯本地LVM改为对接NFS。
操作步骤:
- 准备一台NFS服务器(或者用模板克隆一台IP为
192.168.108.12的节点)。 - 在NFS节点上安装服务并配置共享目录:
bash
mkdir /nfs_share
chmod -R 777 /nfs_share
yum -y install nfs-utils
echo "/nfs_share *(rw,sync,no_root_squash)" > /etc/exports
systemctl stop firewalld.service
systemctl restart nfs-server
systemctl enable nfs-server
- 在控制节点 上,修改
/etc/cinder/cinder.conf:
ini
# 开启多后端支持
enabled_backends = lvm,nfs
[lvm]
volume_backend_name = lvm
volume_driver = cinder.volume.drivers.lvm.LVMVolumeDriver
target_ip_address = 192.168.108.10
target_helper = lioadm
volume_group = cinder-volumes
[nfs]
nfs_mount_point_base = /mnt/nfs_share
nfs_shares_config = /etc/cinder/nfs_shares
volume_driver = cinder.volume.drivers.nfs.NfsDriver
volume_backend_name = nfs
- 创建共享配置文件:
bash
echo "192.168.108.12:/nfs_share" > /etc/cinder/nfs_shares
mkdir -p /mnt/nfs_share
chown -R cinder:cinder /mnt/nfs_share
systemctl restart openstack-cinder-volume
- 关键一步:创建对应的卷类型 。在界面上创建一个名为
nfs的卷类型,并在"扩展规格"里配置键值对:键填volume_backend_name,值填nfs。这样用户在创建卷时,选择nfs类型,Cinder就会把数据写进NFS共享目录里了。
当有了这个共享存储后,多节点间的虚拟机调整大小和迁移就完全不在话下了。
三、 踩坑总结与心得感悟
今天这一大波计算和存储的实操,信息量确实有点大。挑几个印象最深的说:
- 主机聚合(Host Aggregate)的坑:同一台物理机不能跨AZ加入多个聚合,Nova死板是为了保护高可用机制。
- Flavor的Public到底怎么来:移除所有项目可访问权,并不会让它变成所有人可见的Public,而是变成了"隐形人"。要Public,建的时候别指定项目。
- 虚拟机生命周期里的细节:暂停(Pause)是把内存存在宿主机,挂起(Suspend)是存在磁盘。废弃(Shelve)是直接删机器存镜像。这几个动作如果不亲手点一遍,光看书真的很容易混。
- 安全组的解锁策略 :默认配置下普通用户居然能解开管理员上的锁,这是一个很危险的设计,必须改
nova_policy.json才能达到真正的"防误删"目的。 - Cinder的删除链 :删卷之前必须断挂载、删快照、删备份。哪个环节卡住都会报
Invalid volume,学会看报错原因,按顺序清资源才是王道。 - Cinder背后有LVM和NFS:Cinder本身不存数据,它是在指挥后端存储。本地的LVM只能单机玩,要搞热迁移和调整大小,还得是共享的NFS或者Ceph。
从图形界面的直觉操作,到CLI命令行的底表操作,再到配置文件里的深水区(比如Cinder的 cinder.conf 和后端对接),这不仅是把知识点过了一遍,更是对"云"这个东西从抽象走向了具体的认知。
云原生这条路确实很长,光是一个Nova的计算调度(Filter和Weight的计算)就足够写几篇论文了,更别提还有对象存储Swift和网络Neutron还没正式开搞。但今天这一套组合拳打下来,我已经能脑补出:当你在Dashboard上轻轻点一下"创建实例"时,底下的物理资源是如何被Flavor限制、被Scheduler调度、被Cinder挂盘、最后被Hypervisor拉起来的全貌了。