KVM虛擬化管理

轉載地址:https://gitshell.com/chenzhiwei/linux/tree/master/kvm-qemu-libvirt-virtualization/

KVM虛擬化管理

什麼是KVM

KVM(Kernel-based Virtual Machine)是基於內核的虛擬化解決方案,目前Intel和AMD的CPU都對其提供了好很的支持。

平時KVM也會被說成是管理KVM虛擬化的一個工具,類似於qemu(quick emulator)。在網上看的文檔,有的說KVM只能在物理機上做虛擬化,而qemu還適合在虛擬機上面進一步做虛擬化。目前大家常用的KVM虛擬化工具都是qemu。

什麼是libvirt

libvirt是一套免費、開源的支持Linux下主流虛擬化工具的C函數庫,這個函數庫是一種實現Linux虛擬化功能的API,它支持虛擬機監控程序,比如Xen, KVM, Qemu等。

KVM虛擬化鏡像製作

創建img鏡像文件(快照)

# cd /var/instances
# qemu-img create ubuntu.img 5G

使用qemu-img來創建一個空的鏡像文件,可以用-f參數來指定鏡像文件格式,默認爲raw。

在img文件上安裝虛擬機系統

# cd /var/instances
# kvm -hda ubuntu.img -cdrom ubuntu-12.04-server-amd64.iso -boot d -m 512

注:在CentOS下面,kvm命令爲qemu-kvm,在軟件包qemu-kvm裏。以上兩步操作可以一步完成。

# cd /var/instances
# virt-install --name=ubuntu --ram=512 --vcpu=2 \
    --disk path=/var/instances/ubuntu.img,size=5 \
    --cdrom=/var/images/ubuntu-12.04-server-amd64.iso \
    --graphics=vnc,listen=0.0.0.0
#

virt-install命令在virtinst包裏,在CentOS下該包名爲python-virtinst,其實最終調用的命令還是qemu-img和qemu-kvm。

按照提示完成操作系統的安裝

打開VNC客戶端,進入安裝界面,然後一步步的完成安裝。安裝完成之後會在相應目錄下生成鏡像文件及xml配置文件(/etc/libvirt/qemu/ubuntu.xml)。

對虛擬機鏡像進行定製

用以下命令掛載並操作鏡像:

# cd /var/instances
# mount -o loop ubuntu.img /mnt
# chroot /mnt

接下來怎麼操作就不用我說了吧。。。如果chroot之後系統提示Cannot open /dev/urandom for reading: No such file or directory,那麼你在chroot之前需要執行以下命令mount --bind /dev /mnt/dev,其他相似問題類似處理方法。

提取文件系統

在上一步你掛載鏡像時是否遇到了問題?(mount: you must specify the filesystem type),原因很簡單,你當時用這個鏡像安裝操作系統時肯定分了其他分區,並且還有偏移量。你必須將根分區(/)提取出來,然後就可以直接掛載了。

  • 掛載有偏移量的鏡像
# cd /var/instances
# sfdisk -l -uS  ubuntu.img
-------- output of sfdisk command --------
Disk ubuntu.img: cannot get geometry

Disk ubuntu.img: 652 cylinders, 255 heads, 63 sectors/track
Warning: extended partition does not start at a cylinder boundary.
DOS and Linux will interpret the contents differently.
Units = sectors of 512 bytes, counting from 0

   Device Boot    Start       End   #sectors  Id  System
ubuntu.img1   *      2048   9437183    9435136  83  Linux
ubuntu.img2       9439230  10483711    1044482   5  Extended
ubuntu.img3             0         -          0   0  Empty
ubuntu.img4             0         -          0   0  Empty
ubuntu.img5       9439232  10483711    1044480  82  Linux swap / Solaris

從以上輸出可以看到這個鏡像其實包含了5個分區!!!

我們要想掛載第一個分區,需要知道它的偏移量爲512*2048=1048576,然後掛載mount -o loop,offset=1048576 ubuntu.img /mnt/

