date: 2021-04-17title: ceph之RBD高级功能 #标题
tags: ceph #标签
categories: 存储 # 分类

记录下rbd所支持的高级功能,如回收站、快照、克隆、备份等。

RBD回收站机制

ceph是支持回收站机制的,这样可以在我们误删数据后,通过回收站进行数据恢复。

没有使用回收站机制时删除数据

  1. # 查看当前pool中的文件
  2. $ rbd -p ceph-demo-2 ls
  3. demo.img
  4. # 删除此文件
  5. $ rbd rm ceph-demo-2/demo.img
  6. Removing image: 100% complete...done.
  7. # 再次查看确认删除
  8. $ rbd -p ceph-demo-2 ls

使用回收站进行删除数据

  1. # 创建文件
  2. $ rbd create ceph-demo-2/demo.img --size 10G
  3. # 使用回收站机制删除文件
  4. $ rbd help trash move # 查看语法格式
  5. usage: rbd trash move [--pool <pool>] [--namespace <namespace>]
  6. [--image <image>] [--expires-at <expires-at>]
  7. <image-spec>
  8. Move an image to the trash.
  9. Positional arguments
  10. <image-spec> image specification
  11. (example: [<pool-name>/[<namespace>/]]<image-name>)
  12. Optional arguments
  13. -p [ --pool ] arg pool name
  14. --namespace arg namespace name
  15. --image arg image name
  16. --expires-at arg (=now) set the expiration time of an image so it can be
  17. purged when it is stale
  18. # 移动到回收站
  19. $ rbd trash move ceph-demo-2/demo.img --expires-at 20210413
  20. # --expires-at:指定在回收站中保留到哪天,只支持精准到日期
  21. # 确认已删除
  22. $ rbd -p ceph-demo-2 ls
  23. # 但在回收站中可以查看到
  24. $ rbd trash -p ceph-demo-2 ls
  25. 122074693c7cf demo.img
  26. # 当达到我们设置的日期后,会自动将其删除

恢复回收站数据

在上面将数据放到了回收站中,那怎么恢复呢?

# 恢复回收站数据到指定pool中
$ rbd trash restore -p ceph-demo-2 122074693c7cf

# 确认已恢复
$ rbd -p ceph-demo-2 ls                         
demo.img

# 此时回收站中就没有数据了
$ rbd trash -p ceph-demo-2 ls

RBD镜像制作快照

参考 官方文档

准备测试环境

# 创建块文件,需要增加 --image-feature layering 选项
$ rbd create ceph-demo-2/rbd-test.img --image-feature layering --size 10G

# 查看块信息
$ rbd info ceph-demo-2/rbd-test.img
rbd image 'rbd-test.img':
        size 10 GiB in 2560 objects
        order 22 (4 MiB objects)
        snapshot_count: 0
        id: 148e9c7ebb60
        block_name_prefix: rbd_data.148e9c7ebb60
        format: 2
        features: layering
        op_features: 
        flags: 
        create_timestamp: Tue Apr 13 07:02:47 2021
        access_timestamp: Tue Apr 13 07:02:47 2021
        modify_timestamp: Tue Apr 13 07:02:47 2021

# 挂载块文件使用
$ rbd device map ceph-demo-2/rbd-test.img
/dev/rbd0

# 格式化磁盘
$ mkfs.xfs /dev/rbd0

# 挂载使用
$ mount /dev/rbd0 /data

# 创建测试文件
$ echo 'test file' > /data/test.txt

# 手动刷盘
$ sync

制作快照

# 制作快照的命令格式
$ rbd snap create {pool-name}/{image-name}@{snap-name}

# 制作快照
$ rbd snap create ceph-demo-2/rbd-test.img@snap_20210413

查看快照列表

# 命令格式
$ rbd snap ls {pool-name}/{image-name}

# 查看快照列表
$ rbd snap ls ceph-demo-2/rbd-test.img
SNAPID NAME          SIZE   PROTECTED TIMESTAMP                
     4 snap_20210413 10 GiB           Tue Apr 13 07:10:44 2021

恢复快照数据

# 删除测试文件
$ rm -f /data/test.txt 

