Cinder 深度解析:OpenStack 块存储服务原理与实践

Cinder 深度解析:OpenStack 块存储服务原理与实践

定位与职责

Cinder 是 OpenStack 的块存储服务,提供持久化的块设备(云硬盘):

  • 创建、删除、扩容云硬盘(Volume)
  • 挂载/卸载到虚拟机
  • 快照(Snapshot)与备份(Backup)
  • 从快照/镜像创建卷
  • 卷类型(Volume Type)与 QoS 策略

Cinder 只管理块设备的生命周期,不关心文件系统,格式化是 VM 内部的事。


架构总览

1
2
3
4
5
6
7
8
9
10
11
12
cinder-api          ← REST API 入口
│ RPC

cinder-scheduler ← 选择存储后端(FilterScheduler)
│ RPC

cinder-volume ← 实际操作存储后端

├── LVM Driver → 本地 LVM 逻辑卷
├── Ceph RBD Driver → Ceph 分布式存储
├── NFS Driver → NFS 共享存储
└── 第三方 Driver → NetApp/EMC/Pure Storage 等

进程职责

进程 职责
cinder-api 接收 HTTP 请求,写入数据库,发送 RPC 消息
cinder-scheduler 根据卷类型和后端能力选择合适的 cinder-volume
cinder-volume 调用存储驱动执行实际操作
cinder-backup 卷备份到对象存储(Swift/S3/Ceph)

卷驱动体系

驱动接口

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# cinder/volume/driver.py

class VolumeDriver:
"""所有存储驱动的基类"""

def create_volume(self, volume):
"""创建卷"""
raise NotImplementedError

def delete_volume(self, volume):
"""删除卷"""
raise NotImplementedError

def create_snapshot(self, snapshot):
"""创建快照"""
raise NotImplementedError

def initialize_connection(self, volume, connector):
"""返回连接信息(iSCSI target/Ceph mon 地址等)"""
raise NotImplementedError

def attach_volume(self, context, volume, instance_uuid, host_name, mountpoint):
"""挂载卷到实例"""
raise NotImplementedError

LVM Driver(本地存储)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# cinder/volume/drivers/lvm.py

class LVMVolumeDriver(VolumeDriver):
def create_volume(self, volume):
# 调用 lvcreate 创建逻辑卷
self.vg.create_volume(volume.name, volume.size, ...)

def initialize_connection(self, volume, connector):
# 返回 iSCSI 连接信息
return {
'driver_volume_type': 'iscsi',
'data': {
'target_portal': '10.0.0.1:3260',
'target_iqn': 'iqn.2010-10.org.openstack:volume-xxx',
'target_lun': 1,
}
}

Ceph RBD 集成(生产主流方案)

Ceph 是 OpenStack 生产环境最常用的存储后端,Nova/Cinder/Glance 都可以对接 Ceph。

架构

1
2
3
4
5
6
7
8
Nova compute 节点
│ librbd(直接访问,无需 iSCSI)

Ceph RBD Pool
├── volumes/ ← Cinder 卷
├── images/ ← Glance 镜像
├── vms/ ← Nova 实例磁盘(ephemeral)
└── backups/ ← Cinder 备份

Ceph RBD Driver 关键实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
# cinder/volume/drivers/rbd.py

class RBDDriver(VolumeDriver):
def create_volume(self, volume):
# 在 Ceph pool 中创建 RBD image
with RADOSClient(self) as client:
rbd.RBD().create(
client.ioctx,
volume.name,
volume.size * units.Gi,
order=22, # 4MB object size
old_format=False,
features=client.features,
)

def initialize_connection(self, volume, connector):
# 返回 Ceph 连接信息(不需要 iSCSI,直接 librbd)
return {
'driver_volume_type': 'rbd',
'data': {
'name': f'{self.configuration.rbd_pool}/{volume.name}',
'hosts': self.configuration.rbd_ceph_conf,
'auth_username': self.configuration.rbd_user,
'auth_enabled': True,
'secret_type': 'ceph',
'secret_uuid': self.configuration.rbd_secret_uuid,
}
}