注: 偏移量是柱面的偏移數,實際偏移的字節數等於512*柱面偏移數,sfdisk命令輸出的第三列即爲柱面偏移數。

  • 提取根(/)文件系統
# cd /var/instances
# losetup -f ubuntu.img
# losetup -a

/dev/loop0: [0811]:56885251 (/var/instances/ubuntu.img)

# sfdisk -l -uS /dev/loop0 

Disk /dev/loop0: cannot get geometry

Disk /dev/loop0: 652 cylinders, 255 heads, 63 sectors/track
Warning: extended partition does not start at a cylinder boundary.
DOS and Linux will interpret the contents differently.
Units = sectors of 512 bytes, counting from 0

   Device Boot    Start       End   #sectors  Id  System
/dev/loop0p1   *      2048   9437183    9435136  83  Linux
/dev/loop0p2       9439230  10483711    1044482   5  Extended
/dev/loop0p3             0         -          0   0  Empty
/dev/loop0p4             0         -          0   0  Empty
/dev/loop0p5       9439232  10483711    1044480  82  Linux swap / Solaris

# losetup -d /dev/loop0
# losetup -f -o 1048576 ubuntu.img
# losetup -a
/dev/loop0: [0811]:56885251 (/var/instances/ubuntu.img), offset 1048576
# dd if=/dev/loop0 of=ubuntu.final.img
# mount -o loop ubuntu.final.img /mnt
# chroot /mnt

以上這些操作就是提取根(/)文件系統的步驟。首先找到ubuntu.img鏡像的根所在的分區的偏移量,並用losetup命令掛載成loop設備,然後使用dd命令將該loop設備(/dev/loop0)轉換成文件,而這個文件就是最終的鏡像文件。

將內核文件及ramdisk提取出來:

# cd /var/instances
# mount -o loop ubuntu.final.img /mnt
# cp /mnt/boot/vmlinuz-3.2.0-23-generic kernel
# cp /mnt/boot/initrd.img-3.2.0-23-generic ramdisk

鏡像製作2

當你看了之前的製作鏡像步驟後會發現很麻煩,現在介紹一種比較簡單的製作方法。

# qemu-img create ubuntu-12.10.img 10G
# mkfs.ext4 -F -q ubuntu-12.10.img
# kvm -hda ubuntu-12.10.img -cdrom ubuntu-12.10-server-amd64.iso -boot d -m 1024 -vnc 0.0.0.0:20
# mount -o loop ubuntu-12.10.img /mnt
# cp /mnt/boot/initrd.img-3.5.0-17-generic ramdisk
# cp /mnt/boot/vmlinuz-3.5.0-17-generic kernel
# tune2fs -L new-lable ubuntu-12.10.img
# vim /mnt/etc/fstab
edit to the format you like
LABEL=new-lable /               ext4    defaults 0 0
/dev/vda        /               ext4    defaults 0 0
# umount /mnt

以上幾條命令的意思是將系統安裝在整個磁盤上,即磁盤不分區,也就意味着這需要你自己指定內核來啓動系統,詳情請參見instance-hostname.xml文件中的配置。

掛載qcow2格式的文件

# modprobe nbd max_part=16
# qemu-nbd -c /dev/nbd0 disk.qcow2
# partprobe /dev/nbd0
# mount /dev/nbd0 /mnt
# umount /mnt
# qemu-nbd -d /dev/nbd0

以上幾條命令的意思是給內核添加nbd模塊,使用qemu-nbd命令去連接(connect)文件disk.qcow2,通知操作系統分區表已經被修改,掛載與卸載,斷開連接(disconnect)。其中max_part=16表示每塊nbd設備支持的分區個數(modinfo nbd),命令modprobe -r nbd來刪除內核中的nbd模塊。

更多相關內容: http://en.wikibooks.org/wiki/QEMU/Images#Mounting_an_image_on_the_host

KVM虛擬機管理

按照以上方式創建完成虛擬機鏡像之後libvirt會自動生成一個xml配置文件,管理虛擬機主要就靠這個xml文件了,管理的命令是virsh。

