OpenStack:Glance共享与上传、Nova操作选项解释、Cinder操作技巧

2024-09-08 10:32

本文主要是介绍OpenStack:Glance共享与上传、Nova操作选项解释、Cinder操作技巧,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

目录

Glance

member

task

Nova

lock

shelve

rescue

Cinder

manage

local-attach

transfer

backup-export

总结


原作者:int32bit,参考内容

从2013年开始折腾OpenStack也有好几年的时间了。在使用过程中,我发现有很多很有用的操作,但是却很少被提及。这里我暂不直接列举我要介绍的内容,而是先抛出以下几个问题:

  • 如何把一个私有镜像共享给其它租户?
  • 上传一个很大的镜像老是超时怎么办,用户上传恶意镜像怎么办?
  • 如何阻止用户对虚拟机执行变更操作,保证虚拟机安全,防止误操作?
  • 虚拟机长时间不用却一直占用资源怎么办?
  • 虚拟机文件系统奔溃,如何进入rescue模式修复?
  • 如何把存储系统已经存在的volume导入到OpenStack中?
  • 能否把volume挂载到宿主机中?
  • 怎么把一个volume转交给另一个租户?
  • volume备份数据没有问题,但数据库记录丢失了怎么办?

接下来我们将针对以上提及的问题,介绍如何通过OpenStack已有的功能解决。

这些有趣的操作主要包括如下内容

Glance:glance member、glance task、

Nova:nova lock、nova shelve、nova rescue

Cinder:cinder manage、cinder local-attach、cinder backup-export、cinder transfer

Glance

member

镜像是OpenStack中非常重要的数据,保存了用户的操作系统数据,因此保证镜像的安全性非常重要。通常上传到Glance的镜像可以设置为public和private,public的镜像对所有的租户可见,而private镜像只有租户自己可见。在新版本的Glance中,引入了一种新的visibility状态shared,该状态的镜像允许共享给指定的租户。共享的目标租户我们称为member,我们只需要把租户加到镜像的member中就可以访问该镜像了。

首先我们在admin租户下创建一个镜像如下:

glance image-create --disk-format raw --container-format bare --name cirror-3.0 --file cirros-3.0.img

当前在demo租户下该镜像是不可见的:

$ source  openrc_demo
$ glance image-list
+----+------+
| ID | Name |
+----+------+
+----+------+

我们把demo加到镜像member中:

$ glance member-create ec5426f5-ab4d-43a6-a1e1-5a1919aa7bea fb498fdd27e74750a6b209158437696c
+--------------------------------------+----------------------------------+---------+
| Image ID                             | Member ID                        | Status  |
+--------------------------------------+----------------------------------+---------+
| ec5426f5-ab4d-43a6-a1e1-5a1919aa7bea | fb498fdd27e74750a6b209158437696c | pending |
+--------------------------------------+----------------------------------+---------+

admin这边把demo加入到member中,还需要demo这边确认,把member状态更新为accepted,表示接收共享镜像:

$ glance member-update ec5426f5-ab4d-43a6-a1e1-5a1919aa7bea fb498fdd27e74750a6b209158437696c accepted
+--------------------------------------+----------------------------------+----------+
| Image ID                             | Member ID                        | Status   |
+--------------------------------------+----------------------------------+----------+
| ec5426f5-ab4d-43a6-a1e1-5a1919aa7bea | fb498fdd27e74750a6b209158437696c | accepted |
+--------------------------------------+----------------------------------+----------+

此时在demo租户下可以看到共享的镜像了:

$ glance image-list
+--------------------------------------+------------+
| ID                                   | Name       |
+--------------------------------------+------------+
| ec5426f5-ab4d-43a6-a1e1-5a1919aa7bea | cirror-3.0 |
+--------------------------------------+------------+

task

通常我们通过glance image-create上传镜像,这至少存在以下两个问题:

  • 镜像没有校验,你可以随便上传一个图片啥的,或者上传一个恶意文件,你甚至可以把Glance当作对象存储使用。

  • 镜像通常很大,上传占资源多并且慢,上传大镜像经常会由于上传超时而导致失败。

因此Glance从V2版本开始提出了task的概念,task可以定义上传镜像的任务流程,然后Glance会异步去执行并反馈最终结果,关于Glance task介绍可以参考Get started with tasks api in glance.

首先定义task,json文件如下:

{"input": {"image_properties": {"disk_format": "raw","container_format": "bare","name": "cirros-0.3.5-x86_64"},"import_from": "http://download.cirros-cloud.net/0.3.5/cirros-0.3.5-x86_64-disk.img","import_from_format": "raw"},"type": "import"
}

