块设备 (block device) 是一系列的数据块序列。基于数据块的存储接口是最常用的用来存储 硬盘, CD, 软盘, 磁盘等数据的方式。正因为这种普适性,虚拟块设备成了与大容量数据存储系统交互的非常理想的选择。


目录

  1. 块设备概述
  2. 块设备基本命令
    1. 显示帮助
    2. 创建一个块设备池
    3. 创建块设备镜像
    4. 罗列块设备镜像
    5. 获取镜像信息
    6. 调整块设备镜像大小
    7. 移除块设备镜像
    8. 将镜像移到回收站
    9. 启用/禁用镜像特性
    10. 使用镜像元数据
  3. RBD 块设备镜像功能
  4. 内核模块操作
    1. 列出镜像
    2. 映射 RBD 到本地使用
    3. 显示已映射的设备
    4. 取消设备映射
  5. 使用 Python 处理 RBD
    1. 创建和写入镜像

块设备概述

Ceph 中的 块设备, 即可靠的、自治的、分布式的对象存储(RBDs) 块设备(RBDs), 是稀疏预分配的,可调大小的,将数据条状存储在 Ceph 存储集群上。 Ceph 块设备 使用了 RADOS 的一些功能:

  • 创建快照
  • 副本
  • 一致性
    Ceph 块设备使用 librbd 库与 OSDs 交互,其在 KVMs 如 QEMU, 和云计算系统如 OpenStack,CloudStack 等依赖于 libvirtQEMU 功能与之交互的应用中有很高的性能。

块设备基本命令

要使用块设备相关命令, 你需要能够访问正在运行的 Ceph 存储集群,并且安装了 Ceph Block 客户端。 rbd 命令能够创建、列出、自检、移除块设备,还可以对块设备进行克隆、建立快照、回滚快照、查看快照等。

显示帮助

因为 rbd 的命令和子命令非常多, 要记住所有的比较困难, 可以 通过 help 命令查寻相应命令的使用方法.

1
2
3
4
### Usage
[ceph@ceph0 ~]$ rbd help <command> [<subcommand>]
### e.g.
[ceph@ceph0 ~]$ rbd help snap llist

创建一个块设备池

在使用块设备客户端前, 必须有一个 rbd 类型的池存在并且被初始化了.创建一个 rbd Pool, 可以使用如下命令:

1
2
3
4
[ceph@ceph0 ~]$ ceph osd pool create {pool-name} {pg-num} {pgp-num}
### set rbd property for pool
[ceph@ceph0 ~]$ ceph osd pool application enable {pool-name} rbd
[ceph@ceph0 ~]$ rbd pool init -p {pool-name}

创建块设备镜像

使用如下命令 创建一个块设备镜像:

1
2
3
4
### Usage:
[ceph@ceph0 ~]$ rbd create --pool {pool-name} {image-name} --size {megabytes}
### e.g. create a rbd image named data of size 1GB stored in a pool named volumes
[ceph@ceph0 ~]$ rbd create -p volumes data --size 1024