# virsh list
# virsh list --all
# virsh create /etc/libvirt/qemu/ubuntu.xml
# virsh define /etc/libvirt/qemu/ubuntu.xml
# virsh undefine /etc/libvirt/qemu/ubuntu.xml
# virsh autostart domain_id|instance_name
# virsh destory domain_id|instance_name
# virsh start/shutdown/reboot/... domain_id|instance_name

如果你已經創建好虛擬機的鏡像了,並且xml文件模板也已經有了,那麼就可以直接用virsh來進行管理,免去了以上那麼多的麻煩。

Ubuntu已經有自己做好的虛擬機鏡像了,可以直接拿去使用。Ubuntu Enerprise Cloud(UEC): http://uec-images.ubuntu.com/releases/

libvirt XML文件格式

常規信息區域

<domain type='xen' id='3'>
    <name>instance-name</name>
    <uuid>d9ef885b-634a-4437-adb6-e7abe1f792a5</uuid>
    <title>A short description - title - of the domain</title>
    <description>Some human readable description</description>
    <metadata>
        <app1:foo xmlns:app1="http://app1.org/app1/">..</app1:foo>
        <app2:bar xmlns:app2="http://app1.org/app2/">..</app2:bar>
    </metadata>
    ...

其中,type是虛擬化類型,其值可以是kvm, xen, qemu, lxc, kqemu等。id是標識正在運行的虛擬機,可以省略。

  • name

虛擬機的名字,可以由數字、字母、中橫線和下劃線組成。

  • uuid

虛擬機的全局唯一標識,可以用uuidgen命令生成。如果在定義(define)或創建(create)虛擬機實例時省略,系統會自動分配一個隨機值這個實例。

  • title, description

這兩個東西都可以省略,見名知義,如果有特殊需求可以加上。

  • metadata

metadata可以被應用(applications)以xml格式來存放自定義的metadata,該項也可以省略。

操作系統啓動區域

    ...
    <os>
        <type arch='x86_64' machine='pc'>hvm</type>
        <boot dev='hd'/>
        <bootmenu enable='yes'/>
        <kernel>/var/instances/instance-hostname/kernel</kernel>
        <initrd>/var/instances/instance-hostname/ramdisk</initrd>
        <cmdline>root=/dev/vda console=ttyS0</cmdline>
    </os>
    ...
  • type

虛擬機啓動的操作系統類型,hvm表示操作系統是在裸設備上運行的,需要完全虛擬化。

  • boot

boot屬性的值可以是fd, hd, cdrom, network等,用來定義下一個啓動方式(啓動順序)。該屬性可以有多個。

  • bootmenu

在虛擬機啓動時是否彈出啓動菜單,該屬性缺省是彈出啓動菜單。

  • kernel

內核鏡像文件的絕對路徑。

  • initrd

ramdisk鏡像文件的絕對路徑,該屬性是可選的。

  • cmdline

這個屬性主要是在內核啓動時傳遞一些參數給它。

內存和CPU區域

  ...
    <vcpu placement='static' cpuset="1-4,^3,6" current="1">2</vcpu>
    <memory unit='KiB'>2097152</memory>
    <currentMemory unit='KiB'>2000000</currentMemory>
  ...
  • vcpu

vcpu屬性表示分配給虛擬機實例的最大CPU個數。其中cpuset表示該vcpu可以運行在哪個物理CPU上面,一般如果設置cpuset,那麼placement就設置成static。current的意思是是否允許虛擬機使用較少的CPU個數(current can be used to specify whether fewer than the maximum number of virtual CPUs should be enabled)。vcpu下面的這幾個屬性貌似只在kvm與qemu中有。

  • memory

memory表示分配給虛擬機實例的最大內存大小。unit是內存的計算單位,可以是KB, KiB, MB, MiB,默認爲Kib。(1KB=10^3bytes,1KiB=2^10bytes)

  • currentMemory

currentMemory表示實際分配給虛擬實例的內存,該值可以比memory的值小。

磁盤區域