创建task:

$ glance task-create --type import --input "$(cat import_image.json | jq '.input')"
+------------+----------------------------------------------------------------------------------+
| Property   | Value                                                                            |
+------------+----------------------------------------------------------------------------------+
| created_at | 2017-09-28T08:03:47Z                                                             |
| id         | 564b5ee4-56db-4360-bb71-d1d1c4d896a2                                             |
| input      | {"image_properties": {"container_format": "bare", "name":                        |
|            | "cirros-0.3.5-x86_64"}, "import_from_format": "raw", "import_from":              |
|            | "http://download.cirros-cloud.net/0.3.5/cirros-0.3.5-x86_64-disk.img"}           |
| message    |                                                                                  |
| owner      | ae21d957967d4df0865411f0389ed7e8                                                 |
| result     | None                                                                             |
| status     | pending                                                                          |
| type       | import                                                                           |
| updated_at | 2017-09-28T08:03:47Z                                                             |
+------------+----------------------------------------------------------------------------------+

查看task:

$ glance task-list
+--------------------------------------+--------+------------+----------------------------------+
| ID                                   | Type   | Status     | Owner                            |
+--------------------------------------+--------+------------+----------------------------------+
| 564b5ee4-56db-4360-bb71-d1d1c4d896a2 | import | processing | ae21d957967d4df0865411f0389ed7e8 |
+--------------------------------------+--------+------------+----------------------------------+

此时glance会异步地下载镜像,完成后状态变成success:

$ glance task-show 564b5ee4-56db-4360-bb71-d1d1c4d896a2
+------------+----------------------------------------------------------------------------------+
| Property   | Value                                                                            |
+------------+----------------------------------------------------------------------------------+
| created_at | 2017-09-28T09:32:10Z                                                             |
| expires_at | 2017-09-30T09:33:54Z                                                             |
| id         | 564b5ee4-56db-4360-bb71-d1d1c4d896a2                                             |
| input      | {"image_properties": {"container_format": "bare", "disk_format": "raw", "name":  |
|            | "cirros-0.3.5-x86_64"}, "import_from_format": "raw", "import_from":              |
|            | "http://download.cirros-cloud.net/0.3.5/cirros-0.3.5-x86_64-disk.img"}           |
| message    |                                                                                  |
| owner      | ae21d957967d4df0865411f0389ed7e8                                                 |
| result     | {"image_id": "e5f8a941-f14f-4065-b381-b537271eba4c"}                             |
| status     | success                                                                          |
| type       | import                                                                           |
| updated_at | 2017-09-28T09:33:54Z                                                             |
+------------+----------------------------------------------------------------------------------+

result中保存了image的id。

该设计初衷是好的,不过从Mitaka版本开始,task API废弃了,社区准备重构import image流程,参考image import refactor。

Nova

lock

这个功能比较好理解,就是对虚拟机进行锁定,被锁定的虚拟机除了管理员的其他任何用户不能对虚拟机执行任何变更操作。管理员通过该操作可以保证虚拟机的安全性,有效阻止普通用户对虚拟机执行非计划的删除、关机重启等高危操作。

但是需要注意的是,lock只作用于普通用户,管理员是无视lock的。

我们创建一台虚拟机:

nova boot --image f0b1239a-bb34-4cfb-ad06-e18cbb8ee4b9 --flavor m1.small --nic net-id=9f3aad86-f3c1-499b-ba62-5708dd229466 int32bit-test-lock

使用管理员账号对虚拟机进行lock操作:

nova lock d7873036-15b0-4a06-9507-999dbf097c62

我们使用普通用户对虚拟机分别执行重启、删除操作:

$ source openrc_demo
$ nova reboot d7873036-15b0-4a06-9507-999dbf097c62
Instance d7873036-15b0-4a06-9507-999dbf097c62 is locked (HTTP 409) (Request-ID: req-60271d7d-9afd-4ff4-a150-dfb632d5007f)
ERROR (CommandError): Unable to reboot the specified server(s).
$ nova delete d7873036-15b0-4a06-9507-999dbf097c62
Instance d7873036-15b0-4a06-9507-999dbf097c62 is locked (HTTP 409) (Request-ID: req-3e63515b-6e2e-419a-8c91-b27b1a546f12)
ERROR (CommandError): Unable to delete the specified server(s).

从以上输出可见这两个操作都失败了,符合我们的预期。

