标签:
本系列文章会总结 QEMU/KVM 和 Ceph 之间的整合:
(1)QEMU-KVM 和 Ceph RBD 的 缓存机制总结
(2)QEMU 的 RBD 块驱动(block driver)
这篇文章分析一下一个 Ceph RBD 卷是如何被映射到一个 QEMU/KVM 客户机的,以及客户机中设备的命名问题。
挂接一个卷:
#运行nova-attach 命令
nova volume-attach INSTANCE_ID VOLUME_ID auto
#在虚机中操作
vm$ ls /dev/disk/by-id/ virtio-15a9f901-ba9d-45e1-8 vm$ mkfs.ext4 /dev/disk/by-id/virtio-15a9f901-ba9d-45e1-8 vm$ mkdir -p /mnt/volume vm$ mount /dev/disk/by-id/virtio-15a9f901-ba9d-45e1-8 /mnt/volume vm$ echo "Hello OpenStack" > /mnt/volume/test.txt
卸载一个卷:
#在虚机中操作
vm$ umount /mnt/volume
#运行 Nova 命令 $ nova volume-detach <instanceid> <volumeid>
Nova 的 volume-attach 命令为:
root@hkg02kvm004ccz023:~# nova help volume-attach usage: nova volume-attach <server> <volume> [<device>] Attach a volume to a server. Positional arguments: <server> Name or ID of server. <volume> ID of the volume to attach. <device> Name of the device e.g. /dev/vdb. Use "auto" for autoassign (if supported). Libvirt driver will use default device name.
命令:
root@hkg02kvm004ccz023:~# nova volume-attach ap-uplthyfxulbx 8a309ad1-369c-483b-9a95-e4f330bb104e /dev/vdh +----------+--------------------------------------+ | Property | Value | +----------+--------------------------------------+ | device | /dev/vdh |
虚机中:
[root@ap-4oe4-4rz25pvadal7-cs7nmsu4izfy-server-uplthyfxulbx rules.d]# fdisk -l Disk /dev/vda: 42.9 GB, 42949672960 bytes ... Disk /dev/vdb: 1073 MB, 1073741824 bytes ... Disk /dev/vdc: 2147 MB, 2147483648 bytes ... Disk /dev/vdd: 3221 MB, 3221225472 bytes ...
比如通过以下步骤来重现:
整个过程涉及到以下一些模块:
udev 是 Linux 内核的设备管理器(device manager),它主要是负责管理 /dev 目录中的设备节点(device nodes)和 /dev/disk 子目录中的与设备 ID 相关的的符号连接文件。当新的硬件设备(hardware devices)加入系统或者从系统删除时,Linux 内核通过 netlink socket 通知 udev,然后 udev 根据存在的 udev rules 来做相应的处理,默认地,它会在 /dev 目录中创建或者删除设备节点。
从下面的输出可以看出,内核分配的 device name 为 vdb,它是一个 block 设备,其父设备为 virtio,驱动为 virtio-blk,它属于 pci 设备类别。
[root@ap-4oe4-4rz25pvadal7-cs7nmsu4izfy-server-uplthyfxulbx ibmcloud]# udevadm info -a -n /dev/vdb looking at device ‘/devices/pci0000:00/0000:00:07.0/virtio3/block/vdb‘: KERNEL=="vdb" SUBSYSTEM=="block" DRIVER=="" ... looking at parent device ‘/devices/pci0000:00/0000:00:07.0/virtio3‘: KERNELS=="virtio3" SUBSYSTEMS=="virtio" DRIVERS=="virtio_blk" ... looking at parent device ‘/devices/pci0000:00/0000:00:07.0‘: KERNELS=="0000:00:07.0" SUBSYSTEMS=="pci" DRIVERS=="virtio-pci" ... looking at parent device ‘/devices/pci0000:00‘: KERNELS=="pci0000:00" SUBSYSTEMS=="" DRIVERS==""
udev rules 由在 /lib/udev/rules.d 目录中的文件来定义。通过这些文件,你可以做到:
可见,udev 在收到 linux 内核发来的消息后,首先会查找 udev rules:如果存在,则执行其中定义的操作;如果不存在,则执行默认的操作,即使用 linux kernel 分配的默认名称来创建一个 device node。
关于 udev rules 的详细信息,以及如何创建新的 rules,可以参考 http://www.reactivated.net/writing_udev_rules.html。
#删除设备时
KERNEL[1458809817.791365] remove /devices/virtual/bdi/252:48 (bdi) UDEV [1458809817.791426] remove /devices/virtual/bdi/252:48 (bdi) KERNEL[1458809817.791447] remove /devices/pci0000:00/0000:00:0a.0/virtio5/block/vdd (block) UDEV [1458809817.791485] remove /devices/pci0000:00/0000:00:0a.0/virtio5/block/vdd (block) KERNEL[1458809817.795016] remove /devices/pci0000:00/0000:00:0a.0/virtio5 (virtio) UDEV [1458809817.796617] remove /devices/pci0000:00/0000:00:0a.0/virtio5 (virtio) KERNEL[1458809817.796695] remove /devices/pci0000:00/0000:00:0a.0 (pci) KERNEL[1458809817.796871] remove /devices/LNXSYSTM:00/LNXSYBUS:00/PNP0A03:00/device:24 (acpi) UDEV [1458809817.797283] remove /devices/pci0000:00/0000:00:0a.0 (pci) UDEV [1458809817.797301] remove /devices/LNXSYSTM:00/LNXSYBUS:00/PNP0A03:00/device:24 (acpi) #添加设备时 KERNEL[1458809874.181538] remove /devices/LNXSYSTM:00/LNXSYBUS:00/PNP0A03:00/device:0c (acpi) KERNEL[1458809874.182088] add /devices/LNXSYSTM:00/LNXSYBUS:00/PNP0A03:00/device:25 (acpi) UDEV [1458809874.182104] remove /devices/LNXSYSTM:00/LNXSYBUS:00/PNP0A03:00/device:0c (acpi) UDEV [1458809874.186103] add /devices/LNXSYSTM:00/LNXSYBUS:00/PNP0A03:00/device:25 (acpi) KERNEL[1458809874.234695] add /devices/pci0000:00/0000:00:0b.0 (pci) UDEV [1458809874.238377] add /devices/pci0000:00/0000:00:0b.0 (pci) KERNEL[1458809874.241057] add /devices/pci0000:00/0000:00:0b.0/virtio5 (virtio) UDEV [1458809874.241358] add /devices/pci0000:00/0000:00:0b.0/virtio5 (virtio) KERNEL[1458809874.242006] add /devices/virtual/bdi/252:48 (bdi) UDEV [1458809874.242370] add /devices/virtual/bdi/252:48 (bdi) KERNEL[1458809874.243944] add /devices/pci0000:00/0000:00:0b.0/virtio5/block/vdd (block) UDEV [1458809874.258996] add /devices/pci0000:00/0000:00:0b.0/virtio5/block/vdd (block)
也可以看出,Linux 内核向 udev 传入了该 device 所使用的 device name。
那现在要看的是,客户机的 linux 内核传给 udev 的device name 是它自己产生的,还是由 QEMU/KVM 传入的。
<disk type=‘network‘ device=‘disk‘> <driver name=‘qemu‘ type=‘raw‘ cache=‘writeback‘/> ... <target dev=‘vdb‘ bus=‘virtio‘/> <serial>6e5424e4-4e4c-4178-a4cc-e63698716e9b</serial> <alias name=‘virtio-disk1‘/> <address type=‘pci‘ domain=‘0x0000‘ bus=‘0x00‘ slot=‘0x06‘ function=‘0x0‘/> </disk>
-drive file=rbd:default/volume-6e5424e4-4e4c-4178-a4cc-e63698716e9b:id=cinder:key=AQBM+qVWdTNYKhAAMwULMEcH7TOIcVNyKjIaIg==:
auth_supported=cephx\;none:mon_host=10.110.156.54\:6789\;10.110.156.55\:6789\;10.110.156.56\:6789,if=none,id=drive-virtio-disk1,
format=raw,serial=6e5424e4-4e4c-4178-a4cc-e63698716e9b,cache=writeback -device virtio-blk-pci,scsi=off,bus=pci.0,addr=0x6,
drive=drive-virtio-disk1,id=virtio-disk1
其中,选项 ‘-device‘ 指定了前端的设备类型,而 ‘-drive‘ 选项定义了后端存储,并且通过设备的‘drive‘属性把设备和存储关联起来。
这里没有看到 dev =‘vdb‘ 相关的设置,初步推断,KVM 目前不支持执行虚机中的 device name(是不是结论,还需要进一步研究)。
Linux 中,每个磁盘由一个 major number 和 一个 minor number 共同组成其 device name 来唯一标识它。以下图为例,/dev/vd{a,b,c,d}表示四个磁盘,/dev/vda1 表示磁盘 /dev/vda 的第一个分区。
[root@ap-4oe4-4rz25pvadal7-cs7nmsu4izfy-server-uplthyfxulbx rules.d]# fdisk -l Disk /dev/vda: 42.9 GB, 42949672960 bytes ... Device Boot Start End Blocks Id System /dev/vda1 * 6 238312 41941888 83 Linux Disk /dev/vdb: 1073 MB, 1073741824 bytes ... Disk /dev/vdc: 2147 MB, 2147483648 bytes ... Disk /dev/vdd: 3221 MB, 3221225472 bytes ...
vda 设备的属性如下,其中可以看到 major number 和 minor number,以及 device name:
[ibmcloud@ap-4oe4-4rz25pvadal7-cs7nmsu4izfy-server-uplthyfxulbx rules.d]$ sudo udevadm info --query=all --name=/dev/vda P: /devices/pci0000:00/0000:00:04.0/virtio1/block/vda N: vda W: 4 S: block/252:0 S: disk/by-path/pci-0000:00:04.0-virtio-pci-virtio1 E: UDEV_LOG=3 E: DEVPATH=/devices/pci0000:00/0000:00:04.0/virtio1/block/vda E: MAJOR=252 E: MINOR=0 E: DEVNAME=/dev/vda E: DEVTYPE=disk E: SUBSYSTEM=block E: ID_PATH=pci-0000:00:04.0-virtio-pci-virtio1 E: ID_PART_TABLE_TYPE=dos E: LVM_SBIN_PATH=/sbin E: DEVLINKS=/dev/block/252:0 /dev/disk/by-path/pci-0000:00:04.0-virtio-pci-virtio1
而 Linux 内核是在检测到每一个磁盘的时候来分配这两个数字的,包括系统启动和新设备加入以后,DEVNAME 和这两个数字是直接相关的。因此,每个disk 的 device name 不是持久的 (persistent),而是可变的。
udevadm info 命令输出的各个参数,都可以作为 udev rules 的过滤条件来定位到某一个 device,并给它命名为一个非默认名字。
Linux 系统中,udev 负责根据 udev rules 维护如下几个目录中的系统连接符:
[ibmcloud@ap-4oe4-4rz25pvadal7-cs7nmsu4izfy-server-uplthyfxulbx ~]$ ls -l /dev/disk total 0 drwxr-xr-x 2 root root 100 Mar 27 07:16 by-id drwxr-xr-x 2 root root 140 Mar 27 07:16 by-path drwxr-xr-x 2 root root 80 Mar 27 07:16 by-uuid
[ibmcloud@ap-4oe4-4rz25pvadal7-cs7nmsu4izfy-server-uplthyfxulbx ~]$ ls -l /dev/disk/by-uuid/ total 0 lrwxrwxrwx 1 root root 10 Mar 27 07:16 002f642d-f277-49fd-b5ff-47a652b63fe3 -> ../../vda1 lrwxrwxrwx 1 root root 9 Mar 27 07:16 1655a8ca-9627-4a81-acca-79fec66e1131 -> ../../vdb
UUID 是给每一个文件系统分配一个唯一标识符的机制。这些标识符是被文件系统工具在分区被格式化的时候产生的,比如 mkfs.*。
[ibmcloud@ap-4oe4-4rz25pvadal7-cs7nmsu4izfy-server-uplthyfxulbx ~]$ ls -l /dev/disk/by-id/
total 0
lrwxrwxrwx 1 root root 9 Mar 27 07:16 virtio-6e5424e4-4e4c-4178-a -> ../../vdb
lrwxrwxrwx 1 root root 9 Mar 27 07:16 virtio-8a309ad1-369c-483b-9 -> ../../vdd
lrwxrwxrwx 1 root root 9 Mar 27 07:16 virtio-e4585a93-9a90-4967-8 -> ../../vdc
ID 是依赖于硬件的序列号(hardware serial number)产生的。该 ID 是持久的、与系统无关的、SCSI 标准强制要求的、与设备而不是其中保存的数据比如文件系统相关的 ID。
当该设备是由 cinder volume 挂接而来时,可以看出 device id 和 volume id 的映射关系:
root@hkg02kvm004ccz023:~# cinder list | grep 6e5424e4-4e4c-4178-a | 6e5424e4-4e4c-4178-a4cc-e63698716e9b | in-use | sammyvol3 | 2 | None | false | 9ca18b9e-aeef-44ff-81ba-87a59a0c8eec |
这也证明了 ID 只和 device (volume)相关。
查看 /lib/udev/rules.d/60-persistent-storage.rules 文件中的 virtio-blk 部分:
# virtio-blk KERNEL=="vd*[!0-9]", ATTRS{serial}=="?*", ENV{ID_SERIAL}="$attr{serial}", SYMLINK+="disk/by-id/virtio-$env{ID_SERIAL}" KERNEL=="vd*[0-9]", ATTRS{serial}=="?*", ENV{ID_SERIAL}="$attr{serial}", SYMLINK+="disk/by-id/virtio-$env{ID_SERIAL}-part%n"
比较奇怪的是,vda 怎么没出现在列表中。vda 是宿主机上一个镜像文件挂接而来的:
<disk type=‘file‘ device=‘disk‘> <driver name=‘qemu‘ type=‘qcow2‘ cache=‘none‘/> <source file=‘/opt/stack/data/nova/instances/9ca18b9e-aeef-44ff-81ba-87a59a0c8eec/disk‘/> <target dev=‘vda‘ bus=‘virtio‘/> <alias name=‘virtio-disk0‘/> <address type=‘pci‘ domain=‘0x0000‘ bus=‘0x00‘ slot=‘0x04‘ function=‘0x0‘/> </disk>
它的 udev 属性中 ID_SERIAL 的值为空 (ATTR{serial}=="") (sudo udevadm info --query=all --name=/dev/vda)。这是为什么呢?需要进一步研究。
[ibmcloud@ap-4oe4-4rz25pvadal7-cs7nmsu4izfy-server-uplthyfxulbx ~]$ ls -l /dev/disk/by-path/ total 0 lrwxrwxrwx 1 root root 9 Mar 27 07:16 pci-0000:00:04.0-virtio-pci-virtio1 -> ../../vda lrwxrwxrwx 1 root root 10 Mar 27 07:16 pci-0000:00:04.0-virtio-pci-virtio1-part1 -> ../../vda1 lrwxrwxrwx 1 root root 9 Mar 27 07:16 pci-0000:00:06.0-virtio-pci-virtio3 -> ../../vdb lrwxrwxrwx 1 root root 9 Mar 27 07:16 pci-0000:00:07.0-virtio-pci-virtio4 -> ../../vdc lrwxrwxrwx 1 root root 9 Mar 27 07:16 pci-0000:00:08.0-virtio-pci-virtio5 -> ../../vdd
该 path 和设备的最短物理访问路径(shortest physical path)有关,包括 SCSI host, channel, target, LUN numbers 以及可能得 partition number.等。需要注意的是,这里的硬件访问路径有可能变化,比如 pci slot 改变后。
看看 path 相关的 udev rules:
# by-path (parent device path) ENV{DEVTYPE}=="disk", ENV{ID_PATH}=="", IMPORT{program}="path_id %p" ENV{DEVTYPE}=="disk", ENV{ID_PATH}=="?*", SYMLINK+="disk/by-path/$env{ID_PATH}" ENV{DEVTYPE}=="partition", ENV{ID_PATH}=="?*", SYMLINK+="disk/by-path/$env{ID_PATH}-part%n"
理解 QEMU/KVM 和 Ceph(3):存储卷挂接和设备名称
标签:
原文地址:http://www.cnblogs.com/sammyliu/p/5325492.html