使用 QEMU 恢复不可访问的实例

系统灾难后使用 QEMU 或 IBM SmartCloud Enterprise 特性恢复映像

假设某些地方发生了错误,并且您发现在 IBM® SmartCloud Enterprise 上有一个不可访问的 Linux® 实例,那么您该怎么做呢?本文的作者将会带您亲历恢复一个不可访问的 Linux 实例的每个步骤。这些步骤展示了如何捕获一个私有映像,将该映像复制到一个永久存储器,使用 QEMU 来引导所捕获的映像或使用 kpartx 来挂载该映像,修复问题,然后将这个映像重新导入到云中。

Claudiu Popescu, 主题专家, IBM

/developerworks/i/p-pclaudiu.jpgClaudiu Popescu 是一名主题专家,专门研究 IBM SmartCloud Enterprise 和 Enterprise+ 的 L3 客户支持和映像开发。他的研究领域包括云计算、虚拟化、编程和网络架构。



Mihai Criveti, IT 架构师, IBM

/developerworks/i/p-mcriveti.jpgMihai Criveti 是一名主要关注云计算和虚拟化的 IT 架构师。他的兴趣包括云计算、虚拟化、企业架构、SOA、中间件、数字取证以及 UNIX 系统。



2013 年 3 月 18 日

不要手足无措

最好是要有一个应急预案。本文介绍了如何使用 IBM SmartCloud Enterprise 的导入和复制特性来执行云上的裸机恢复。


何时需要在云上进行裸机恢复