...
<devices>
    <emulator>/usr/bin/kvm</emulator>

    <disk type='file' device='disk'>
        <source file='/var/instances/instance-hostname/disk' />
        <target dev='vda' bus='ide' />
    </disk>

    <disk type='file' device='disk'>
        <driver name='qemu' type='raw'/>
        <source file='/var/instances/instance-hostname/disk.raw'/>
        <target dev='vda' bus='virtio'/>
        <alias name='virtio-disk0'/>
        <address type='pci' domain='0x0000' bus='0x00' slot='0x04' function='0x0'/>
    </disk>

    <disk type='block' device='disk'>
        <driver name='qemu' type='raw'/>
        <source dev='/dev/sdc'/>
        <geometry cyls='16383' heads='16' secs='63' trans='lba'/>
        <blockio logical_block_size='512' physical_block_size='4096'/>
        <target dev='hda' bus='ide'/>
    </disk>
</devices>
...
  • emulator

模擬器的二進制文件全路徑。

  • disk

定義單塊虛擬機實例上的磁盤。

type 可以是block, file, dir, network。分別表示什麼意思就不多說了。

device 表示該磁盤以什麼形式暴露給虛擬機實例,可以是disk, floppy, cdrom, lun,默認爲disk。

  • driver

可以定義對disk更爲詳細的使用結節。

  • source

定義磁盤的源地址,由type來確定該值應該是文件、目錄或設備地址。

  • target

控制着磁盤的bus/device以什麼方式暴露給虛擬機實例,可以是ide, scsi, virtio, sen, usb, sata等,如果未設置的系統會自動根據設備名字來確定。如: 設備名字爲hda那麼就是ide。

  • mirror

這個mirror屬性比較牛B,可以將虛擬機實例的某個盤做鏡像,具體不細說了。

網絡接口區域

...
<devices>
    <interface type='bridge'>
        <source bridge='br0'/>
        <mac address='00:16:3e:5d:c7:9e'/>
        <model type='virtio'/>
    </interface>
</devices>
...

以上內容就不多解釋了,看名知義。

相關事件的配置

    ...
    <on_poweroff>destroy</on_poweroff>
    <on_reboot>restart</on_reboot>
    <on_crash>restart</on_crash>
    <on_lockfailure>poweroff</on_lockfailure>
    ...
  • on_poweroff, on_reboot, on_crash

其屬性值爲遇到這三項時進行的操作,可以是以下操作:

destroy 虛擬機實例完全終止並且釋放所佔資源。
restart 虛擬機實例終止並以相同配置重新啓動。
preserve 虛擬機實例終止,但其所佔資源保留來做進一步的分析。
rename-restart 虛擬機實例終止並且以一個新名字來重新啓動。

on_crash 還支持以下操作:

coredump-destroy crash的虛擬機實例會發生coredump,然後該實例完全終止並釋放所佔資源。
coredump-restart crash的虛擬機實例會發生coredump,然後該實例會重新啓動。

  • on_lockfailure(我對這個不瞭解)

當鎖管理器(lock manager)失去對資源的控制時(lose resource locks)所採取的操作:

poweroff 虛擬機實例被強制停止。
restart 虛擬機實例被停止後再啓動來重新獲取它的鎖(locks)。
pause 虛擬機實例會被暫停,並且當你解決了鎖(lock)問題後可以將其手動恢復運行。
ignore 讓虛擬機實例繼續運行,彷彿一切都沒發生過。

時間區域

<clock offset='localtime'/>

offset支持utc, localtime, timezone, variable等四個值,表示虛擬機實例以什麼方式與宿主機同步時間。(並不是所有虛擬化技術都支持這些模式)

圖形管理接口

...
<devices>
    <graphics type='vnc' port='5904'>
        <listen type='address' address='1.2.3.4'/>
    </graphics>
    <graphics type='vnc' port='-1' autoport='yes' keymap='en-us' listen='0.0.0.0'/>
</devices>
...

type爲管理類型,可以是VNC,rdp等。其中port可以自動分配(從5900開始分配)。

日誌記錄