另外需要强调的是,其实普通用户也是可以对虚拟机执行lock操作的,不过普通用户加的lock,其他任意用户都可以执行unlock。而默认policy下,只有管理员添加的lock,才能阻止普通用户执行unlock:

$ nova unlock d7873036-15b0-4a06-9507-999dbf097c62
ERROR (Forbidden): Policy doesn't allow os_compute_api:os-lock-server:unlock:unlock_override to be performed. (HTTP 403) (Request-ID: req-9fabda60-4857-429e-ab1d-6ca6fb36844e)

shelve

对于一些长期不用的虚拟机,即使关机了,仍然占用着集群资源,或者在公有云上用户欠费时间很长,又没有及时主动删掉虚拟机,导致一直占据着资源。此时我们可以通过shelve(搁置)操作临时释放资源。

shelve操作的原理分为两种情况:

  • 如果虚拟机是从Glance image创建的(boot from image),则先给虚拟机创建一个快照并上传到glance中,然后把虚拟机从OpenStack中删掉,释放所有资源。
  • 如果虚拟机是从Cinder volume中创建的(boot from volume),则直接删除虚拟机,但不会从Cinder中删除根磁盘。

我们假定虚拟机是从Glance镜像中创建的,通过shelve子命令对虚拟机执行搁置操作:

nova shelve 5b540e93-e931-45ed-a7f3-1dc2e88d8d33

shelve完成后我们查看虚拟机是否彻底从libvirt底层删除:

$ nova list --fields id,name,status,instance_name
+--------------------------------------+--------------------------------------+----------------------+-------------------+-------------------+
| ID                                   | Id                                   | Name                 | Status            | Instance Name     |
+--------------------------------------+--------------------------------------+----------------------+-------------------+-------------------+
| 5b540e93-e931-45ed-a7f3-1dc2e88d8d33 | 5b540e93-e931-45ed-a7f3-1dc2e88d8d33 | int32ibt-test-shelve | SHELVED_OFFLOADED | instance-0000033b |
+--------------------------------------+--------------------------------------+----------------------+-------------------+-------------------+
$ virsh list --all | grep instance-0000033b

可见instance-0000033b已经删除了。

使用glance可以查看刚刚创建的虚拟机快照:

$ glance image-list | grep shelved
| 36d7d6a0-aa18-4373-ad79-afcae8609489 | int32ibt-test-shelve-shelved|

删除的虚拟机可以通过unshelve操作恢复虚拟机,该操作基于快照重新启动(rebuild)虚拟机,并把快照从Glance中删掉。

$ nova unshelve 5b540e93-e931-45ed-a7f3-1dc2e88d8d33
$ nova list
+--------------------------------------+----------------------+--------+------------+-------------+---------------------+
| ID                                   | Name                 | Status | Task State | Power State | Networks            |
+--------------------------------------+----------------------+--------+------------+-------------+---------------------+
| 5b540e93-e931-45ed-a7f3-1dc2e88d8d33 | int32ibt-test-shelve | ACTIVE | -          | Running     | test-net=10.0.51.22 |
+--------------------------------------+----------------------+--------+------------+-------------+---------------------+

rescue

我们经常在文件系统奔溃时,进入rescue模式修复,或者通过Live CD进入一个临时操作系统来修复奔溃的文件系统。

假如我们使用OpenStack启动的虚拟机出现问题导致启动不起来了,该怎么处理呢。

当然你可以把虚拟机的根磁盘挂载到本地(如果使用的是ceph,则直接通过rbd map),然后在宿主机中修复。但是作为云提供商,显然不可能这么做,否则用户的数据太不安全了。我们需要用户自己去修复。

Nova提供了rescue API,其实现原理和我们前面提到的方式基本一样,先来看看rescue子命令用法:

nova rescue [--password <password>] [--image <image>] <server>

rescue会使用指定的image重新创建一个虚拟机,同时把原来的虚拟机根磁盘作为附加磁盘挂载到新创建的虚拟机,它会重用原来虚拟机的所有信息,如flavor、network等。

注意:通过rescue新创建的虚拟机不支持指定keypair。另外其实rebuild也不支持指定keypair,在前几天的邮件列表中看到有讨论这个问题,估计在Q版本中会实现。

我们试验下:

$ nova rescue  --image f0b1239a-bb34-4cfb-ad06-e18cbb8ee4b9 5b540e93-e931-45ed-a7f3-1dc2e88d8d33
+-----------+--------------+
| Property  | Value        |
+-----------+--------------+
| adminPass | 4mDD7BGsfvMN |
+-----------+--------------+
$ nova list
+--------------------------------------+------+--------+------------+-------------+---------------------+
| ID                                   | Name | Status | Task State | Power State | Networks            |
+--------------------------------------+------+--------+------------+-------------+---------------------+
| 5b540e93-e931-45ed-a7f3-1dc2e88d8d33 | 2    | ACTIVE | rescuing   | Running     | test-net=10.0.51.22 |
+--------------------------------------+------+--------+------------+-------------+---------------------+

当虚拟机rebuild完成后,查看其状态:

$ nova list
+--------------------------------------+------+--------+------------+-------------+---------------------+
| ID                                   | Name | Status | Task State | Power State | Networks            |
+--------------------------------------+------+--------+------------+-------------+---------------------+
| 5b540e93-e931-45ed-a7f3-1dc2e88d8d33 | 2    | RESCUE | -          | Running     | test-net=10.0.51.22 |
+--------------------------------------+------+--------+------------+-------------+---------------------+

虚拟机状态变为RESCUE。

查看虚拟机挂载的block设备如下:

$ virsh domblklist 5b540e93-e931-45ed-a7f3-1dc2e88d8d33
Target     Source
------------------------------------------------
vda        /var/lib/nova/instances/5b540e93-e931-45ed-a7f3-1dc2e88d8d33/disk.rescue
vdb        /var/lib/nova/instances/5b540e93-e931-45ed-a7f3-1dc2e88d8d33/disk

其中disk.rescue是新创建虚拟机的临时根磁盘,disk是原来虚拟机的根磁盘。此时进入新创建的虚拟机,就可以对原来虚拟机的根磁盘进行操作了。

操作完成后,通过unrescue子命令恢复:

nova unrescue 5b540e93-e931-45ed-a7f3-1dc2e88d8d33

unrescue会再次rebuild虚拟机,并重新使用之前的根磁盘作为根磁盘,删除前面创建的临时根磁盘。

Cinder

manage

Cinder创建一个volume时,通常会由后端存储系统负责创建一个volume,并与Cinder volume一一映射。

如果我们存储系统中已经有一些volume了,比如Ceph中已有的一些rbd image,如何让Cinder纳管起来呢?可幸的是,Cinder支持导入OpenStack外部存储数据卷,这个操作称为manage。接下来我们演示下这个过程。

假设我们使用的是LVM后端driver,首先我们创建一个LV:

$ lvcreate --name int32bit-test-LV --size 1G cinder-volumesLogical volume "int32bit-test-LV" created.
$ lvs | grep int32bit
int32bit-test-LV                               cinder-volumes -wi-a-----  1.00g

使用manage子命令纳管刚刚创建的LV:

$ cinder manage --name int32bit-test-manage 'devstack@lvm#cinder-volumes' int32bit-test-LV
+--------------------------------+--------------------------------------+
|            Property            |                Value                 |
+--------------------------------+--------------------------------------+
|          attachments           |                  []                  |
|       availability_zone        |                 nova                 |
|            bootable            |                false                 |
|      consistencygroup_id       |                 None                 |
|           created_at           |      2017-09-28T03:09:55.000000      |
|          description           |                 None                 |
|           encrypted            |                False                 |
|               id               | 9394b827-4ad0-488e-8df8-26476b3a8662 |
|            metadata            |                  {}                  |
|        migration_status        |                 None                 |
|          multiattach           |                False                 |
|              name              |      int32bit-test-manage            |
|     os-vol-host-attr:host      |     devstack@lvm#cinder-volumes      |
| os-vol-mig-status-attr:migstat |                 None                 |
| os-vol-mig-status-attr:name_id |                 None                 |
|  os-vol-tenant-attr:tenant_id  |   42ee53fa480f49149ce5c3df4a953a6b   |
|       replication_status       |                 None                 |
|              size              |                  0                   |
|          snapshot_id           |                 None                 |
|          source_volid          |                 None                 |
|             status             |               creating               |
|           updated_at           |                 None                 |
|            user_id             |   a61a3c0659bd4cca8cb5f66ea2fe3df7   |
|          volume_type           |                 None                 |
+--------------------------------+--------------------------------------+

以上两个参数,其中第一个参数是host,注意Cinder的host格式为hostname@backend#pool,如果不清楚,使用admin账号show其中一个volume,查看其os-vol-host-attr:host。另一个参数为identifier,即后端存储数据卷名,对应LVM即LV name,对应Ceph rbd则为image name。

