runsisi's

technical notes

RBD image 访问方式

2019-02-13 runsisi#ceph#rbd

RBD image 的 IO 访问有 rbd map,rbd nbd map,librbd API 等常见的三种方式,在某些场景下,可能这三种方式都不是很方便,比如前两种方式要求内核支持,而 API 访问很多时候显得不那么方便。

下面再提供两种RBD image 访问的方式,分别是 1)通过 rbd export 导出 RBD image 为普通文件,然后通过类似 losetup 的工具在本地 Linux 系统上生成块设备,以及 2)通过 rbd-fuse 直接以 fuse 读写文件的形式访问 RBD image。

rbd export

  1. 通过 rbd export 导出 RBD image 为 rbd.img
~# rbd export i1 rbd.img
Exporting image: 100% complete...done.
  1. 从 rbd.img 生成 /dev/ 下的 loop 设备
~# losetup -f rbd.img
  1. 查看生成的 loop 设备
~# losetup -a
  1. 通过 parted 查看生成的块设备是不是存在分区
~# parted /dev/loop0 print
  1. 如果存在分区,则加载分区设备
~# partprobe /dev/loop0
  1. lsblk 查看是否有 lvm 分区
~# lsblk
  1. 如果 loop 设备有 lvm 分区,则需要执行下面的命令扫描 vg
~# vgscan
  1. 如果 blkid 查看到 loop 设备的分区有 lvm 信息,但是 vgscan、pvscan 都搜索不到的话,需要检查 lvm 配置文件中是否有 filter 的定义,从而过滤掉了 loop 设备。可以使用 lvmconfig 快速查看 lvm 的配置,如果确实定义了 filter,则修改 /etc/lvm/lvm.conf 中 filter 的定义,或者直接注释掉其定义
  2. 然后使用 lvmdiskscan 扫描是否能够将 loop 设备扫描出来
~# lvmdiskscan
  1. 然后重新使用 pvscan/vgscan 扫描 lvm 信息,并使用,pvs/vgs/lvs 查看所有扫描到的 lvm 信息
~# vgs
  1. 激活扫描到的 vg vg1
~# vgchange -ay vg1
  1. 最后挂载 lv
~# mount /dev/mapper/vg1-lv1 /media/
  1. 当处理完之后,需要 deactivate vg vg1
~# vgchange -an vg1
  1. 然后删除 loop 设备
~# losetup -d /dev/loop0

通过上面的命令删除 loop 设备之后,可能不会删除 /dev 下的 loop 文件,不建议去手工删除,因为删除之后可能会出现后面再次进行 losetup 加载 loop 设备时报错,即使要删除也只删除类似 /dev/loop0p1 的分区设备,而不要删除类似 /dev/loop0 的原始 loop 设备。

如果已经删除了,且导致了 losetup -f 操作报错,可以重新加载 loop 驱动解决,即:

~# modprobe -r loop
~# modprobe loop

但这种方法可能只适用于 CentOS,因为 Ubuntu 内核中 loop 模块是直接编译进内核的,而不是以内核模块存在。而且如果当前还有其它 loop 设备在使用,我们并没有办法移除 loop 模块。

实际上 losetup -f 报错是因为我们删除了 /dev/loopx 块设备,因此我们可以通过重建这个被删除的 loop 设备来解决,比如假设我们之前删掉的是 /dev/loop0(删除 loop 分区设备不会导致 losetup -f 报错),那我们可以通过如下的 mknod 命令重建(注意块设备的 major、minor 号我是根据 /dev 目录下的其它 loop 设备推测的,测试了一下,好像这个 major 号必须是 7,minor 没要求,只要不和已存在的重复即可):

~# mknod -m 660 /dev/loop0 b 7 0

rbd-fuse

rbd-fuse 支持将 ceph 集群中的 image 通过 fuse 的方式进行访问,一般的使用方法如下。

  1. 假设当前集群中只有一个存储池 rbd,且存储池中的 image 如下
~# rbd ls
i1
test1
  1. 将存储池中所有的 image 以文件的形式在 linux 文件系统中导出,可以通过 -p 选项指定存储池,-r 选项指定 image,默认会导出 rbd 存储池中的所有 image
~# rbd-fuse /media
~# ls /media/
i1  test1
  1. 此时导出的 image 在 linux 文件系统中体现出来是一个普通文件,可以通过 losetup 在 /dev/ 下挂载成块设备再创建文件系统,也可以直接创建文件系统
~# mkfs.ext4 /media/i1
~# mount /media/i1 /mnt
  1. 查看系统的 mount 信息,可以看到 rbd-fuse 自身的挂载信息以及 image 的挂载信息
~# mount
...
rbd-fuse on /media type fuse.rbd-fuse (rw,nosuid,nodev,relatime,user_id=0,group_id=0)
/media/i1 on /mnt type ext4 (rw,relatime,data=ordered)
  1. 在挂载目录下 touch 文件会默认创建一个 1G 大小的 image
~# touch fuse
~# rbd info fuse
rbd image 'fuse':
        size 1024 MB in 256 objects
        order 22 (4096 kB objects)
        block_name_prefix: rbd_data.3b9b1140e0f76
        format: 2
        features: layering
        flags:
        create_timestamp: Wed Nov  8 09:07:38 2017
  1. 通过 truncate 可以创建指定大小的 image
~# truncate -s $((100 * 1024 * 1024 * 1024)) fuse
~# rbd info fuse
rbd image 'fuse':
        size 102400 MB in 25600 objects
        order 22 (4096 kB objects)
        block_name_prefix: rbd_data.3b9cf2d1d5ae9
        format: 2
        features: layering
        flags:
        create_timestamp: Wed Nov  8 09:21:21 2017
  1. 删除文件会删除对应的 image
~# rm -f fuse
~# rbd info fuse
rbd: error opening image fuse: (2) No such file or directory
  1. 最后可以 umount rbd-fuse 挂载的目录
~# umount /media

只是这个功能好像没有太大用处,因为前面介绍的 rbd export 方式也可以导出 image,然后在本地通过 losetup/kpartx 访问该块设备。