所描述的过程要比使用一个远端控制 (lights-out) 管理工具复杂得多,但是用例多少有些相似。以下是需要使用这些恢复措施的一些可能原因:

  • 您无法访问实例的可能原因有很多,比如:
    • 错误地配置了防火墙,并且不再允许 SSH 连接。
    • 错误地配置了 SSH 服务,或删除了私有密钥或 authorized_hosts 文件,并且无法登录到实例。
    • 删除了 idcuser 帐户,且没有为其他帐户配置 SSH 登录。
    • 错误地配置了 GRUB、runlevels 或 startup 脚本,并且您的系统不再引导或启动联网或 SSH 服务。
    • 需要重设帐户密码或使用恢复媒介访问该环境。
    • 需要以单用户模式从文件系统崩溃中恢复。
    • 未知原因(不再能使用 SSH 访问映像。您想要调查并解决此问题。
    • 想要执行系统维护,比如完全备份,或通过单用户模式或使用恢复媒介进行分区。
  • 您可能想要将实例 OS 升级到一个新的主要发布版本,而这又需要从安装媒介进行引导。
  • 您可能想要安装并导入自己的 Linux 操作系统,而且想要直接在云上构建映像。
  • 您的实例可能已经被破坏,您想要将它复制到一个附加的存储器中以便进行鉴定。为此,您可以选择使用像 kpartx 这样的工具将这个映像文件挂载为只读形式,或使用 QEMU 来引导一个 Live CD。QEMU 是一个通用的开源机器模拟器和仿真器。当用作机器模拟器时,QEMU 可以在另一个机器上运行专为单机制作的 OSes 和程序。通过将一个主机模式的网络设备附加到 QEMU 还能让您调查出站的网络连接。

那么在 SmartCloud 内具有 Image Import/Copy 特性之前,是什么状况呢?在很多情况下,如果您的实例不再能够访问,您必须重新提供实例。而现在,借助于 SmartCloud 的这个新特性,您可以使用一系列步骤来恢复无法访问的实例,具体如下所示:

  • 捕获实例的一个私有映像。
  • 将此映像复制到一个永久存储设备。
  • 将这个永久存储器附加到一个 Linux 实例。
  • 使用 QEMU 直接在云上引导 OS 映像。
  • 使用一个 VNC 客户端连接您的导出映像(您可以早在 GRUB 引导加载程序序列就与映像进行交互)。
  • 调查并修复阻碍您使用 SSH 访问此映像的任何问题。
  • 使用一个 SSH 客户端测试登录。
  • 将此映像重新导入到云中。
  • 根据所恢复的映像提供一个新实例。如果想要保留系统主机名和网络设置,则需要一个专有 IP。

恢复工具

为了遵循本文中所描述的步骤,使用以下工具来设置一个环境:

  • SmartCloud Image Import/Copy API
  • Kernal-based Virtual Machine (KVM)
  • libvirt
  • QEMU
  • IBM Rational Asset Manager (REST Client/curl)

让我们逐一简单介绍一下这些工具。

SmartCloud Linux Import/Copy API 和工具用于将虚拟机导入到 SmartCloud 中并在数据中心之间复制映像。要获得有关此特性的详细描述,包括使用指导、样例模式文件以及验证工具,可以查阅 Creating and Customizing Images and Software Bundles 指南(SmartCloud 文档库的一部分)。在 SmartCloud Web 用户界面的 Support 选项卡上也有到此库的链接。您也可以使用 asset catalog search 特性来寻找这些资产。本文中描述的三个特性包括:

  • 映像导入:导入放置在永久存储器上的外部(或内部)映像。
  • 映像复制:将 Rational Asset Catalog 内用 Copy Allowed = Y 属性标记的、启用了 VirtIO 的映像复制到您的 ext3 格式化的永久存储设备的其中一个中。
  • 克隆永久存储器:将一个永久存储卷克隆到另一个数据中心。这可用来将已复制的映像移动到另一个数据中心,在这个数据中心里您可以导入已复制的映像。

SmartCloud 内的基于内核的虚拟机 (Kernel-based Virtual Machine, KVM) 是一个面向 Linux 内核的虚拟化基础架构。由于 KVM 支持包括虚拟化扩展(Intel VT 或 AMD-V)在内的 x86 硬件上的本地虚拟化,所以它不会单独执行任何仿真。KVM 的优势之一是面向网卡、磁盘 I/O 控制器以及 VGA 图形界面的半虚拟化;与全虚拟化相比,这提供了性能上的收益。

Libvirt 是一组用来与像 KVM、Xen 等虚拟机管理程序交互的工具。虚拟机管理程序的管理是使用 >virsh 通过 libvirt 通用的 API 或命令行完成的。

QEMU 是一个快速的通用机器仿真器,支持和 KVM 一起实现虚拟化。

IBM Rational Asset Manager 可由企业用来编目、治理、管理以及作为软件库的一部分维护可重用软件包。


开始设置

让我们停下来一会,先来看看在本文中使用的符号和约定,以及设置环境需要注意的一些事项。

  • 作为 root 在系统上执行的命令以 root@host# 为前缀。
  • 使用 sudo 作为 root 在系统上执行的命令以 user@host# sudo 为前缀。
  • 作为常规用户在系统上执行的命令以 user@host $ 为前缀。
  • 命令的输出与命令通过一个新行进行分割,并向右缩进 1 个制表位(如下面的代码块所示):

注意:在本文中,我们特意对代码块进行了设置,以便无法复制/粘贴全部代码块,这是因为示例代码只是为了起到指导的作用,您需要根据自己的环境、ID、范围等调整该代码。

root@host# 1st command - to be run as root
root@host# 2nd command - to be run as root (previous command has no output)

    output from 2nd command

user@host$ 3rd command - to be run as user

    output from 3rd command

使用 sudo 来运行需要升级特权的命令(或 sudo -s)。不要使用 sudo bash,因为这会保留 idcuser 环境设置。例如:sudo yum install rpmdevtools rpm-devel rpm-build

要求

您必须具有:

  • 一个足够大能容纳已复制映像的 SmartCloud 永久存储卷。您将这个存储器附加到运行 QEMU 的 Linux 实例。
  • 一个 SmartCloud 64 位的 Red Hat Enterprise Linux (RHEL) 或 SUSE Linux Enterprise Server (SLES) 实例,您将在此安装 QEMU、附加永久存储器以及执行恢复步骤。称为 “R1”。
  • 想要恢复的 SmartCloud Linux 实例或映像。称为 “U1”。
  • 来自 SmartCloud 文档库的如下文档:Creating and Customizing Images and Software BundlesCommand Line Tool ReferenceREST API Reference。这些文档包含了执行映像导入/复制所需的文档和工具。

您还会需要:

  • 使用 SmartCloud 命令行工具或 API 的一些经验。
  • 单用户模式下引导 Linux 实例或从安装媒介执行恢复的经验。在 Secure Shell (SSH) 上以隧道的方式处理 VNC 以及使用 Linux 防火墙的经验。这些步骤类似于系统管理员在物理或虚拟硬件上执行的步骤。
  • 使用 QEMU 或 KVM 的经验,以及在 Linux 上构建和安装软件的经验。

而且如果您能保持耐心和决心,那也会很有帮助。引导 QEMU 内的虚拟映像以在虚拟机上运行是一个缓慢且容易出错的过程。根据您的实例以及映像的大小,导入/复制过程也会需要一段时间。如果第一次尝试的时候出错,就必须从头再做一次。已经提醒过您了!


恢复步骤总结

现在就可以开始了。按照如下步骤执行:

  • 捕获映像,并允许在 Rational Asset Catalog 内导出。
  • 编辑所捕获的映像,并将 CopyAllowed = N 更改为 CopyAllowed = Y。
  • 将该映像复制到一个存储设备。将这个存储设备附加到另一个 Linux 实例(R1 实例)并进行挂载。
  • 安装 QEMU 1.1.1 (./configure; make; make install)。
  • 通过 SSH 隧道处理端口 5900。
  • 使用 QEMU 引导该映像。比如:/usr/local/bin/qemu-system-i386 -cdrom /root/IF-YOU-NEED-A-RECOVERY-DISK.iso -boot d -m 1024 -drive file=BWVoPePtRACvZVO3Srl1lQ.img,if=virtio--daemonize
  • 使用一个 VPN 客户端连接到 localhost:0。
  • 修复这个问题。
  • 卸载这个卷并进行分离。
  • 将该映像重新导入到云中。
  • 配给这个新映像并进行测试。

您应该在同一个数据中心执行所有这些步骤。


恢复步骤

现在,一切设置完毕,可以开始了。

创建不可访问实例的一个私有映像

您可以使用 WebUI 捕获一个私有映像:

  1. 登录到 SmartCloud Enterprise Web 界面。
  2. 浏览到 Control Panel > Instances,选择需要恢复的实例并单击 Create private image
  3. 单击 Submit 并等待将要创建的映像。

编辑映像资产

您可以使用 Web 用户界面或 Rational Asset Manager REST API。要使用 Web 用户界面:

  1. 捕获到映像后,转到 Control panel > View asset catalog > Home > My Assets
  2. 搜索所保存的映像并选中它。
  3. 单击位于页面右上角的 pencil 图标。
    图 1. 在 Rational Asset Manager 内修改映像资产
    在 Rational Asset Manager 内修改映像资产
  4. 在 Operating System 下,单击 More
    图 2. 展开 RAM 内的 More... Image Asset 选项卡
    展开 RAM 内的 More... Image Asset 选项卡
  5. 将 Copy Allowed: 从 N 更改为 Y,并通过单击页面右下方的 Update 保存更改。键入描述所做更改的注释,然后再次单击 Update
    图 3. 更新 Rational Asset Manager 内的 Image Asset 选项卡
    更新 Rational Asset Manager 内的 Image Asset 选项卡

将这个映像导出到一个存储设备并进行挂载

  1. 使用命令行工具或 REST API 将这个映像导出到一个存储设备(这个存储设备需要使用 ext3 进行格式化)。使用 SmartCloud 命令行工具:
    user@host$ ic-copy-to.sh -u|--username username -w|--passphrase passphrase 
    -g|--file-path filepath -v|--volume-id volumeID -I|--image-id imageID
  2. 确认映像已经被复制到存储器。使用 SmartCloud 命令行工具:
    user@host$ ic-describe-volume.sh -u $OWNER -g cmihai.key -v $STORAGEID -w pass \
    | grep State
    
        State: UNMOUNTED
  3. 将存储器附加到 R1 实例。本例使用了 Dynamic Disk Attach 特性来将一个磁盘附加到一个已经提供的实例。使用 SmartCloud 命令行工具:
    user@host$ ic-attach-volume.sh -u|--username username -w|--passphrase passphrase
    -g|--file-path filepath -l|--instance-id instanceId -v|--volume-id volumeId

    这类似于:

    user@host$ ic-attach-volume.sh -g <your.key> -u <your.email@ibm.com> -w \
    <your.passphrase> -v <your.volume.id> -l <your.instance.id>
    
        Executing action: AttachVolume  ...
        The request has been submitted successfully.
        Executing AttachVolume  finished
        
    user@host$ ic-describe-volume.sh -g <your.key> -u <your.email@ibm.com> \
    -w <your.passphrase> -v <your.volume.id> \
    | grep State
    
        State: MOUNTED

    注意:如果您的实例不支持动态磁盘附加,您仍可以提供一个新的 Linux 实例并在实例创建期间附加存储器,比如使用这个 WebUI 向导。

  4. 在 R1 实例上挂载所附加的存储器。首先,在实例 R1 上标识出新附加的磁盘。您可以通过检查 dmesg 日志来实现这个目的。新的磁盘应该使用 VirtIO 进行附加,在本例中为 vde1
    user@host# sudo dmesg | tail
    
        virtio-pci 0000:00:07.0: using default PCI settings
        virtio-pci 0000:00:08.0: no hotplug settings from platform
        virtio-pci 0000:00:08.0: using default PCI settings
        pci 0000:00:0a.0: no hotplug settings from platform
        pci 0000:00:0a.0: using default PCI settings
        virtio-pci 0000:00:0a.0: enabling device (0000 -> 0003)
        virtio-pci 0000:00:0a.0: PCI INT A -> Link[LNKB] -> GSI 11 (level, high)
        virtio-pci 0000:00:0a.0: irq 35 for MSI/MSI-X
        virtio-pci 0000:00:0a.0: irq 36 for MSI/MSI-X
        vde: vde1

    您还可以使用 fdisk: 列出分区表

    user@host$ sudo /sbin/sudo fdisk -l

    识别出新磁盘后,就可以继续进行并使用 mount 命令了:

    user@host$ sudo mkdir /mnt/storage                            
    user@host$ sudo mount /dev/vde1 /mnt/storage

    验证 /mnt/storage 的内容:

    user@host$  sudo find /mnt/storage/ -type f -exec \
    sh -c 'du -h {}; printf "\t"; file -b {};' \;
    
        3.6G    /mnt/storage/image/gqlhq2tfTsmBUqFcld4r1Q.img
            x86 boot sector; GRand Unified Bootloader, stage1 version 0x3, 
            boot drive 0x80, 1st sector stage2 0xe0800, GRUB version 0.94; 
            partition 1: ID=0x83, active, starthead 32, startsector 2048, 
            2048000 sectors; partition 2: ID=0x83, starthead 155,
            startsector 2050048, 7426866 sectors, code offset 0x48
        8.0K    /mnt/storage/image/gqlhq2tfTsmBUqFcld4r1Q.ovf
            XML  document text
        28K     /mnt/storage/image/Terms.zip
            Zip archive data, at least v2.0 to extract
        4.0K    /mnt/storage/image/leZ8NeYxSti8pXxnzd3_Tg/vhost0133_DataDisk1.img
            data
        8.0K    /mnt/storage/image/BSS.zip
            Zip archive data, at least v2.0 to extract
        4.0K    /mnt/storage/image/S40E4IiKR923NAsiZTyf0A/vhost0133_DataDisk2.img
            data
        104K    /mnt/storage/image/RAM.zip
            Zip archive data, at least v2.0 to extract

    您的磁盘名称和磁盘号将会有所不同,具体取决于所捕获的实例种类。而且,您的磁盘大小也会有所不同,这是因为这里的磁盘收缩到只包含捕获的数据。

表 1 显示了在 storage/image 下找到的文件。

表 1. 在 storage/image 下找到的文件:
文件路径描述
$UID.ovfOVF 容器
$UID.imgRAW 磁盘映像
$UID/$HOSTNAME_DataDisk$ID.img附加磁盘
BSS.zip压缩的 BSS.xml
RAM.zip压缩的 Rational Asset Manager 工件。
Terms.zip压缩的条款和条件文档。

调整 root 分区的大小

只有当您计划在使用 QEMU 或在 chroot 内引导后安装新的包时才必须要调整 root 分区的大小。导出映像后,root 分区上的空闲空间将会在 10MB 左右。如果需要安装新的包或是复制映像上的文件,那么必须调整分区的大小。

调整 RHEL 上的 root 分区的大小

使用 guestfs 工具:

  1. 安装 libguestfs-tools。
    yum install libguestfs-tools
  2. 将旧的映像文件复制到一个新的映像文件并增加该文件的大小。
    root@host# virt-filesystems -l -h --all -a <your.image.img>
    
        Name       Type        VFS   Label  MBR  Size  Parent
        /dev/sda1  filesystem  ext3  -      -    94M   -
        /dev/sda2  filesystem  ext3  /      -    4.2G  -
        /dev/sda1  partition   -     -      83   94M   /dev/sda
        /dev/sda2  partition   -     -      83   4.2G  /dev/sda
        /dev/sda   device      -     -      -    4.3G  -
                            
    root@host# truncate -r <your.image.img> <your.new.image.img>
    root@host# truncate -s +5G newdisk

    这个新映像文件反映出了新的大小。在本例中为 9.3G。

  3. 现在,图像文件的大小为 5G 以上,扩展这个 root 分区。
    root@host# virt-resize --expand /dev/sda2 olddisk newdisk
                        
        Examining <your.image.img> ...
        100% [##################################################] 00:00
        **********
                        
        Summary of changes:
                        
        /dev/sda1: This partition will be left alone.
                        
        /dev/sda2: This partition will be resized from 4.2G to 9.2G.  The 
        filesystem ext3 on /dev/sda2 will be expanded using the 'resize2fs' 
        method.
                        
        **********
        Setting up initial partition table on <your.new.image.img> ...
        Copying /dev/sda1 ...
        100% [##################################################] 00:00
        Copying /dev/sda2 ...
        100% [##################################################] 00:00
        100% [##################################################] 00:00

    从现在开始,您需要使用这个新映像文件,用 QEMU 引导或使用 kpartx 的备选方案。

调整 SLES 上的 root 分区的大小

使用标准的 Linux 工具:

  1. 请确保所有东西均已卸载,且已删除 loop 设备。
  2. 设置 RAWIMAGE 以方便使用。
    root@host# export RAWIMAGE=<your.image.img>

    请注意这是一个稀疏的映像。

  3. 获得可视的映像大小。
    root@host # du -m --apparent-size $RAWIMAGE
                            
        4628    <your.image.img>
  4. 这通常要比所使用的磁盘空间大。
    root@host# du -m $RAWIMAGE
                                
        3628    <your.image.img>
  5. 调整磁盘的大小。确保想要的大小大于映像大小。使用 dd 将该映像扩展为一个 稀疏文件
    root@host# export DESIREDSIZE="9000"
    root@host# dd if=/dev/zero of=$RAWIMAGE bs=1M count=0 seek=$DESIREDSIZE
  6. 请确保您的映像文件扩展到新的大小。
    root@host# du -m --apparent-size $RAWIMAGE
                        
        9000    <your.image.img>
  7. 现在,您就可以创建 loop 设备了。
    root@host# losetup /dev/loop0 $RAWIMAGE
    root@host# fdisk -l /dev/loop0
    root@host# kpartx -av /dev/loop0
  8. 运行一个文件系统检查。
    >root@host# e2fsck -fy /dev/mapper/loop0p1
  9. 删除旧分区,并在其位置上创建一个较大的分区来调整分区的大小。若在这里出错有可能会导致数据丢失。请留意分区的布局并调整这些命令以匹配您的映像。

    注意:在如下的代码部分中,用户输入均以粗体标记。

    root@host# fdisk /dev/loop0
        Command (m for help): p
                        
        Disk /dev/loop0: 9437 MB, 9437184000 bytes
        255 heads, 63 sectors/track, 1147 cylinders
        Units = cylinders of 16065 * 512 = 8225280 bytes
        Sector size (logical/physical): 512 bytes / 512 bytes
        I/O size (minimum/optimal): 512 bytes / 512 bytes
        Disk identifier: 0x0003ee5f
                        
        Device Boot      Start         End      Blocks   Id  System
        /dev/loop0p1   *           1         128     1024000   83  Linux
        Partition 1 does not end on cylinder boundary.
        /dev/loop0p2             128         590     3713433   83  Linux
        Partition 2 does not end on cylinder boundary.
                        
        Command (m for help): d
                     
        Partition number (1-4): 2
                        
        Command (m for help): n
        Command action
        e   extended
        p   primary partition (1-4)
        p
        Partition number (1-4): 2
        First cylinder (128-1147, default 128):
        Using default value 128
        Last cylinder, +cylinders or +size{K,M,G} (128-1147, default 1147):
        Using default value 1147
                        
        Command (m for help): p
                        
        Disk /dev/loop0: 9437 MB, 9437184000 bytes
        255 heads, 63 sectors/track, 1147 cylinders
        Units = cylinders of 16065 * 512 = 8225280 bytes
        Sector size (logical/physical): 512 bytes / 512 bytes
        I/O size (minimum/optimal): 512 bytes / 512 bytes
        Disk identifier: 0x0003ee5f
                        
        Device Boot      Start         End      Blocks   Id  System
        /dev/loop0p1   *           1         128     1024000   83  Linux
        Partition 1 does not end on cylinder boundary.
        /dev/loop0p2             128        1147     8188253+  83  Linux
        
        Command (m for help): w
        The partition table has been altered!
                        
        Calling ioctl() to re-read partition table.
                        
        WARNING: Re-reading the partition table failed with error 22: Invalid argument.
        The kernel still uses the old table. The new table will be used at
        the next reboot or after you run partprobe(8) or kpartx(8)
        Syncing disks.
  10. 重读分区表。
    root@host# kpartx -dv /dev/loop0
    root@host# losetup -d /dev/loop0
    root@host# losetup /dev/loop0 $RAWIMAGE
    root@host# fdisk -l /dev/loop0
    root@host# kpartx -av /dev/loop0
  11. 调整分区的大小。
    root@host#resize2fs /dev/mapper/loop0p2
        resize2fs 1.41.12 (17-May-2010)
        Resizing the filesystem on /dev/mapper/loop0p2 to 2047063 (4k) blocks.
        The filesystem on /dev/mapper/loop0p2 is now 2047063 blocks long.
  12. 运行另一个文件系统检查。
    root@host# e2fsck -fy /dev/mapper/loop0p2

安装 QEMU

登录到您已经附加并挂载了存储器的实例并安装 QEMU。

在 RHEL 上安装 QEMU

  1. 构建 QEMU RPM 和 SRC RPM。首先,您需要这些文件。
    user@host$ wget http://wiki.qemu.org/download/qemu-1.1.1.tar.bz2
  2. 要构建 RPM,需要一个 spec 文件。
    user@host$ cat > qemu-1.1.1.spec <<'EOF'
    Name            : qemu
    Version         : 1.1.1
    Release         : 1
    License         : LGPL, GPL
    Summary         : A generic and open source processor emulator.
    Group           : Applications/Emulators
    URL             : http://fabrice.bellard.free.fr/qemu/
    Vendor          : Fabrice Bellard >fabrice@bellard.org<
    Packager        : Your Name >recipient@domain.tld<
    BuildRoot       : %{_tmppath}/%{name}-buildroot
    Source0         : %{name}-%{version}.tar.gz        
    Requires        : gcc
    BuildRequires   : gcc
    AutoReq         : no
    AutoProv        : no
            
    %description
    QEMU emulator.
            
    %prep
    rm -rf %{buildroot}
            
    %setup -q
            
    %build
    ./configure --prefix=/usr
    make
            
    %install
    mkdir -p %{buildroot}/usr/lib/debug
    make install prefix=%{buildroot}/usr bindir=%{buildroot}/usr/bin \
    datadir=%{buildroot}/usr/share/qemu docdir=%{buildroot}/usr/share/doc/qemu \ 
    mandir=%{buildroot}/usr/share/man
            
    %clean
    rm -rf %{buildroot}
            
    %files
    %defattr(-,root,root)
    %doc Changelog COPYING COPYING.LIB LICENSE README README.distrib TODO VERSION
    %{_bindir}/qemu*
    %{_docdir}/qemu
    %{_mandir}/man1/qemu*
    %{_datadir}/qemu
    * Thu Aug 02 2012 Your Name >recipient@domain.tld< 1.0-1
    - qemu 1.1.1
            
    EOF
  3. 构建二进制和源 RPM。

    在 RHEL 上使用 yum 来安装 RPM 构建工具。

    root@host# yum install rpmdevtools rpm-devel rpm-build

    在 SLES 上,使用 zypper 来安装 RPM 构建工具。

    root@host# zypper install rpmdevtools rpm-devel rpm-build
  4. 构建这些 RPM。您可以作为常规用户(建议)或作为 root 用户来完成。
    root@host# cp qemu-1.1.1.spec /usr/src/packages/SPEC
    root@host# cp qemu-1.1.1.tar.bz2 /usr/src/packages/SOURCES/qemu-1.1.1.tar.bz2
    root@host# rpmbuild -ba /usr/src/packages/SPEC/qemu-1.1.1.spec

在 SLES 上安装 QEMU

  1. 查出安装的是 glib2 的哪个版本。
    user@host$ sudo zypper info glib2 | grep Version
    
        Version: 2.22.5-0.4.3
  2. 知道了安装的是 stock glib2 版本之后,就需要获得相同的版本并进行构建。下载并解压缩。
    user@host$ wget http://wiki.qemu.org/download/qemu-1.1.1.tar.bz2
    user@host$ wget http://zlib.net/zlib-1.2.7.tar.gz  
    user@host$ wget http://ftp.acc.umu.se/pub/GNOME/sources/glib/2.22/glib-2.22.5.tar.bz2
    user@host$ wget ftp://sourceware.org/pub/libffi/libffi-3.0.10.tar.gz
    user@host$ tar zxf qemu-1.1.1.tar.bz2
    user@host$ tar zxf zlib-1.2.7.tar.gz
    user@host$ tar jxf glib-2.22.5.tar.bz2
    user@host$ tar zxf libffi-3.0.10.tar.gz
  3. 构建 libffi
    user@host$ cd libffi-3.0.10/
    user@host$ ./configure && make && sudo make install && cd..
  4. 构建 zlib
    user@host$ cd zlib-1.2.7/
    user@host$ ./configure && make && sudo make install && cd..
  5. 构建 glib2
    user@host$ cd glib-2.22.5
    user@host$ ./configure && make && sudo make install && cd..
  6. 构建 QEMU。
    user@host$ cd qemu-1.1.1/
    user@host$ ./configure && make && sudo make install && cd..

引导该映像

在执行 QEMU 以引导映像之前,为一个新的会话启动 vncviewer。您还将需要编辑 GRUB 配置行来以单用户模式引导该映像。您只有 5 秒时间停止映像的引导。

  1. 首先,为 VNC 设置一个 ssh 隧道。您可以使用 SSH 或 PuTTY。PuTTY 是一个开源 telnet 和 SSH 客户端。

    要想使用 SSH 转发这个 VNC 端口:

    user@host$ ssh -i /pub_key-g -L 5910:127.0.0.1:5901 idcuser@instance-R1

    要想使用 PuTTY 转发这个 VNC 端口:

    1. 启动 PuTTY。对于主机名,输入 Linux 实例的公共 IP 地址。
      图 4. 新建的 PuTTY 会话
      PuTTY 会话
    2. 在 Category 框中,单击 SSH 并选择 Compression 复选框。
      图 5. 在 PuTTY 内启用 SSH 压缩
      在 PuTTY 内启用 SSH 压缩
    3. 展开 SSH 并单击 Auth。通过单击 Browse 并导航到存储了 .ppk 密钥的位置来加载已加密的 .ppk 密钥:
      图 6. PuTTY Auth
      PuTTY Auth
    4. 单击 Tunnel。输入本地使用的 Source 端口 :5910 以及将要转发的 Destination 端口 127.0.0.1:5901。
      图 7. PuTTY 端口转发
      PuTTY 端口转发
    5. 在 Category 框中,单击 Session 并单击 Open
  2. 在 R1 实例上添加一个 iptables 规则以允许 VNC 通过防火墙。
    	user@host$ sudo /sbin/iptables -A INPUT -p tcp --dport 5900:5920 -j ACCEPT
    	user@host$ sudo /sbin/service iptables save
  3. 引导该映像。

    对于 64 位:

    root@host$ /usr/local/bin/qemu-system-x86_64 -vnc 127.0.0.1:1 -m 1024 \
    -drive file=<your.image.img>,if=virtio -daemonize

    对于 32 位:

    root@host# /usr/local/bin/qemu-system-i386 -vnc 127.0.0.1:1 -m 1024 \
    -drive file=<your.image.img>,if=virtio -daemonize

使用 VNC 从本地工作站进行连接

现在就可以进行连接了。

在 UNIX 上,运行 vncviewer

user@host$ vncviewer 127.0.0.1:5910

在 Windows 上,您可以使用任何一个免费的 VNC Viewer 程序,比如 RealVNC。

在 RHEL 上

现在应该可以看到映像的引导了。

  1. 在 VNC 窗口内单击,按下空格键停止引导过程,然后键入 e 进行编辑。
    图 8. RHEL 5 - GRUB 引导菜单
    RHEL 5 grub 引导菜单
  2. 选择 kernel 行并键入 e
    图 9. RHEL 5 - GRUB - kernel 行
    RHEL 5 grub kernel 选择
  3. 删除 serial console 行。向 kernel 行添加 Single
    图 10. RHEL 5 - GRUB - kernel 编辑
    RHEL 5 - GRUB - kernel 编辑
  4. 按下 Enter 键,然后键入 b 进行引导。例如,编辑 kernel 行来以单用户模式引导映像。
    kernel /vmlinuz-2.6.32-131.0.15.el6.x86_64 ro \
    root=UUID=252e009f-8fc9-455e-9e65-400e5baa413d \
    rd_NO_LUKS rd_NO_LVM rd_NO_MD rd_NO_DM \
    LANG=en_US.UTF-8 SYSFONT=latarcyrheb-sun16 KEYBOARDTYPE=pc \
    KEYTABLE=us crashkernel=auto rhgb quiet \
    console=ttyS1,9600 console=ttyUSB0,115200n8 elevator=deadline Single

    注意:删除 console 行。

参阅 参考资料 获得 Red Hat Enteprise 文档的相关链接,了解如何恢复 RHEL 实例的详细信息。

使用 SLES GRUB 引导菜单

  1. 引导这个映像。
    图 11. SLES - GRUB edit - init=/bin/bash
    SLES GRUB edit single

    有关在恢复模式下引导一个 SLES 实例的更多详细信息,请参阅 官方文档

  2. 在使用 init=/bin/bash 引导该映像之后,为 idcuser 设置密码。
    user@host$ passwd idcuser
  3. 在运行级别 3 中启动机器。
    user@host$ init 3
  4. idcuser 登录并启用 sshd service
    user@host$ sudo /sbin/service sshd start
    user@host$ sudo /sbin/chkconfig sshd on
  5. 关闭这个用 QEMU 引导的映像。

从 storage/volume 导入这个映像

您差不多已经完成了这个恢复过程。

  1. 当关闭 QEMU 内所引导的映像后,将 FileValidation.sh 脚本(位于 Rational Asset Catalog 中)复制到 image 文件夹中。
  2. 验证 image 文件夹内的所有文件。如果验证失败,就会创建一个新的具有 FileValidation.sh 脚本的 manifest.mf 文件。
  3. 创建 .mf 文件后,将存储器从 R1 实例分离开来。
  4. 从存储器导入 U1 映像:
    user@host$ ic-import-image.sh u [username] -g [auth file full path] -w [passphrase] 
        -v [volume id] -n [name of image]
  5. 如果导入成功,就会在 SCE > Control panel > Images 选项卡内创建一个私有映像。
  6. 从这个私有映像创建一个子实例并尝试访问该实例。如果成功提供了子实例,那么应该能够通过 ssh 访问该子实例。

使用 kpartx(而不是 QEMU)挂载这个映像文件

在某些情况下,比如执行检查或只是将私有密钥复制到 authorized_keys 文件,只需挂载导出的映像 “loopback” 就足够了。本节将阐释具体的做法。

最初的复制步骤

最初的映像复制步骤类似于 QEMU 场景中的步骤:

  1. 捕获想要恢复的实例的私有映像。
  2. 创建一个足够大的 ext3 格式化的永久存储器来容纳同一个数据中心内的映像。
  3. 在对应于所捕获映像的 Rational Asset Catalog 项内将 Copy Allowed 属性设为 Y。
  4. 获得所捕获映像的 Image ID 以及从 WebUI、API 或 CMD 工具创建的存储器的 Storage Volume ID。
  5. 使用 ic-copy-to.sh 命令或 API 将您的映像复制到存储器。
  6. 将这个存储器附加到一个现有的 Linux 实例,或创建一个新的 Linux 实例并将这个存储器附加到该实例。

挂载所导出的映像

  1. 通过 SSH 访问挂载这个存储的 Linux 实例并挂载此映像。
    root@host# losetup /dev/loop0 /mnt/storage/image/<your.image.img>
    root@host# fdisk -l /dev/loop0
    
        Disk /dev/loop0: 4852 MB, 4852179968 bytes
        255 heads, 63 sectors/track, 589 cylinders
        Units = cylinders of 16065 * 512 = 8225280 bytes
        Sector size (logical/physical): 512 bytes / 512 bytes
        I/O size (minimum/optimal): 512 bytes / 512 bytes
        Disk identifier: 0x0003ee5f
        
        Device Boot      Start         End      Blocks   Id  System
        /dev/loop0p1   *           1         128     1024000   83  Linux
        Partition 1 does not end on cylinder boundary.
        /dev/loop0p2             128         590     3713433   83  Linux
        Partition 2 does not end on cylinder boundary.
    
    root@host# kpartx -av /dev/loop0
    
        add map loop0p1 (253:0): 0 2048000 linear /dev/loop0 2048
        add map loop0p2 (253:1): 0 7426866 linear /dev/loop0 2050048
    
    root@host# mkdir /mnt/myimage
    root@host# mount /dev/mapper/loop0p2 /mnt/myimage
    root@host# mount /dev/mapper/loop0p1 /mnt/myimage/boot

    您可以使用 fdisk -l /dev/loop0 列出 <your.image.img> 的分区表。

  2. 映像已经挂载。

    您可能还需要挂载其他的分区(比如其他磁盘上的分区)。可以根据您的分区方案对上述步骤进行调整来实现这一目的。请注意挂载 LVM(pvs、lvdisplay、vgscan 等)的分区部分还有一些额外的步骤。如果已经挂载了 root 分区,那么可以重用现有的挂载点(以主机 OS 挂载点为前缀)。

    您可以使用 chroot 命令来使用映像的工具和二进制:

    1. 在您的映像内挂载 /proc /sys /dev/dev/pts
      root@host# mount -o bind /proc /mnt/myimage/proc
      root@host# mount -o bind /sys /mnt/myimage/sys 
      root@host# mount -o bind /dev /mnt/myimage/dev
      root@host# mount -o bind /dev/pts /mnt/myimage/dev/pts
    2. 现在,就可以使用 chroot 命令了。
      root@host# chroot /mnt/myimage
    3. 查看 OS 和 kernel 的版本。
      user@host$ cat /etc/issue
      user@host$ uname -a
    4. 修复可能有的问题,然后退出 shell。
      exit

      您可以访问所有的 OS 工具(包括 yum、zypper 等)。请不要忘记如果需要,在挂载前要重新调整分区的大小。

    请注意,您可能还需要挂载其他的分区。现在就可以修复您的映像了。请注意您也可以使用 chroot 命令来使用映像的工具和二进制:chroot /mnt/myimage/ /bin/bash

  3. 完成后,卸载这个映像。如果需要,请务必退出 chroot。如果您为 chroot 挂载了特殊的设备,请先卸载这些设备。
    root@host# umount /mnt/myimage/proc/
    root@host# umount /mnt/myimage/dev/pts
    root@host# umount /mnt/myimage/dev
    root@host# umount /mnt/myimage/sys
  4. 首先使用挂装点卸载其他分区。比如:
    root@host# umount /mnt/myimage/boot/
  5. 卸载 root 映像。
    root@host# umount /mnt/myimage/
  6. 删除分区映射以及循环设备。
    root@host# kpartx -dv /dev/loop0
        del devmap : loop0p2
        del devmap : loop0p1
    
    root@host# losetup -d /dev/loop0
  7. 通过运行 FileValidationTool.sh 重新创建包含 SHA1SUM 代码的 .mf 文件。参阅 /mnt/myimage/image 目录内的 Creating and customizing images 指南。
  8. 分离这个永久存储卷并将修复后的映像重新导入到云中。

结束语

在本文中,我们向您展示了如何通过捕获一个私有映像、将该私有映像复制到永久存储器、使用 QEMU 引导一个附加到永久存储设备的 Linux 映像、修复问题以及将映像重新导入到云中来恢复一个不可访问的 Linux 实例。此外,我们还展示了一种替代方案 —— 使用 kpartx 挂载映像文件。这些过程可以帮助您重新回归正常,但是这些过程的确需要时间、耐心以及基本的 Linux 知识。


附录 A:存储状态码及含义

此表列出了存储状态码及含义。

存储状态码含义存储状态码含义存储状态码含义
0新建5已附加10正在附加
1正在创建6故障11正在分离
2正在删除7即将删除12正在复制
3已删除8正被克隆13正在导入
4已分离9正在克隆14转换重试

附录 B: Rational Asset Manager REST API

Rational Asset Manager 提供了一些 REST API,让您可以执行资产以及工件上的事务操作。

图 12. Rational Asset Manager Rest Model - Search
Rational Asset Manager Search API

附录 C: 使用 Rational Asset Manager REST API

这是危险地带!您随时都可以返回并转而使用 WebUI。这个过程很容易出错,所以务必小心。

  1. 为了方便使用,设置 USER、PASSWORD、OWNER 和 BASE_URL。

    如果您定义了在章节 将映像导出到一个存储器并挂载该映像 内描述的变量,请忽略本步骤。

    user@host$ export OWNER=<your.ibm.id@domain.tld>
    user@host$ read PASSWORD
    user@host$ export LOGIN="$OWNER:$PASSWORD"
    user@host$ export BASE_URL=\
    https://www-147.ibm.com/computecloud/enterprise/api/rest/20100331/
  2. 您需要找到所保存映像的 ID。注意:我们必须安装 libxml2 的一个更新的版本,如上所述,使用 xmllint 内的 --xpath 函数。作为一个最佳实践,您可能想要以常规用户构建包。
    root@host# yum install tidy rpm-build rpmdevtools xz-devel python-devel
    root@host# rpm -ivh ftp://xmlsoft.org/libxml2/libxml2-2.8.0-1.src.rpm
    root@host# cd ~/rpmbuild/SPECS/
    root@host# rpmbuild -ba libxml2.spec
    root@host# rpm -Uvh /root/rpmbuild/RPMS/x86_64/libxml*

    我们使用一个 XPath 表达式来只打印 PRIVATE 映像。

    user@host$ curl -s -k -H 'Accept: application/xml' \
    -u $LOGIN $BASE_URL/offerings/image \
    |xmllint --xpath \
    "//Image[Visibility=\"PRIVATE\" and Owner=\"$OWNER\"]/ID \
    | //Image[Visibility=\"PRIVATE\" and Owner=\"$OWNER\"]/Name" - \
    | tidy -xml -q
                            
    <ID>20059014</ID>
    <Name>RHEL-58-x32-COPPER-IMG1</Name>
    <ID>20059016</ID>
    <Name>RHEL-62-BRONZE</Name>
    <ID>20059017</ID>
    <Name>SLES-11SP1-X64 7/23/12 2:38 AM</Name>
  3. 设置 IMAGEID 变量。
    user@host$ export IMAGEID=<your.image.id>
  4. 获得惟一的 Image ID 并替代 { and }
    user@host$ export GUID=$(curl -s -u $LOGIN \
    $RAM_BASE_URL'/search?q=({owner:("'$OWNER'")id\:("'$IMAGEID'")})' \
    | xml_grep -t //GUID)
                            
    user@host$ export RAMGUID=$(echo $GUID \
    | sed -e 's/{/%7B/g' | sed -e 's/}/%7D/g')

    注意:如果没有 xml_grep 或任何 XPath 工具可用,您可以使用标准的 Linux 工具,比如 grep、awk、sed 等。比如:

    RAMGUID=%7B`curl -s -u $LOGIN \
    $RAM_BASE_URL'/search?q=({owner:("'$OWNER'")id\:("'$IMAGEID'")})' \
    | grep '/GUID' | awk -F{ '{print $2}' \
    | awk -F} '{print $1}'`%7D
  5. 保存 XML 以便编辑。
    curl -s -u $LOGIN "$RAM_BASE_URL/assets/$RAMGUID/1.0" > $IMAGEID.xml
  6. 使用您最喜欢的文本编辑器编辑此 XML:vim $IMAGEID.xml。查找带文本 “Copy Allowed” 的 //ram:attributeValue//dce:title 元素。将如下的 value 元素更改为 Y
    <ram:attributeValue>
    <attribute rel="related" href="internal/attributes/classif/assetTypesSchema.xmi
    %23copy_allowed.xml">
    <dce:title>Copy Allowed</dce:title>
    </attribute>
    <value>Y</value>
    </ram:attributeValue>
  7. 现在,您就可以更新该资产了。
    curl --header "Content-Type:application/xml" -X PUT -u $LOGIN -d @$IMAGEID.xml \
    "$RAM_BASE_URL/assets/$RAMGUID/1.0"

    注意:如果想要再次更新此资产,就需要下载此资产 XML 的一个新版本,如步骤 5 所描述的那样。


附录 D: 使用 SmartCloud REST API

您可以使用 SmartCloud REST API 与 Linux curl 工具来执行与使用 WebUI 或命令行工具相同的操作。

SmartCloud REST API:将一个映像复制到存储器 (ic-copy-to)

您可以使用 REST API 执行与 ic-copy-to.sh 命令行工具相同的命令。在 Linux 上,您可以使用 curl 命令。下面详细描述了一个示例。注意,您需要用自己的值替换 USER、PASSWORD、IMAGE 和 STORAGE 的值。

本文中多次使用了所导出的变量,因此,您应该只使用在其中为 API 调用导出变量的那个终端。

user@host$ export LOGIN=<your.ibm.id@domain.tld:your.password>
user@host$ export BASE_URL=https://www-147.ibm.com/computecloud/enterprise/api/rest\
/20100331
user@host$ export IMAGE=<your.image.id>
user@host$ export STORAGE=<your.storage.id>
user@host$ curl -s -u $LOGIN -X PUT -d "imageId=$IMAGE" --location-trusted \
$BASE_URL/storage/$STORAGE

如果您没有在 RAM 内设置 Copy Allowed 标志,就会收到如下错误:Error 501: CopyTo feature is not allowed for this image

SmartCloud REST API:验证映像是否复制到存储器 (ic-describe-volume)

您可以使用 REST API 执行与 ic-describe-volume.sh 命令行工具相同的命令。在 Linux 上,您可以使用 curl 命令。下面附加了一个示例。注意,您需要用自己的值替换 USER、PASSWORD、IMAGE 和 STORAGE 的值。

user@host$  curl -s -k -H 'Accept: application/xml' \
-u $LOGIN $BASE_URL/storage/$STORAGEID \
| tidy -xml -q | grep "State"

    <State>12</State>

参考 API User's Guide 中的 “Storage state code and meaning” 部分。12 表示正在复制。等待 <State>4</State>,它的意思是已分离。

SmartCloud REST API:动态磁盘附加(ic-attach-volume 和 ic-describe-volume)

首先,您需要定义下列变量以方便使用:

user@host$ export INSTANCEID=<your.instance.id>
user@host$ export STORAGEID=<your.storage.id>
user@host$ export DATA="type=attach&storageID=${STORAGEID}"

附加您的磁盘:

user@host$ curl -s -u $LOGIN -X PUT -d "$DATA" --location-trusted \
$BASE_URL/instances/${INSTANCEID}

检查状态:

user@host$ curl -s -k -H 'Accept: application/xml' \
-u $LOGIN $BASE_URL/storage/$STORAGEID \
| tidy -xml -i -q | grep State

    <State>10</State>

在本例中,您可以看到磁盘状态为 10 - Attaching。如果成为 5,就意味着已经附加。如果成为 4,就意味着已经分离且附加失败。

参考资料

学习

获得产品和技术

  • 您可以使用 QEMU 这个开源处理器仿真器来直接在云实例上引导 SmartCloud 映像。
  • 下载 PuTTY。这是一种开源的 SSH 和远程登录客户端。
  • 您可以使用 RealVNC 连接到一个计算机并进行远程控制。
  • Libvirt 是一组用来与 KVM、Xen 等虚拟机管理程序进行交互的工具。
  • TightVNC:一种免费的远程控制软件包 可用来连接到 QEMU VNC 显示器。

讨论

条评论

developerWorks: 登录

标有星(*)号的字段是必填字段。


需要一个 IBM ID?
忘记 IBM ID?


忘记密码?
更改您的密码

单击提交则表示您同意developerWorks 的条款和条件。 查看条款和条件

 


在您首次登录 developerWorks 时,会为您创建一份个人概要。您的个人概要中的信息(您的姓名、国家/地区,以及公司名称)是公开显示的,而且会随着您发布的任何内容一起显示,除非您选择隐藏您的公司名称。您可以随时更新您的 IBM 帐户。

所有提交的信息确保安全。

选择您的昵称



当您初次登录到 developerWorks 时,将会为您创建一份概要信息,您需要指定一个昵称。您的昵称将和您在 developerWorks 发布的内容显示在一起。

昵称长度在 3 至 31 个字符之间。 您的昵称在 developerWorks 社区中必须是唯一的,并且出于隐私保护的原因,不能是您的电子邮件地址。

标有星(*)号的字段是必填字段。

(昵称长度在 3 至 31 个字符之间)

单击提交则表示您同意developerWorks 的条款和条件。 查看条款和条件.

 


所有提交的信息确保安全。


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=10
Zone=Cloud computing, Linux
ArticleID=861672
ArticleTitle=使用 QEMU 恢复不可访问的实例
publish-date=03182013