当volume状态变为available时,说明创建volume成功,并成功导入了指定的LV。

我们使用lvs查看我们创建的LV是否还存在:

$ lvs | grep int32bit

我们发现创建的int32bit-test-LV不存在了,查看实现源码如下:

def manage_existing(self, volume, existing_ref):lv_name = existing_ref['source-name']self.vg.get_volume(lv_name)if volutils.check_already_managed_volume(self.db, lv_name):raise exception.ManageExistingAlreadyManaged(volume_ref=lv_name)# Attempt to rename the LV to match the OpenStack internal name.try:self.vg.rename_volume(lv_name, volume['name'])except processutils.ProcessExecutionError as exc:exception_message = (_("Failed to rename logical volume %(name)s, ""error message was: %(err_msg)s")% {'name': lv_name,'err_msg': exc.stderr})raise exception.VolumeBackendAPIException(data=exception_message)

从源码中发现,Cinder会自动把LV重命名,与Cinder volume对应起来。由此可见manage和create唯一不同的是:

  • create会调用后端driver创建一个volume。
  • manage则会调用后端driver重命名一个volume。

当然,也有一个相反的操作,即unmanage,这个和delete操作基本一样,唯一不同的是,delete会调用后端存储把数据卷从底层彻底删除,而unmanage只是删除volume数据库记录,并不会删除后端存储的数据卷。

不过Cinder目前还不支持从本地文件系统中导入volume以及把volume导出到本地文件系统中,其实当初manage功能就是为了实现前面的import/export volume blue-print的,参考add export import volume.

local-attach

Cinder作为OpenStack的块存储服务,最典型的应用是挂载到OpenStack虚拟机中,当作虚拟硬盘使用。但volume能不能挂载到物理机呢,或者说挂载到宿主机呢?答案是可以!我们把volume挂载到本地,称为local attach。

不过默认的cinderclient没有local attach命令,我们需要安装cinderclient扩展包:

pip install python-brick-cinderclient-ext

安装完后,可以发现cinder CLI多了两个子命令:

$ cinder --help | grep local
local-attach
local-detach

下面演示如何把一个volume挂载到本地:

首先创建一个volume:

$ cinder create --volume-type lvm --name int32bit-test-local-attach 1
+--------------------------------+--------------------------------------+
| Property                       | Value                                |
+--------------------------------+--------------------------------------+
| attached_servers               | []                                   |
| attachment_ids                 | []                                   |
| availability_zone              | nova                                 |
| bootable                       | false                                |
| consistencygroup_id            | None                                 |
| created_at                     | 2017-09-28T02:50:16.000000           |
| description                    | None                                 |
| encrypted                      | False                                |
| id                             | af767c74-1902-4a7a-8fff-4ea68695a3f8 |
| metadata                       | {}                                   |
| migration_status               | None                                 |
| multiattach                    | False                                |
| name                           | int32bit-test-local-attach           |
| os-vol-host-attr:host          | None                                 |
| os-vol-mig-status-attr:migstat | None                                 |
| os-vol-mig-status-attr:name_id | None                                 |
| os-vol-tenant-attr:tenant_id   | ae21d957967d4df0865411f0389ed7e8     |
| replication_status             | None                                 |
| size                           | 1                                    |
| snapshot_id                    | None                                 |
| source_volid                   | None                                 |
| status                         | creating                             |
| updated_at                     | None                                 |
| user_id                        | 70828c56f2844a9090d286c29a1fb599     |
| volume_type                    | lvm                                  |
+--------------------------------+--------------------------------------+

等待volume状态为available后,我们使用local-attach子命令挂载到本地:

$ cinder local-attach af767c74-1902-4a7a-8fff-4ea68695a3f8
+----------+-----------------------------------+
| Property | Value                             |
+----------+-----------------------------------+
| path     | /dev/sdb                          |
| scsi_wwn | 360000000000000000e00000000010001 |
| type     | block                             |
+----------+-----------------------------------+

以上输出结果表明成功挂载volume到本地中,并映射为/dev/sdb。

我们安装文件系统并mount到本地:

$ mkfs.ext4 /dev/sdb
mke2fs 1.42.13 (17-May-2015)
Creating filesystem with 262144 4k blocks and 65536 inodes
Filesystem UUID: 2a3fdcac-3a68-494a-830d-2bbebddaa875
Superblock backups stored on blocks:32768, 98304, 163840, 229376Allocating group tables: done
Writing inode tables: done
Creating journal (8192 blocks): done
Writing superblocks and filesystem accounting information: done$ mount /dev/sdb /mnt
$ ls /mnt
lost+found