# 回滚快照命令格式如下
$ rbd snap rollback {pool-name}/{image-name}@{snap-name}

# 回滚
$ rbd snap rollback ceph-demo-2/rbd-test.img@snap_20210413

# 回滚后再次查看依旧是没数据,怎么回事呢
$ ls /data/

# 因为还需要将这个块设备卸载掉,重新挂载
>$ umount /data/
$ mount /dev/rbd0 /data/


# 再次查看,数据恢复
$ ls /data/
test.txt

删除快照

# 查看快照列表
$ rbd snap ls ceph-demo-2/rbd-test.img
SNAPID NAME          SIZE   PROTECTED TIMESTAMP                
     4 snap_20210413 10 GiB           Tue Apr 13 07:10:44 2021 

# 删除命令格式如下
rbd snap rm {pool-name}/{image-name}@{snap-name}

# 删除快照
$ rbd snap rm ceph-demo-2/rbd-test.img@snap_20210413
Removing snap: 100% complete...done.

# 再次查看,确认已删除
$ rbd snap ls ceph-demo-2/rbd-test.img

RBD镜像克隆机制

参考 官方文档

制作快照

$ rbd snap create ceph-demo-2/rbd-test.img@template

# 确认快照已存在
$ rbd snap ls ceph-demo-2/rbd-test.img             
SNAPID NAME     SIZE   PROTECTED TIMESTAMP                
     6 template 10 GiB           Tue Apr 13 07:41:18 2021 

# 将快照保护起来,避免被删除
$ rbd snap protect ceph-demo-2/rbd-test.img@template

# 确认无法删除快照
$ rbd snap rm ceph-demo-2/rbd-test.img@template     
Removing snap: 0% complete...failed.
rbd: snapshot 'template' is protected from removal.
2021-04-13 07:42:43.330 7f4107789c80 -1 librbd::Operations: snapshot is protected

克隆一个快照

# 克隆的命令格式
$ rbd clone {pool-name}/{parent-image}@{snap-name} {pool-name}/{child-image-name}

# 克隆快照(可以克隆到同一个pool中,也可以克隆到不同pool中)
$ rbd clone ceph-demo-2/rbd-test.img@template ceph-demo-2/vm_template.img

# 查看克隆的镜像文件
$ rbd -p ceph-demo-2 info vm_template-2.img
rbd image 'vm_template-2.img':
        size 10 GiB in 2560 objects
        order 22 (4 MiB objects)
        snapshot_count: 0
        id: 149ac75067fa8
        block_name_prefix: rbd_data.149ac75067fa8
        format: 2
        features: layering
        op_features: 
        flags: 
        create_timestamp: Tue Apr 13 07:46:13 2021
        access_timestamp: Tue Apr 13 07:46:13 2021
        modify_timestamp: Tue Apr 13 07:46:13 2021
        parent: ceph-demo-2/rbd-test.img@template        # 此镜像文件的父镜像是这个
        overlap: 10 GiB

注意:克隆出来的镜像依赖于父镜像,需要保证父镜像正常,子镜像才可以正常使用,这也是我们要将快照保护起来,避免误删除的原因。

挂载使用克隆的镜像

$ rbd device map ceph-demo-2/vm_template.img

# 挂载使用
$ mount /dev/rbd1 /mnt

注意:多个子镜像和父镜像同一时间只能有一个被挂载使用,如果同时挂载,会出现如下提示:

$ mount /dev/rbd2 /data1
mount: 文件系统类型错误、选项错误、/dev/rbd2 上有坏超级块、
       缺少代码页或助手程序,或其他错误

       有些情况下在 syslog 中可以找到一些有用信息- 请尝试
       dmesg | tail  这样的命令看看。

出现这种情况,是因为我们克隆出来的子镜像和父镜像的UUID是一样的,如下:

ceph之RBD高级功能 - 图1

修改磁盘UUID

解决办法1:mount禁用uuid(不建议)

# mount增加 -o nouuid 选项
$ mount -o nouuid /dev/rbd1 /data1

解决办法2:修改uuid

# xfs文件系统修改uuid
$ xfs_admin -U generate /dev/rbd1
Clearing log and setting UUID
writing all SBs
new UUID = 0ce5d1d8-5fa1-44c7-8213-47f352e00358