...
<devices>
    <console type='stdio'>
        <target port='1'/>
    </console>
    <serial type="file">
        <source path='/var/instances/instance-hostname/console.log'/>
        <target port="1"/>
    </serial>
</devices>
...

以上意思是禁止字符設備的輸入,並將其輸出定向到虛擬機的日誌文件中(domain log)。將設備的日誌寫到一個文件裏(Device log),比如:開機時的屏幕輸出。

如你所想,libvirt的XML配置文件不可能就這麼項內容,還有很多很多配置及詳細配置,我在此不寫出了,想深入瞭解的話可以看參考資料部分。

使用示例

鏡像文件及XML文件位置: /var/instances/base ,要創建的虛擬機位置: /var/instances/instance-name/,操作步驟如下:

# cd /var/instances/base
# ls
ubuntu.final.img  ramdisk  kernel  instance-name.xml
# cp -rf /var/instances/base /var/instances/instance-host180
# cd /var/instances/instance-host180
# mount -o loop ubuntu.final.img /mnt
# vim /mnt/etc/network/interfaces
edit eth0 and eth1 section
CentOS interface file: /etc/sysconfig/network-scripts/ifcfg-eth0[1]
# umount /mnt
# mv instance-name.xml instance-host180.xml
# vim instance-host180.xml
edit some sections of this XML file
# virsh define instance-host180.xml
# virsh create instance-host180.xml
# virsh autostart host180

經過以上幾步,一臺虛擬機就創建OK了。當然如果虛擬機使用DHCP方式來獲取IP的話,就根本不用修改網卡配置文件。

其他說明

本文檔同級目錄下有一個XML文件模板,可以參考一下。

這個文檔是step by step,注重操作和使用。我當時就是這樣一步步學習的,當使用熟練之後可以進行更深入的研究學習。

新加內容

主要是關於rawqcow2格式的相互轉換及文件大小壓縮相關。

擴大raw或qcow2格式文件

改變raw或qcow2格式的文件大小。

# virt-filesystems --long -h --all -a old.file.raw
Name       Type        VFS   Label  MBR  Size  Parent
/dev/sda1  filesystem  ext4  -      -    10G   -
/dev/sda1  partition   -     -      83   10G   /dev/sda
/dev/sda   device      -     -      -    10G   -
# truncate -r old.file.raw new.file.raw
# truncate -s +5G new.file.raw
# virt-resize --expand /dev/sda1 old.file.raw new.file.raw

the other way

# virt-filesystems --long -h --all -a old.file.raw
Name       Type        VFS   Label  MBR  Size  Parent
/dev/sda1  filesystem  ext4  -      -    10G   -
/dev/sda1  partition   -     -      83   10G   /dev/sda
/dev/sda   device      -     -      -    10G   -
# cp -pf old.file.raw new.file.raw
# qemu-img resize new.file.raw +2G
# virt-resize --expand /dev/sda1 old.file.raw new.file.raw

掛載qcow2或raw格式文件

用libguestfs掛載qcow2和raw格式的文件

# guestmount -a disk.file -i /mnt

壓縮qcow2或raw格式文件的大小

  • 壓縮qcow2格式的文件
# virt-sparsify --compress --convert qcow2 --format qcow2 input.qcow2 output.qcow2
  • raw格式的文件不支持壓縮,但是可以縮小

raw格式文件整起來比較費勁,這裏我只做當raw文件是一個ext4文件系統的情況。

# qemu-img create disk.final.raw 10G
# // dd if=/dev/zero of=disk.final.raw bs=512 seek=1000000
# mkfs.ext3 -Fq disk.final.raw
# mount -o loop disk.origin.raw /origin
# mount -o loop disk.final.raw /final
# cp -arf /origin/* /final/*
# umount /final
# umount /origin

參考資料

1.Libvirt Domain XML format: http://libvirt.org/formatdomain.html
2.OpenStack Creating custom images: http://docs.openstack.org/trunk/openstack-compute/admin/content/creating-custom-images.html

發佈了14 篇原創文章 · 獲贊 8 · 訪問量 10萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章