创建的时候有一些选项:

  • --order n, 创建的RBD的条带大小为 2^n bytes, 如–order 24` 为 16M
  • --iamge-format, 默认格式是 1, 原始格式, 不支持 RBD 分层, format 2 支持 RBD 分层, 可以 COW, 可写快照。

罗列块设备镜像

要列出 Pool 内所有的镜像, 可用如下命令

1
2
3
4
### Usage: list rbd pool if pool name is absent
[ceph@ceph0 ~]$ rbd ls [{pool-name}]
### e.g. list images of pool volumes
[ceph@ceph0 ~]$ rbd ls volumes

获取镜像信息

列出 Pool 内的镜像后, 我们可能对某一个镜像感兴趣, 可通过如下命令获取其信息:

1
2
3
4
5
6
7
8
### Usage: image-name in rbd if pool-name is absent
[ceph@ceph0 ~]$ rbd [{pool-name}] info --image {image-name}
### e.g. retriving information of image data in pool rbd
[ceph@ceph0 ~]$ rbd info --image data
### e.g. retriving information of image data in pool volumes
[ceph@ceph0 ~]$ rbd info -p volumes --image data
### or simply
[ceph@ceph0 ~]$ rbd info volumes/data

调整块设备镜像大小

Ceph 的块设备镜像是稀疏分配的, 直到你开始往其中存入数据,它们才会使用物理空间. 它们有一个最大可用容量, 由 --size 选项指定, 但你可以通过 resize 命令来更改其大小.

1
2
3
4
### Usage: resize image-name in rbd pool if pool-name is absent
[ceph@ceph0 ~]$ rbd resize --image <image-name> --size <size> [--pool <pool-name>]
### e.g. cresize data in volumes pool from original to 60G
[ceph@ceph0 ~]$ rbd resize volumes/data --size 60G

rbd 大小一般只能扩大, 不能减小, 否则很可能会损坏数据. 若非要减小其大小, 可加上 --allow-shrink 选项

移除块设备镜像

当一个镜像完成了使命,我们便可以将其删除掉,

1
2
3
4
5
6
### Usage: remove image image-name in pool rbd if pool-name is absent
[ceph@ceph0 ~]$ rbd rm [--pool {pool-name}] rm {image-name}
### e.g. remove an image bar from pool volumes
[ceph@ceph0 ~]$ rbd rm volumes/bar
### or
[ceph@ceph0 ~]$ rbd rm -p volumes bar

将镜像移到回收站

相比于 rm 命令, 我们可以使用 trash 命令将镜像移到回收站里, 过后再将其删除, 防止意外删除镜像. trash 命令提供了比 rm更多的选项.

  1. 移动镜像到回收站

    1
    2
    3
    4
    ### Usage
    [ceph@ceph0 ~]$ rbd trash move [--pool {pool-name}] image-name
    ### e.g.
    [ceph@ceph0 ~]$ rbd trash move -p volumes data
  2. 从回收站彻底删除镜像. 利用镜像的 image-id:

    1
    2
    3
    4
    ### Usage
    [ceph@ceph0 ~]$ rbd trash remove [--pool {pool-name}] {image-id}
    ### e.g.
    [ceph@ceph0 ~]$ rbd trash remove volumes/data-image-id
  3. 延时回收镜像. 通过 --delay {time-in-second} 选项来指定一定时间内镜像不可从回收站删除.

    1
    2
    3
    4
    ### Usage
    [ceph@ceph0 ~]$ rbd trash move [--delay {time-in-second}] [--pool {pool-name}] {image-name}
    ### e.g.
    [ceph@ceph0 ~]$ rbd trash move --delay 360 -p volumes data
  4. 从回收站恢复镜像. 只要一个镜像还在回收站中未被删除, 且没有指定 --delay 选项, 就可以回收站中恢复.

    1
    2
    3
    4
    ### Usage
    [ceph@ceph0 ~]$ rbd trash restore [--pool {pool-name}/]{image-id}
    ### e.g.
    [ceph@ceph0 ~]$ rbd trash restore {pool-name}/data-image-id

启用/禁用镜像特性

我们可以启用或禁用镜像的某些特性, 比如 fast-diff, exclusive-lock, object-map 或者 journaling 等等.

  1. 启用特性

    1
    2
    3
    4
    ### Usage
    [ceph@ceph0 ~]$ rbd feature enable {pool-name}/{image-name} {feature-name}
    ### e.g. enable journaling on volumes/data
    [ceph@ceph0 ~]$ rbd feature enable volumes/data journaling
  2. 禁用特性

    1
    2
    3
    4
    ### Usage
    [ceph@ceph0 ~]$ rbd feature disable {pool-name}/{image-name} {feature-name}
    ### e.g. disable journaling on volumes/data
    [ceph@ceph0 ~]$ rbd feature disable volumes/data journaling
  3. 在启用 fast-diffobject-map 特性后, 要重新建立 object map:

    1
    [ceph@ceph0 ~]$ rbd object-map rebuild {pool-name}/{image-name}ss
  4. deep flatten 特性只能在 镜像建立时 启用, 不能在 已经建立而没有启用 的镜像上启用.

使用镜像元数据

Ceph 支持向镜像添加 key-value 对形式的元数据. key-value 对没有什么严格的形式. 使用 rbd image-meta 命令可以添加删除元数据.

  1. 设置镜像元数据

    1
    2
    3
    4
    ### Usage
    [ceph@ceph0 ~]$ rbd image-meta set {pool-name}/{image-name} {key} {value}
    ### e.g.
    [ceph@ceph0 ~]$ rbd image-meta set volumes/data last-update 2018-09-19:10:51
  2. 获取一个键的值

    1
    2
    3
    4
    ### Usage
    [ceph@ceph0 ~]$ rbd image-meta get {pool-name}/{image-name} <key>
    ### e.g.
    [ceph@ceph0 ~]$ rbd image-meta get volumes/data last-update
  3. 移除镜像元数据

    1
    2
    3
    4
    ### Usage
    [ceph@ceph0 ~]$ rbd image-meta remove {pool-name}/{image-name} {key}
    ### e.g.
    [ceph@ceph0 ~]$ rbd image-meta remove volumes/data last-update
  4. 列出镜像的元数据

    1
    2
    3
    4
    ### Usage
    [ceph@ceph0 ~]$ rbd image-meta list {pool-name}/{image-name}
    ### e.g.
    [ceph@ceph0 ~]$ rbd image-meta list volumes/data
  5. 重设镜像默认配置

    1
    2
    3
    4
    ### Usage
    [ceph@ceph0 ~]$ rbd image-meta set {pool-name}/{image-name} conf_{parameter} {value}
    ### e.g.
    [ceph@ceph0 ~]$ rbd image-meta set volumes/data conf_rbd_cache false

RBD 块设备镜像功能

RBD 的镜像功能是一种在两个及以上 Ceph 集群间异步副本功能。 镜像功能保证了对一个 iamge 做的更改在所有副本上保持时间点的一致性, 包括读写、块设备大小调整、快照、克隆和扁平化等等。 具体可参考 Ceph RBD 镜像功能与异地备份

内核模块操作

要使用 内核模块操作, 必须有一个正在运行的 Ceph 集群。

列出镜像

Ceph 块设备的一大应用就是可挂载到虚拟机,我们也可以挂载到本地使用。要挂载一个镜像,需要先知道镜像名字,先将所有镜像列出:

1
[ceph@ceph-client ~]$ rbd list

映射 RBD 到本地使用

需要指定 pool 名字, 镜像名字,用户名字, 若使用 CephX 进行认证,则还要加上相应的 密钥文件(keyring).

1
2
3
4
### Usage
[ceph@ceph-client ~]$ rbd map [--pool {pool-name}] image-name --id {user-name} [--keyring /path/to/keyring]
### e.g.
[ceph@ceph-client ~]$ rbd map volumes/data --id admin --keyring /etc/ceph/ceph.client.admin.keyring

显示已映射的设备

要显示已映射的设备,可以使用 rbdshowmapped 选项:

1
2
## Usage
[ceph@ceph-client ~]$ rbd showmapped

一般会映射到 /dev/rbd/xxx/xxx 之类的地方, 比如 /dev/rbd/rbd/rbd1, 然后就就像一般硬盘一样可以对其格式化,挂载使用

1
2
3
[ceph@ceph-client ~]$ sudo mkfs.ext4 /dev//dev/rbd/volumes/data
[ceph@ceph-client ~]$ sudo mount -t ext4 /dev/rbd/volumes/data /mnt/volumes/data
[ceph@ceph-client ~]$ df -Th

取消设备映射

1
2
3
4
## Usage
[ceph@ceph-client ~]$ rbd unmap /dev/rbd/{pool-name}/{image-name}
## e.g.
[ceph@ceph-client ~]$ rbd unmap /dev/rbd/volumes/data

使用 Python 处理 RBD

Python 中的 rbd 模块提供了像处理文件一样处理 RBD 镜像的功能, 核心接口由 librbd 提供。
使用这些功能之前,要先导入 radosrbd 模块

1
2
3
### in python
>>> import rados
>>> import rbd

创建和写入镜像

  1. 连接到 RADOS (Ceph 集群), 打开一个 IO 上下文 (IO context)

    1
    2
    3
    >>> cluster = rados.Rados(conffile = 'my_ceph.conf')
    >>> cluster.connect()
    >>> ioctx = cluster.open_ioctx('my_pool')
  2. 实例化一个 class:rbd.RBD 对象,可以用来创建镜像:

    1
    2
    3
    >>> rbd_inst = rbd.RBD()
    >>> size = 4*1024**3 # 4 GiB
    >>> rbd_inst.create(ioctx, 'my_image', size)
  3. 实例化一个 class:rbd.RBD 对象,对镜像进行读写:

    1
    2
    3
    >>> image = rbd.Image(ioctx, 'my_image')
    >>> data = 'foo' * 200
    >>> image.write(data, 0)
  4. 关闭镜像, I/O 上下文,和与 RADOS 的连接:

    1
    2
    3
    >>> image.close()
    >>> ioctx.close()
    >>> cluster.shutdown()
  5. 为了安全,可以使用 finally:with 语句:

    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
    ### with
    with rados.Rados(conffile='my_ceph.conf') as cluster:
    with cluster.open_ioctx('my_pool') as ioctx:
    rbd_inst = rbd.RBD()
    size = 4*1024**3 # 4 GiB
    rbd_inst.create(ioctx, 'my_image', size)
    with rbd.Image(ioctx, 'my_image') as image:
    data = 'foo' * 200
    image.write(data, 0)
    ### try and finally
    cluster = rados.Rados(conffile = 'my_ceph.conf')
    try:
    ioctx = cluster.open_ioctx('my_pool')
    try:
    rbd_inst = rbd.RBD()
    size = 4*1024**3 # 4 GiB
    rbd_inst.create(ioctx, 'my_image', size)
    image = rbd.Image(ioctx, 'my_iamge')
    try:
    data = 'foo' * 200
    image.write(data, 0)
    finally:
    image.close()
    finally:
    ioctx.close()
    finally:
    cluster.shutdown()