# ext2/3/4文件系统修改uuid
$ tune2fs /dev/rbd1 -U time

RBD解除依赖关系

查看父子镜像依赖关系

$ rbd children ceph-demo/rbd-test.img@template      
ceph-demo/vm01.img
ceph-demo/vm02.img
ceph-demo/vm03.img

可以看到template是有三个子镜像的,如果template这个父镜像坏掉的话,那么这三个子镜像也将无法使用,所以需要解除其依赖关系,使他们互不影响。

解除父子关系

$ rbd flatten ceph-demo/vm01.img
Image flatten: 100% complete...done.
$ rbd flatten ceph-demo/vm02.img
Image flatten: 100% complete...done.
$ rbd flatten ceph-demo/vm03.img
Image flatten: 100% complete...done.

确认已解除父子关系

# 已经没有了parent 这行
$ rbd info ceph-demo/vm01.img
rbd image 'vm01.img':
        size 10 GiB in 2560 objects
        order 22 (4 MiB objects)
        snapshot_count: 0
        id: fb04646a025d
        block_name_prefix: rbd_data.fb04646a025d
        format: 2
        features: layering
        op_features: 
        flags: 
        create_timestamp: Wed Apr 14 07:10:50 2021
        access_timestamp: Wed Apr 14 07:10:50 2021
        modify_timestamp: Wed Apr 14 07:10:50 2021

删除父镜像

# 确认父镜像下已没有子镜像
$ rbd children ceph-demo/rbd-test.img@template

# 删除父镜像
$ rbd snap unprotect ceph-demo/rbd-test.img@template   # 取消禁止删除的标志位
$ rbd snap rm ceph-demo/rbd-test.img@template        # 删除父镜像
Removing snap: 100% complete...done.

当父镜像删除后,可以自行测试下,子镜像是不收任何影响,可以正常使用的。

查看镜像文件和块设备的映射关系

$ rbd device ls
id pool      namespace image        snap device    
0  ceph-demo           rbd-test.img -    /dev/rbd0 
1  ceph-demo           vm01.img     -    /dev/rbd1 
2  ceph-demo           vm02.img     -    /dev/rbd2 
3  ceph-demo           vm03.img     -    /dev/rbd3

RBD备份与恢复

在上面介绍的RBD快照功能呢,也是对数据的一个备份手段,只是这种备份是在ceph集群内部的,一旦你的ceph集群出现故障,数据照样无法恢复,所以这里介绍下离线备份的方式,适用于数据跨集群迁移或者说防止cehp集群崩溃的场景。

备份

# 制作快照
$ rbd snap create ceph-demo/rbd-test.img@snap-demo

# 查看快照
$ rbd snap ls ceph-demo/rbd-test.img              
SNAPID NAME      SIZE   PROTECTED TIMESTAMP                
     7 snap-demo 10 GiB           Wed Apr 14 07:45:53 2021 

# 导出快照
# 命令格式如下
$ rbd help export
usage: rbd export [--pool <pool>] [--namespace <namespace>] [--image <image>] 
                  [--snap <snap>] [--path <path>] [--no-progress] 
                  [--export-format <export-format>] 
                  <source-image-or-snap-spec> <path-name> 

Export image to file.

Positional arguments
  <source-image-or-snap-spec>  source image or snapshot specification
                               (example:
                               [<pool-name>/[<namespace>/]]<image-name>[@<snap-n
                               ame>])
  <path-name>                  export file (or '-' for stdout)

Optional arguments
  -p [ --pool ] arg            source pool name
  --namespace arg              source namespace name
  --image arg                  source image name
  --snap arg                   source snapshot name
  --path arg                   export file (or '-' for stdout)
  --no-progress                disable progress output
  --export-format arg          format of image file



# 导出镜像
$ rbd export ceph-demo/rbd-test.img@snap-demo /root/rbd-test.img  
Exporting image: 100% complete...done.

# 查看导出的文件大小
$ du -sh /root/rbd-test.img 
88M     /root/rbd-test.img

恢复

当我们将备份文件导出后,可以导入到其他任意ceph集群中。命令格式如下:

$ rbd help import
usage: rbd import [--path <path>] [--dest-pool <dest-pool>] 
                  [--dest-namespace <dest-namespace>] [--dest <dest>] 
                  [--image-format <image-format>] [--new-format] 
                  [--order <order>] [--object-size <object-size>] 
                  [--image-feature <image-feature>] [--image-shared] 
                  [--stripe-unit <stripe-unit>] 
                  [--stripe-count <stripe-count>] [--data-pool <data-pool>] 
                  [--journal-splay-width <journal-splay-width>] 
                  [--journal-object-size <journal-object-size>] 
                  [--journal-pool <journal-pool>] 
                  [--sparse-size <sparse-size>] [--no-progress] 
                  [--export-format <export-format>] [--pool <pool>] 
                  [--image <image>] 
                  <path-name> <dest-image-spec> 

Import image from file.

Positional arguments
  <path-name>               import file (or '-' for stdin)
  <dest-image-spec>         destination image specification
                            (example: [<pool-name>/[<namespace>/]]<image-name>)

Optional arguments
  --path arg                import file (or '-' for stdin)
  --dest-pool arg           destination pool name
  --dest-namespace arg      destination namespace name
  --dest arg                destination image name
  --image-format arg        image format [1 (deprecated) or 2]
  --new-format              use image format 2
                            (deprecated)
  --order arg               object order [12 <= order <= 25]
  --object-size arg         object size in B/K/M [4K <= object size <= 32M]
  --image-feature arg       image features
                            [layering(+), exclusive-lock(+*), object-map(+*),
                            deep-flatten(+-), journaling(*)]
  --image-shared            shared image
  --stripe-unit arg         stripe unit in B/K/M
  --stripe-count arg        stripe count
  --data-pool arg           data pool
  --journal-splay-width arg number of active journal objects
  --journal-object-size arg size of journal objects [4K <= size <= 64M]
  --journal-pool arg        pool for journal objects
  --sparse-size arg         sparse size in B/K/M [default: 4K]
  --no-progress             disable progress output
  --export-format arg       format of image file
  -p [ --pool ] arg         pool name (deprecated)
  --image arg               image name (deprecated)

Image Features:
  (*) supports enabling/disabling on existing images
  (-) supports disabling-only on existing images
  (+) enabled by default for new images if features not specified

导人备份文件

# 导入到集群并命名为rbd-test-import.img
$ rbd import rbd-test.img ceph-demo/rbd-test-import.img
Importing image: 100% complete...done.

# 挂在块文件并查看(删除不支持的特性)
$ rbd feature disable ceph-demo/rbd-test-import.img deep-flatten fast-diff object-map exclusive-lock

# 映射为块设备
$ rbd device map ceph-demo/rbd-test-import.img


# 确认文件系统已存在
$ blkid

# 挂载后验证文件是否可以正常访问
$ mount /dev/rbd1 /media/
$ cat /media/a.txt

至此,我们已经实现了块文件的一个离线备份与恢复。但现在还有一个问题,就是按照上面的方式的话,是个完全备份,这样会出现很多不必要的冗余数据,所以ceph也支持增量备份与增量恢复。

增量备份与恢复

要验证增量备份的话,自行在块设备中新增文件,然后继续测试。

增量备份
# 块设备文件如下
$ ls
a.txt  b.txt

# 对块设备做快照
$ rbd snap create ceph-demo/rbd-test.img@testv1

# 将快照进行增量导出
$ rbd export-diff ceph-demo/rbd-test.img@testv1 rbd-test.img@testv1
Exporting image: 100% complete...done.


# 确认导出的备份文件大小
$ ll -h
# 第一次导出的备份
-rw-r--r--  1 root root  10G 4月  15 07:18 rbd-test.img
# 第二次导出的备份
-rw-r--r--  1 root root  11M 4月  15 07:45 rbd-test.img@testv1

增量恢复
# 现在将增量备份的文件恢复到ceph集群中
$ rbd import-diff rbd-test.img\@testv1 ceph-demo/rbd-test-import.img 
Importing image diff: 100% complete...done.

# 查看是否有新文件
$ ls /media/
a.txt

# 默认是没有的,需要重新挂载下