此时我们可以把volume当作本地的一个硬盘使用了。可以使用local-detach子命令从本地中卸载volume。

transfer

我们知道Glance支持通过member把一个镜像分享给其它租户,自然想到的是,Cinder能不能把其中一个volume分享给其它租户呢?很遗憾,Cinder没有member的概念,即不支持通过member把一个volume共享给其它租户。

不过Cinder支持把一个volume的所有权转移给另一个租户(过户),这种行为称为transfer。

首先我们在admin租户下创建一个volume:

cinder create --name int32bit-test-transfer 1

此时我们在demo的租户下看不到刚刚创建的volume:

$ source  openrc_demo
$ cinder list
+----+--------+------+------+-------------+----------+-------------+
| ID | Status | Name | Size | Volume Type | Bootable | Attached to |
+----+--------+------+------+-------------+----------+-------------+
+----+--------+------+------+-------------+----------+-------------+

在admin租户下创建一个transfer:

$ cinder transfer-create --name test-transfer int32bit-test-transfer
+------------+--------------------------------------+
| Property   | Value                                |
+------------+--------------------------------------+
| auth_key   | c259b651426121fd                     |
| created_at | 2017-09-28T05:25:20.105051           |
| id         | b03c0b07-1e1c-4df3-b096-be3c66b433f7 |
| name       | test-transfer                        |
| volume_id  | 093f41b1-39f9-4a01-bfb8-116baf1dbe2f |
+------------+--------------------------------------+

以上输出的auth_key非常重要,并且只有创建的时候会输出,之后通过API就拿不到这个auth_key了。对方就是通过这个auth_key接收转移的。此时volume的状态将变为awaiting-transfer

在demo租户下accept:

$ cinder transfer-accept b03c0b07-1e1c-4df3-b096-be3c66b433f7 c259b651426121fd
+-----------+--------------------------------------+
| Property  | Value                                |
+-----------+--------------------------------------+
| id        | b03c0b07-1e1c-4df3-b096-be3c66b433f7 |
| name      | test-transfer                        |
| volume_id | 093f41b1-39f9-4a01-bfb8-116baf1dbe2f |
+-----------+--------------------------------------+

其中第一个参数为transfer id,第二个参数为auth_key。

我们在demo上查看volume:

$ cinder list
+--------------------------------------+-----------+------------------------+------+-------------+----------+-------------+
| ID                                   | Status    | Name                   | Size | Volume Type | Bootable | Attached to |
+--------------------------------------+-----------+------------------------+------+-------------+----------+-------------+
| 093f41b1-39f9-4a01-bfb8-116baf1dbe2f | available | int32bit-test-transfer | 1    | lvmdriver-1 | false    |             |
+--------------------------------------+-----------+------------------------+------+-------------+----------+-------------+

可见该volume已经成功转接给demo租户。

需要注意的是,任何人拿到transfer_id和auth_key都可以接收转接的volume,因此注意auth_key保密。auth_key只能使用一次,完成交接后,对应的transfer实例将自动删除。

backup-export

Cinder backup可以把Cinder volume备份到远端的存储系统中,如Ceph、Swift等。但是backup的元数据怎么办呢,万一数据库记录丢失了,数据还是恢复不了。

有人可能会说,备份的时候不是会保存backup的元数据吗,为什么不用backup的元数据呢。这是因为并不是所有的备份都会在远端保存元数据,比如若cinder-volume和备份存储后端都是使用Ceph driver,则备份时直接使用rbd的import,不需要元数据,因此在备份的ceph中也不会保存元数据。

幸运的是,Cinder支持backup export,把metadata导出。

$ cinder --debug backup-export fcbbfcca-b83e-4fab-acb6-7dbbd017b151
{"backup-record": {"backup_service": "cinder.backup.drivers.swift","backup_url": "eyJzdGF0dXM...efQ=="}
}

以上eyJzdGF0dXM...efQ==字符串很长,为了便于排版,省略了中间一大部分。输出的backup_url是一串字符串什么用途呢,我们查看源码:

def export_record(self, context, backup):
# ...
# Call driver to create backup description string
try:backup_service = self.service.get_backup_driver(context)driver_info = backup_service.export_record(backup)backup_url = backup.encode_record(driver_info=driver_info)backup_record['backup_url'] = backup_url
except Exception as err:msg = six.text_type(err)raise exception.InvalidBackup(reason=msg)

