OpenStack里那么多服务,我平时被人问得最多的除了Nova就是Cinder。Cinder这个名字你只要搞过OpenStack就绕不开,它负责的是整个平台的块存储服务,云硬盘、虚拟机的数据盘、快照这些全都归它管。很多人搭好了环境却不知道怎么把存储用起来,或者一遇到卷创建失败、挂载不上就抓瞎。这篇就把Cinder从概念到实操捋一遍,卷类型怎么建、后端怎么配、命令行怎么敲、出问题怎么排查,全部按实际干活的方式讲清楚,适合刚搭完OpenStack准备上业务的人,也适合已经踩了不少坑想找排查思路的老手。
1. 先搞懂Cinder在OpenStack里的定位与核心思想
Cinder全称是OpenStack Block Storage,提供的是块级别的存储服务。它解决的问题说起来很简单:虚拟机跑在计算节点上,默认的本地磁盘是临时的,一旦虚拟机删除或者迁移,数据就跟着没了。为了让数据能够持久化、能够独立于虚拟机存在,就需要一套统一的存储服务,Cinder就是干这个的。
1.1 为什么计算和存储要拆成两个服务
Nova管计算实例,Cinder管存储卷,两者分开的原因不是架构师闲得没事,而是现实需求逼出来的。计算资源通常是弹性伸缩的,扩容缩容很频繁,而数据存储则要求稳定持久,两者生命周期完全不一样。如果存储跟着计算走,那虚拟机一删数据就没了;如果计算跟着存储走,那调度就会变得极其僵硬。拆开之后,卷可以独立创建、独立挂载到任意一台虚拟机、独立备份和迁移,计算节点宕机了数据也在,虚拟机删了卷还在,这才是云平台该有的形态。
另外拆分之后还有一个好处:Cinder通过驱动机制支持几十种后端存储,LVM、NFS、Ceph、各种商业存储阵列都能接进来。这样底层存储的差异被Cinder屏蔽掉,上层用户只需要看到统一的卷接口就行。实际用起来,你会感受到这种设计的价值——你创建卷的时候根本不用关心这块盘背后是分布式存储还是一台NAS,只要指定卷类型就够了。
1.2 四个核心组件各自都在忙什么
Cinder的核心组件有四个,我分开讲一下它们各自的分工。
cinder-api是整个Cinder的入口,所有API请求都先进这里,不管是命令行、Horizon界面还是其他服务调用,都得通过它来路由。它做的事情相当于前台接待,收请求、做初步校验,然后交给后台处理。
cinder-scheduler是调度器,负责决定每个卷应该创建在哪个后端存储上。它会根据卷类型、容量需求、后端存储的空闲情况等条件来筛选。这层调度逻辑跟Nova的scheduler思路很像,核心目标就是把卷放到最合适的存储池里。
cinder-volume是真正干活的组件,它直接和后端存储打交道,创建卷、删除卷、挂载连接、扩容快照,这些操作最终都是它来执行。它从调度器收到任务后,通过对应的驱动调用底层存储接口完成实际动作。
cinder-backup负责把卷备份到对象存储(比如Swift或者Ceph的RGW),是数据安全的最后一道保险。
实际部署中,cinder-api和cinder-scheduler通常部署在控制节点,cinder-volume可以部署在控制节点也可以独立部署在存储节点,取决于你的后端存储方案。如果后端是网络存储(比如Ceph或者商业存储),cinder-volume放控制节点问题不大;如果用本地LVM做后端,那cinder-volume就必须跑在真正持有物理卷的那台机器上,这是很多人配置LVM后端时容易踩的坑。
1.3 你天天打交道的卷、卷类型和快照
卷这个概念不复杂,可以理解成一块云上的硬盘,独立于虚拟机存在,格式上是块设备,可以挂给虚拟机当数据盘或者启动盘。
卷类型(Volume Type)就比较重要了,它是卷的配置模板,决定了卷最终落到哪个后端存储、有没有启用压缩、是不是SSD等属性。创建卷类型只是第一步,关键是要把卷类型和后端存储关联起来,再通过extra-specs来设置具体参数,这个在第二章细讲。
快照则是卷在某个时间点的只读副本,基于快照可以恢复数据,也可以快速创建新卷。LVM后端利用的是LVM的thin snapshot机制,Ceph后端利用的是RBD的快照机制,本质都是在底层存储层面做引用计数,所以快照创建通常是秒级的。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 上手前的准备工作:认证、卷类型与后端配置
不管你是用命令行还是Horizon界面,动手创建卷之前,环境上有些准备工作必须做好。多数人失败都是因为跳过了这一节。
2.1 让命令行认识你的OpenStack环境
用命令行操作OpenStack之前,第一件事是导入认证变量。一般是通过source你个人的openrc文件来导入用户名、密码、项目名、认证地址等信息。这一步不做,后面所有openstack命令都会报认证失败。
bash复制source /root/admin-openrc.sh
openstack token issue
执行openstack token issue看到输出了token信息,说明认证通了。这一步看似简单,实际经常出问题的是openrc文件里的OS_PROJECT_NAME和OS_USER_DOMAIN_NAME填得不一致,或者认证URL里端口写错。建议在刚刚创建Cinder服务后先执行一次token验证,排除基础认证问题再继续。
2.2 创建卷类型并指定后端驱动
卷类型的设计理念是:让使用者不用关心底层基础设施细节。用户创建卷时只需要说"我要一块高性能盘"或者"我要一块普通盘",至于这块盘是放在SSD存储池还是机械盘存储池,由管理员提前配好。
创建卷类型和执行关联的命令如下:
bash复制# 创建卷类型
cinder type-create lvm-ssd
cinder type-create nfs-hdd
# 查看已有卷类型
cinder type-list
创建之后,要配置extra-specs来告诉Cinder这个类型对应哪个后端。如果没有设置这一步,卷类型就是一个空壳,创建卷时会因找不到后端而失败。
bash复制cinder type-key lvm-ssd set volume_backend_name=LVM_SSD
cinder type-key nfs-hdd set volume_backend_name=NFS_HDD
volume_backend_name这个值必须和cinder.conf里后端的backend_name参数完全一致。不一致时,调度器会报"No valid backend"的错误,这个问题我在第五章故障排查里还会再提。
2.3 LVM后端的配置实例
LVM后端是最简单也最适合练手的方案,非常适合测试环境或者小规模部署。它直接利用Linux主机的LVM逻辑卷管理能力,在卷组上创建块设备。
在cinder-volume节点上编辑/etc/cinder/cinder.conf:
ini复制[lvm-ssd]
volume_driver = cinder.volume.drivers.lvm.LVMVolumeDriver
volume_group = cinder-volumes
volume_backend_name = LVM_SSD
target_protocol = iscsi
target_helper = lioadm
这里的volume_group指定的就是你在存储节点上用pvcreate和vgcreate创建好的卷组名字。创建卷时,Cinder会从这个卷组里划分逻辑卷出来。target_protocol设置成iscsi,配合target_helper=lioadm使用LIO作为iSCSI Target,这是我在Linux上用的最多的组合,稳定性不错。
配置完重启相关服务:
bash复制systemctl restart cinder-volume
tail -f /var/log/cinder/cinder-volume.log
日志里出现Driver init successful之类的信息,说明后端加载成功。同一台机器上可以配置多个后端,方法是配置多个带独立名字的配置段,然后通过enabled_backends参数启用它们。
ini复制[DEFAULT]
enabled_backends = lvm-ssd, nfs-hdd
这样一台cinder-volume就能同时管理LVM和NFS两种后端。
3. Cinder日常操作实战:从创建到删除的完整链路
准备工作做完,就到了真正干活的部分。这一节我把日常用得最多的操作用完整链路串起来,从创建卷、挂载、扩容、快照到删除,每一步都带上参数说明和注意事项。
3.1 创建云硬盘:参数逐个说明
创建卷是使用频率最高的操作,命令很简单:
bash复制openstack volume create --type lvm-ssd --size 20 --name my-data-disk
几个参数说明一下:
--type:指定卷类型。这里写的是lvm-ssd,会落到我们之前配置的LVM_SSD后端上。--size:容量大小,单位GB。创建时指定的容量不可以超过该用户的项目配额,否则会报QuotaExceeded。--name:卷的名字,相当于给这块盘起个标识。--description:可选,写备注用。--availability-zone:指定可用域,如果不指定会使用默认值。
创建完成后查看状态:
bash复制openstack volume list
openstack volume show my-data-disk
正常情况下状态会从creating变成available。这里有个细节,show命令输出的os-vol-host-attr:host字段可以看出这个卷最终落在哪台物理机的哪个后端上,排查问题时有用的很。
如果一直停在creating,说明后端有问题,参考第五章的排查方法。
3.2 挂载到虚拟机:注意实例内部的操作
卷创建好之后,挂载到虚拟机上有两种情况:创建虚拟机时挂载和创建完成后动态挂载。动态挂载的命令是:
bash复制openstack server add volume <server-name-or-id> <volume-id> --device /dev/vdb
执行完这条命令,OpenStack会调用Nova的volume attach接口,再由Nova通知底层hypervisor把卷作为块设备附加到虚拟机。命令返回成功不代表虚拟机内部已经能用,这一点很多新手会踩坑,实际上还要进入虚拟机内部做处理。
在Linux虚拟机内部执行以下命令:
bash复制# 查看系统识别到的块设备
lsblk
# 如果设备是空盘,需要创建分区和文件系统
fdisk /dev/vdb
mkfs.ext4 /dev/vdb1
# 创建挂载点并挂载
mkdir -p /data
mount /dev/vdb1 /data
# 写入fstab,重启后自动挂载
echo "/dev/vdb1 /data ext4 defaults 0 0" >> /etc/fstab
Windows虚拟机就更简单一些,打开磁盘管理,找到新出现的未初始化磁盘,右键联机、初始化、新建简单卷,一路下一步就行。
挂载后确认数据能正常写入再收工,这是我个人的习惯,防止出现共享卷、文件系统损坏这些隐藏问题。
卸载的操作对应的是:
bash复制openstack server remove volume <server-name-or-id> <volume-id>
注意,卸载前在虚拟机内部先执行umount,确保没有进程占用磁盘,否则可能出现数据不一致甚至文件系统损坏。这是个顺序问题,先卸主机层面的挂接,再卸实例内部的挂载,反了可能会出问题。
3.3 扩容和快照:数据安全的基本功
卷用着用着不够了,扩容是常事。Cinder支持在线扩容,意思是卷正在挂载使用时也能直接调大容量。
bash复制openstack volume set my-data-disk --size 100
扩容完成后,虚拟机内部的文件系统并不会自动感知到新空间,必须手动扩展文件系统。以ext4为例,先让分区识别新大小,再扩展文件系统:
bash复制# 重新读取分区表
partprobe /dev/vdb
# 扩展分区(如果卷没分区,直接跳过这步)
# 扩展文件系统
resize2fs /dev/vdb1
如果是xfs文件系统,用xfs_growfs /data。这个操作顺序出错的概率很高,我见过有人直接在扩容后什么都不做,重启一看数据还在但空间没变,其实这是正常的,文件系统需要你手动扩展。
快照在这个场景下的价值很大。做任何可能影响数据的操作之前,先打个快照总没错。创建快照的命令:
bash复制openstack volume snapshot create --volume my-data-disk --name my-data-disk-snap
快照创建几乎都是秒级的,因为底层用的是写时复制机制。需要恢复时,用快照创建新卷:
bash复制openstack volume create --snapshot my-data-disk-snap --size 100 --name my-data-disk-restored
这里有个内存中的坑:用快照创建新卷时,如果快照定义是100GB,新卷大小不能小于它,只能等于或大于。如果配小了会报错。
3.4 迁移、备份与删除
迁移卷这种操作,在传统物理环境下想都不敢想,但在Cinder里就是几行命令的事。最实用的场景是把卷从一个后端迁移到另一个后端,比如把普通HDD上的卷迁移到SSD上,提升性能。
bash复制cinder migrate <volume-id> <host#backend-name> --force-host-copy True
这里的host#backend-name格式,比如把卷迁移到LVM_SSD上就写cinder@lvm-ssd#LVM_SSD。--force-host-copy强制通过主机拷贝而不是底层驱动迁移,跨不同类型后端时必须用。
备份到对象存储,用到的是:
bash复制openstack volume backup create --name my-backup my-data-disk
备份功能依赖cinder-backup服务正常运行,并且底层配置了可用的对象存储。恢复备份的命令是openstack volume backup restore,恢复时目标卷大小不能小于原卷。
删除卷相对简单:
bash复制openstack volume delete my-data-disk
但要注意,卷正在挂载给虚拟机时直接删除,通常会被拒绝,需要先执行openstack server remove volume将卷和实例分离再删除。如果出现删不掉、状态一直卡在deleting的情况,参考第五章的处理方法。
4. 后端存储选型:LVM、NFS与Ceph怎么选
后端存储是Cinder里最影响运维体验的部分。很多环境出问题不是Cinder本身坏了,而是后端存储的配置或者驱动跟实际环境不匹配。这一节结合我自己的使用经验,把最常见的三种后端做个对比和选型建议。
4.1 三种后端的横向对比
| 对比项 | LVM(iSCSI) | NFS | Ceph(RBD) |
|---|---|---|---|
| 部署复杂度 | 低 | 低 | 高 |
| 数据冗余 | 无(依赖LVM镜像) | 取决于NFS服务器 | 多副本,自带冗余 |
| 性能表现 | 好(本地盘) | 一般(网络文件系统) | 好(分布式,多副本损耗) |
| 扩展性 | 差(受单机容量限制) | 中等(存储侧扩展) | 强(横向加节点) |
| 典型场景 | 测试环境、单节点试用 | 轻量共享存储、中小环境 | 生产环境、大规模云平台 |
| 常见坑点 | 卷组容量耗尽、iSCSI target异常 | NFS挂载权限、锁问题 | 网络带宽瓶颈、Pool配额 |
LVM的优势是简单直接,只要有一台Linux机器,装了lvm2,就能马上用起来。缺点也明显:单机容量有限,没有副本机制,一旦磁盘损坏数据就没了,所以不适合承载重要业务。
NFS后端有意思的地方在于,它能把一个文件系统目录变成块设备的存放位置,每个卷就是一个文件。配置NFS后端时需要先准备好一个NFS共享目录:
ini复制[nfs-hdd]
volume_driver = cinder.volume.drivers.nfs.NfsDriver
nfs_shares_config = /etc/cinder/nfs_shares
volume_backend_name = NFS_HDD
nfs_mount_point_base = /var/lib/cinder/nfs
nfs_shares_config文件里写一行NFS导出路径,例如192.168.1.10:/data/nfs。Cinder会自动挂载该共享并把卷文件放在下面。好处是管理简单、容量扩容容易,缺点是性能受NFS网络和文件系统本身的限制。
Ceph则是最主流的生产环境选择。通过RBD驱动,Cinder可以和Ceph深度集成,创建卷的本质是在Ceph中创建RBD image,快照用的是RBD快照,底层三副本、数据强一致。配置时通常要指定Ceph的配置文件和keyring:
ini复制[ceph-backend]
volume_driver = cinder.volume.drivers.rbd.RBDDriver
rbd_pool = volumes
rbd_ceph_conf = /etc/ceph/ceph.conf
rbd_flatten_volume_from_snapshot = False
rbd_max_clone_depth = 5
rbd_store_chunk_size = 4
rados_connect_timeout = -1
volume_backend_name = CEPH
生产环境用Ceph,我实际用下来最需要注意的一点是:Ceph集群的网络带宽必须足够,否则热迁移或大规模创建卷时,cluster网络会扛不住,表现为Cinder操作超时、Ceph osd报slow request。
4.2 如何让几种后端同时存在并按需分配
生产环境很少只用一种后端,最常见的是高性能SSD资源池给数据库用,普通HDD资源池给文件存储用,然后通过卷类型暴露给用户。
实现的思路就是前面提到的:在cinder.conf里配置多个后端段,用enabled_backends启用,然后为每个后端创建对应的卷类型,通过volume_backend_name关联。
bash复制cinder type-create ssd-high
cinder type-create hdd-normal
cinder type-key ssd-high set volume_backend_name=CEPH-SSD
cinder type-key hdd-normal set volume_backend_name=CEPH-HDD
然后在cinder.conf里把Ceph的Pool分别映射到不同Profile。这样用户在创建卷时只需要选择ssd-high或hdd-normal,完全不用关心后端细节。
我见过不少团队到这一步就止步了,结果所有卷都落在同一个后台上,性能和成本都无法区分。虽然搭建的时候多花一点时间配多后端,后面运维的灵活性能高一整个量级。
5. 高频故障与排查实录
这一节全是实战积累,我把日常运维中遇到的几类高频问题、排查思路和处理方法整理成速查表,尤其是Yoga版本里容易踩的卷分离失败bug,单独拿出来详细讲一下。
5.1 卷一直处于creating状态怎么办
卷卡在creating是新手最容易碰到的问题,也是最应该学会自救的场景。出现这个现象基本可以断定是cinder-volume环节出了问题。
排查套路按照下面几步走,80%的问题能快速定位:
-
看cinder-volume日志,确认后端驱动是否init成功。
bash复制tail -100 /var/log/cinder/cinder-volume.log | grep -i error -
确认cinder-volume服务进程还活着。
bash复制
systemctl status cinder-volume -
确认卷组存在且有剩余空间(LVM后端)。
bash复制
vgs lvs -
看cinder-scheduler日志,确认卷是否被调度成功。
bash复制tail -100 /var/log/cinder/cinder-scheduler.log
常见原因一个是cinder-volumes卷组不存在,创建卷时底层找不到卷组直接报错退出;另一个原因是cinder-volume节点的驱动配置里volume_group名字拼错。我遇到过最隐蔽的一种情况是:多后端配置了,但某一个后端的配置段缩进或参数名写错,导致该后端init失败,而cinder-api侧没有明显报错,只有日志里能看到。
把后端配置修正并重启cinder-volume后,对卡住的卷可以强制重置状态:
bash复制cinder reset-state --state available <volume-id>
如果卷本身没创建出来,最好直接删掉重建,避免留下脏数据。
5.2 Yoga版本卷分离失败bug的定位与处理
OpenStack Yoga版本里卷分离失败是社区里讨论很多的一个问题。现象是执行openstack server remove volume之后,命令卡住,或者命令返回了但卷在cinder侧一直显示in-use,再也无法执行删除、迁移、重新挂载等操作。底层日志会报Terminate connection failed或者Volume is still attached。
这个问题我实际排查过多次,根因往往出在attachment记录没有清理干净。虚拟机被强制删除、或者Nova和Cinder在分离过程中因为网络抖动导致事务没走完,数据库里就会残留attachment记录,Cinder以为卷还被挂着,就拒绝所有后续操作。
处理思路是先查数据库里的attachment记录。找到残留记录后,判断实例是否真的还在使用这个卷。如果确认已经不需要,手动删除attachment记录,并将卷状态重置为available。
bash复制# 找到卷对应的attachment记录
mysql -uroot -p -e "select id, volume_id, instance_uuid, attach_status from cinder.volume_attachment where volume_id='<volume-id>';"
# 确认实例已不存在或已不需要该卷后,清理attachment
mysql -uroot -p -e "delete from cinder.volume_attachment where volume_id='<volume-id>';"
# 将卷状态重置为available
cinder reset-state --state available <volume-id>
如果后端是iSCSI,还需要到计算节点上清理掉iSCSI会话:
bash复制iscsiadm -m session
iscsiadm -m node -T <target-name> -p <portal-ip> -u
这里要特别加一句:直接改数据库属于最后手段,操作前一定要确认卷确实不再被任何虚拟机使用,否则可能把使用中的卷搞成可用状态,造成数据写冲突。如果只是偶尔遇到一次,我更推荐先把计算节点上的nova-compute服务重启,再尝试一次分离,很多时候能自动恢复。
5.3 实例内不识别挂载的卷
挂载操作在OpenStack层面已经成功,进入虚拟机执行lsblk却看不到新设备,这种情况也很常见。
先确认OpenStack侧的挂载状态:
bash复制openstack volume show <volume-id>
看返回里有没有attached字段。如果显示attached,再看Nova侧:
bash复制openstack server show <server-id> -f json | grep -i volume
如果两者都是attached状态,大概率是虚拟机内部的操作系统没有扫描到新设备。Linux下尝试重新扫描SCSI设备:
bash复制echo "- - -" > /sys/class/scsi_host/host0/scan
或者重启虚拟机。如果重启后仍然看不到,检查设备名是否被占用,比如系统盘已经是/dev/vda,新卷被设置成/dev/vdb,但某些内核版本下设备枚举顺序不同,可能出现命名错位。这时候用dmesg | grep vd看内核日志能帮上大忙。
Hypervisor层面如果是KVM+qemu,还需要关注驱动类型。Cinder卷默认走virtio-blk或者virtio-scsi,Windows虚拟机如果没有安装对应的guest驱动,设备会显示为Unknown Device而无法初始化,这种情况只能通过安装virtio驱动解决。
5.4 删除卷卡在deleting的处理
删除卷是另一个高频故障场景,现象是执行openstack volume delete后,卷状态一直是deleting,再也不动了。
绝大多数原因是卷仍然处于挂载状态,但OpenStack层面的状态因为前面的一些异常没有同步。先检查卷当前状态,如果是in-use,老老实实先分离再删除。如果是available但一直deleting,问题通常出在后端存储无法真正删掉底层数据。
排查流程:
- 检查cinder-volume日志,看具体报错。
- LVM后端:确认该卷对应的逻辑卷是否存在且能被删除,可能被快照引用导致无法删除。
bash复制lvs lvremove -f /dev/cinder-volumes/volume-<id> - Ceph后端:检查RBD image状态,必要时手动删除残留。
bash复制rbd ls volumes rbd rm volumes/volume-<id> - 确认底层资源清理完毕后,执行:
bash复制
cinder reset-state --state error <volume-id> openstack volume delete <volume-id>
这种场景我处理过很多次,最核心的要点是:不要只在上层做reset,一定要把底层存储的资源一并清掉,否则下次创建同名的卷时可能引发数据冲突。
| 故障现象 | 大概率原因 | 首选排查动作 |
|---|---|---|
| 卷卡creating | 后端驱动init失败 / 卷组不存在 | 看cinder-volume日志,确认卷组空间 |
| 卷一直在in-use,无法分离 | attachment记录残留 | 查数据库attachment,清理后reset-state |
| 实例内看不到新挂载盘 | 内核未扫描 / 驱动缺失 | 重新扫描SCSI设备,确认驱动 |
| 删除卷卡deleting | 底层资源未清理 / 快照引用 | 看日志,手动清底层LV/RBD image |
一点个人的使用体会
Cinder用久了你会慢慢发现,它的坑大多不在Cinder本身,而在你对底层存储的理解深度。LVM后端简单,但你要懂LVM才能排障;Ceph后端强大,但你要懂Ceph才能用好。不管用哪种,日志永远是第一线索,/var/log/cinder/下的日志记录了所有真相,排障时先看日志再动手改数据,这个习惯能帮你避免很多误操作。另一个体会是卷类型这个设计真的很值得认真对待,提前规划好卷类型和后端映射,后续运维能少很多麻烦。数据安全无小事,任何操作前先备份,再稳都不为过。