Ceph 对接配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# cinder.conf
[DEFAULT]
enabled_backends = ceph

[ceph]
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
rbd_user = cinder
rbd_secret_uuid = <libvirt-secret-uuid>
volume_backend_name = ceph

快照机制

快照原理(COW)

1
2
3
4
5
6
7
8
9
10
原始卷(Volume)

▼ 创建快照(瞬间完成,COW)
快照(Snapshot)← 记录创建时刻的数据指针

▼ 后续写入
原始卷继续写入新数据,快照保留旧数据的引用

从快照创建新卷:
快照 → clone → 新卷(Ceph 中是 COW clone,极快)

Ceph 快照链

1
2
3
4
5
6
7
8
9
# Ceph 中查看快照
rbd snap ls volumes/volume-xxx

# 快照链(clone 深度)
volumes/volume-xxx
└── @snap-yyy
└── volumes/volume-zzz (clone)
└── @snap-aaa
└── volumes/volume-bbb (clone)

注意:Ceph clone 深度过深会影响性能,rbd_max_clone_depth = 5 超过后会自动 flatten。


卷挂载流程

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
Nova 请求挂载卷


nova-compute 调用 os-brick 库


os-brick 根据连接类型选择 connector
├── iSCSI Connector → iscsiadm 登录 target
├── RBD Connector → 映射 rbd 设备
└── NFS Connector → mount NFS 路径


返回本地设备路径(/dev/sdb 或 /dev/rbd0)


libvirt 将设备 attach 到 VM(热插拔)

卷类型与 QoS

卷类型(Volume Type)

1
2
3
4
5
6
7
8
9
10
11
12
13
# 创建卷类型
openstack volume type create ssd-high-iops \
--property volume_backend_name=ceph-ssd \
--property replication_enabled=True

# 创建 QoS 规格
openstack volume qos create high-iops-qos \
--consumer front-end \
--property read_iops_sec=10000 \
--property write_iops_sec=5000

# 关联 QoS 到卷类型
openstack volume qos associate high-iops-qos ssd-high-iops

多后端调度

1
2
3
4
5
6
7
8
9
10
11
12
13
# cinder.conf
[DEFAULT]
enabled_backends = ceph-ssd,ceph-hdd,lvm-local

[ceph-ssd]
volume_driver = cinder.volume.drivers.rbd.RBDDriver
rbd_pool = ssd-volumes
volume_backend_name = ceph-ssd

[ceph-hdd]
volume_driver = cinder.volume.drivers.rbd.RBDDriver
rbd_pool = hdd-volumes
volume_backend_name = ceph-hdd

源码关键路径

1
2
3
4
5
6
7
8
9
10
11
12
cinder/
├── api/v3/ # REST API
├── volume/
│ ├── manager.py # cinder-volume 核心逻辑
│ ├── driver.py # 驱动基类
│ └── drivers/
│ ├── rbd.py # Ceph RBD 驱动
│ ├── lvm.py # LVM 驱动
│ └── nfs.py # NFS 驱动
├── scheduler/ # 后端选择调度器
├── backup/ # 备份服务
└── db/ # 数据库模型

生产运维要点

卷状态异常处理

1
2
3
4
5
6
7
8
# 卷卡在 attaching/detaching 状态
openstack volume set --state available <volume-id>

# 强制删除卡住的卷
openstack volume delete --force <volume-id>

# 重置卷状态
cinder reset-state --state error <volume-id>

容量监控

1
2
3
4
5
6
7
# 查看后端容量
cinder get-pools --detail

# Prometheus 指标
openstack_cinder_volume_gb_total
openstack_cinder_volume_gb_used
openstack_cinder_pool_capacity_gb_free