我们从源码中发现export_record就是通过backup实例调用encode_record完成的,encode_record的作用很明显就是序列化过程,我们查看其源码:

@base.remotable
def encode_record(self, **kwargs):"""Serialize backup object, with optional extra info, into a string."""# We don't want to export extra fields and we want to force lazy# loading, so we can't use dict(self) or self.obj_to_primitiverecord = {name: field.to_primitive(self, name, getattr(self, name))for name, field in self.fields.items()}# We must update kwargs instead of record to ensure we don't overwrite# "real" data from the backupkwargs.update(record)retval = jsonutils.dump_as_bytes(kwargs)return base64.encode_as_text(retval)

从源码中可以看出,首先把backup序列化为json格式,然后转化为base64,我可以验证下:

Python 2.7.5 (default, Nov  6 2016, 00:28:07)
[GCC 4.8.5 20150623 (Red Hat 4.8.5-11)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import base64
>>> base64.b64decode('eyJzdGF0dXM...fQ==')
'{"status": "available", "temp_snapshot_id": null, "display_name": "2", "availability_zone": "nova", "deleted": false, "volume_id": "676ec7a5-d4ae-43d9-88cd-bd93dc143538", "restore_volume_id": null, "updated_at": "2017-08-30T05:56:47Z", "host": "devstack", "snapshot_id": null, "user_id": "a61a3c0659bd4cca8cb5f66ea2fe3df7", "service_metadata": "volume_676ec7a5-d4ae-43d9-88cd-bd93dc143538/20170830055626/az_nova_backup_fcbbfcca-b83e-4fab-acb6-7dbbd017b151", "id": "fcbbfcca-b83e-4fab-acb6-7dbbd017b151", "size": 1, "object_count": 22, "deleted_at": null, "container": "cinder-backup", "service": "cinder.backup.drivers.swift", "driver_info": {}, "created_at": "2017-08-30T05:56:23Z", "disk_size": 3444122, "display_description": "", "data_timestamp": "2017-08-30T05:56:23Z", "parent_id": null, "num_dependent_backups": 0, "fail_reason": null, "project_id": "42ee53fa480f49149ce5c3df4a953a6b", "temp_volume_id": null}'

下面我们从数据库中删除该backup记录:

MariaDB [cinder]> delete from backups where id='fcbbfcca-b83e-4fab-acb6-7dbbd017b151';
Query OK, 1 row affected (0.00 sec)

此时Cinder已经找不到该backup记录了:

$ cinder backup-show fcbbfcca-b83e-4fab-acb6-7dbbd017b151
ERROR: No volumebackup with a name or ID of 'fcbbfcca-b83e-4fab-acb6-7dbbd017b151' exists.

接下来我们使用backup-import恢复记录:

$ cinder backup-import cinder.backup.drivers.swift eyJzdGF0dXM...efQ==
+------------+--------------------------------------+
|  Property  |                Value                 |
+------------+--------------------------------------+
|     id     | fcbbfcca-b83e-4fab-acb6-7dbbd017b151 |
|    name    |                 None                 |
| parent_id  |                 None                 |
| project_id |   42ee53fa480f49149ce5c3df4a953a6b   |
+------------+--------------------------------------+

backup记录成功恢复:

$ cinder backup-show fcbbfcca-b83e-4fab-acb6-7dbbd017b151
+-----------------------+--------------------------------------+
|        Property       |                Value                 |
+-----------------------+--------------------------------------+
|   availability_zone   |                 nova                 |
|       container       |            cinder-backup             |
|       created_at      |      2017-08-30T05:56:23.000000      |
|     data_timestamp    |      2017-08-30T05:56:23.000000      |
|      description      |                                      |
|       disk_size       |               3444122                |
|      fail_reason      |                                      |
| has_dependent_backups |                False                 |
|           id          | fcbbfcca-b83e-4fab-acb6-7dbbd017b151 |
|     is_incremental    |                False                 |
|          name         |                  2                   |
|      object_count     |                  22                  |
|       parent_id       |                 None                 |
|       project_id      |   42ee53fa480f49149ce5c3df4a953a6b   |
|          size         |                  1                   |
|      snapshot_id      |                 None                 |
|         status        |              available               |
|       updated_at      |      2017-08-30T05:56:47.000000      |
|       volume_id       | 676ec7a5-d4ae-43d9-88cd-bd93dc143538 |
+-----------------------+--------------------------------------+

总结

以上我们介绍了OpenStack的一些非常有用的操作,主要包括如下:

Glance:glance member、glance task、

Nova:nova lock、nova shelve、nova rescue

Cinder:cinder manage、cinder local-attach、cinder backup-export、cinder transfer

以后发现有新的有意思的操作,再补充。

END

OpenStack虚拟机实例各种状态之间的转换关系

这篇关于OpenStack:Glance共享与上传、Nova操作选项解释、Cinder操作技巧的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1147858

相关文章

Linux使用fdisk进行磁盘的相关操作

《Linux使用fdisk进行磁盘的相关操作》fdisk命令是Linux中用于管理磁盘分区的强大文本实用程序,这篇文章主要为大家详细介绍了如何使用fdisk进行磁盘的相关操作,需要的可以了解下... 目录简介基本语法示例用法列出所有分区查看指定磁盘的区分管理指定的磁盘进入交互式模式创建一个新的分区删除一个存

Golang操作DuckDB实战案例分享

《Golang操作DuckDB实战案例分享》DuckDB是一个嵌入式SQL数据库引擎,它与众所周知的SQLite非常相似,但它是为olap风格的工作负载设计的,DuckDB支持各种数据类型和SQL特性... 目录DuckDB的主要优点环境准备初始化表和数据查询单行或多行错误处理和事务完整代码最后总结Duck

NFS实现多服务器文件的共享的方法步骤

《NFS实现多服务器文件的共享的方法步骤》NFS允许网络中的计算机之间共享资源,客户端可以透明地读写远端NFS服务器上的文件,本文就来介绍一下NFS实现多服务器文件的共享的方法步骤,感兴趣的可以了解一... 目录一、简介二、部署1、准备1、服务端和客户端:安装nfs-utils2、服务端:创建共享目录3、服

C# 读写ini文件操作实现

《C#读写ini文件操作实现》本文主要介绍了C#读写ini文件操作实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧... 目录一、INI文件结构二、读取INI文件中的数据在C#应用程序中,常将INI文件作为配置文件,用于存储应用程序的

Python使用qrcode库实现生成二维码的操作指南

《Python使用qrcode库实现生成二维码的操作指南》二维码是一种广泛使用的二维条码,因其高效的数据存储能力和易于扫描的特点,广泛应用于支付、身份验证、营销推广等领域,Pythonqrcode库是... 目录一、安装 python qrcode 库二、基本使用方法1. 生成简单二维码2. 生成带 Log

Java操作ElasticSearch的实例详解

《Java操作ElasticSearch的实例详解》Elasticsearch是一个分布式的搜索和分析引擎,广泛用于全文搜索、日志分析等场景,本文将介绍如何在Java应用中使用Elastics... 目录简介环境准备1. 安装 Elasticsearch2. 添加依赖连接 Elasticsearch1. 创

怎么关闭Ubuntu无人值守升级? Ubuntu禁止自动更新的技巧

《怎么关闭Ubuntu无人值守升级?Ubuntu禁止自动更新的技巧》UbuntuLinux系统禁止自动更新的时候,提示“无人值守升级在关机期间,请不要关闭计算机进程”,该怎么解决这个问题?详细请看... 本教程教你如何处理无人值守的升级,即 Ubuntu linux 的自动系统更新。来源:https://

java Stream操作转换方法

《javaStream操作转换方法》文章总结了Java8中流(Stream)API的多种常用方法,包括创建流、过滤、遍历、分组、排序、去重、查找、匹配、转换、归约、打印日志、最大最小值、统计、连接、... 目录流创建1、list 转 map2、filter()过滤3、foreach遍历4、groupingB

Java操作PDF文件实现签订电子合同详细教程

《Java操作PDF文件实现签订电子合同详细教程》:本文主要介绍如何在PDF中加入电子签章与电子签名的过程,包括编写Word文件、生成PDF、为PDF格式做表单、为表单赋值、生成文档以及上传到OB... 目录前言:先看效果:1.编写word文件1.2然后生成PDF格式进行保存1.3我这里是将文件保存到本地后

将Python应用部署到生产环境的小技巧分享

《将Python应用部署到生产环境的小技巧分享》文章主要讲述了在将Python应用程序部署到生产环境之前,需要进行的准备工作和最佳实践,包括心态调整、代码审查、测试覆盖率提升、配置文件优化、日志记录完... 目录部署前夜:从开发到生产的心理准备与检查清单环境搭建:打造稳固的应用运行平台自动化流水线:让部署像