专栏首页yuncoderLibvirt磁盘锁-sanlock

Libvirt磁盘锁-sanlock

本文之前在腾讯云tstack上已经发布过了https://cloud.tencent.com/developer/article/1658665,此处自己记录保留一份。

在云中使用虚拟机HA,热迁移等功能的时候,可能会出现两个主机上的虚拟机同时对共享存储上同一个磁盘进行读写操作,导致磁盘数据损坏的问题。Libvirt提供了两种方式实现磁盘资源的互斥,分别是sanlocklockd。相关的配置可以参考文档: https://libvirt.org/locking.html,本篇描述libvirt使用sanlock作为磁盘锁的使用方法。

关于sanlock的基本用法可以参考我之前的一篇文章: https://cloud.tencent.com/developer/article/1651000

1. 安装与配置

1.1 安装sanlock

sanlock用于实现libvirt磁盘锁的具体配置参考文档 https://libvirt.org/locking-sanlock.html

安装 libvirt sanlock 插件

[root@compute01 ~]# yum install libvirt-lock-sanlock

关闭firewall和selinux

# 关闭防火墙
[root@compute01 ~]# systemctl stop firewalld
[root@compute01 ~]# systemctl disable firewalld

# 关闭selinux
[root@compute01 ~]# setenforce 0
[root@compute01 ~]# sed -i 's/SELINUX=enforcing/SELINUX=disabled/g' /etc/selinux/config

启动sanlock与wdmd服务,sanlock通过wdmd(watchdog multiplexing daemon)与watchdog建立连接,如果sanlock服务崩溃或异常终止,将会导致整个主机重新启动

# 启动sanlock
[root@compute01 ~]# systemctl enable sanlock
[root@compute01 ~]# systemctl start sanlock

# 启动wdmd
[root@compute01 ~]# systemctl enable wdmd
[root@compute01 ~]# systemctl start wdmd

查看启动sanlock守护进程使用的用户和组,后续会使用到该用户和组信息,这里只看父进程号为1的sanlock进程的信息,即进程2930所属的用户和组均为sanlock

[root@compute01 ~]# ps xao pid,ppid,group,user,command | grep sanlock
 2930     1 sanlock  sanlock  /usr/sbin/sanlock daemon
 2932  2930 root     root     /usr/sbin/sanlock daemon
11336  3648 root     root     grep --color=auto sanlock

1.2 准备sanlock需要的共享存储

默认libvirt使用sanlock时,要求共享存储路径为/var/lib/libvirt/sanlock,该路径可以通过修改配置文件/etc/libvirt/qemu-sanlock.conf中的disk_lease_dir选项进行修改。共享存储可以采用NFS或者cephfs等,此处不提供共享存储的搭建步骤。

sanlock守护进程需要访问共享存储,从前面得知sanlock守护进程所属的用户和组均为sanlock,所以此处需要修改nfs共享存储挂载路径所属的用户和组为sanlock

[root@compute01 ~]# chown -R sanlock:sanlock /var/lib/libvirt/sanlock

1.3 配置libvirt使用sanlock

修改配置文件/etc/libvirt/qemu.conf,配置libvirt lock_manager使用sanlock

lock_manager = "sanlock"

编辑配置/etc/libvirt/qemu-sanlock.conf,配置sanlock

# 值为1表示采用自动加锁,即对虚拟机的每个磁盘都进行自动加锁处理
# 值为0表示关闭自动加锁,加锁操作需要在虚拟机xml文件中实现
auto_disk_leases = 1

# 为当前主机分配一个1~2000的唯一值,该值在所有加入sanlock集群的主机中唯一
host_id = 1

# 运行sanlock守护进程的用户和组,从前面得知user和group均为sanlock
user = "sanlock"
group = "sanlock"

重启libvirtd服务

[root@compute01 ~]# systemctl restart libvirtd

libvirtd服务重启完成,在共享存储挂载的路径下会自动创建出名为__LIBVIRT__DISKS__的文件,该文件是用于管理主机的文件,如果没有该文件,则说明前面的配置存在问题

[root@compute01 ~]# ll /var/lib/libvirt/sanlock/
total 1024
-rw-r----- 1 sanlock sanlock 1048576 Dec  9 03:48 __LIBVIRT__DISKS__

[root@compute01 ~]# sanlock direct dump /var/lib/libvirt/sanlock/__LIBVIRT__DISKS__
  offset                            lockspace                                             resource  timestamp  own  gen lver
00000000                   __LIBVIRT__DISKS__      9711d473-6095-46db-a37d-407372bd2612.centos-san 0000002853 0001 0001

2. 磁盘位于NFS共享存储

本节验证虚拟机磁盘位于NFS共享存储时,sanlock对磁盘加锁的情况。测试方法为在计算节点1和计算节点2上分别启动一个虚拟机来进行测试,两个主机上的虚拟机系统盘均为NFS共享存储上的同一个磁盘。

准备虚拟机系统盘文件,此处采用cirros镜像,在计算节点1上执行下面的命令下载cirros镜像,并将其置于共享存储上

[root@compute01 ~]# wget http://download.cirros-cloud.net/0.3.4/cirros-0.3.4-x86_64-disk.img

# 将下载的虚拟机磁盘文件移动到共享存储上
[root@compute01 ~]# cp cirros-0.3.4-x86_64-disk.img /var/lib/libvirt/sanlock/cirros.disk

在计算节点1上通过下面的命令创建虚拟机

[root@compute01 ~]# virt-install --import \
--name cirros-vm --vcpus 1 --memory 64 \
--disk /var/lib/libvirt/sanlock/cirros.disk,format=qcow2,bus=virtio \
--network bridge=virbr0,model=virtio \
--graphics vnc,listen=0.0.0.0 \
--console pty,target_type=virtio

# 虚拟机创建并运行成功
[root@compute01 ~]# virsh list
Id    Name                           State
----------------------------------------------------
1     cirros-vm                      running

查看共享存储路径下,可以发现自动生成了一个以md5值命名的文件,该文件即为磁盘/var/lib/libvirt/sanlock/cirros.disk的锁文件,文件名的md5值即为磁盘全路径字符串的md5值

[root@compute01 ~]# ll /var/lib/libvirt/sanlock
total 15028
-rw------- 1 sanlock sanlock  1048576 Dec  9 04:39 0f2d1b2c88ac72e97d4a9c4d13fe4db0
-rw-r--r-- 1 qemu    qemu    13287936 Dec  9 04:38 cirros.disk
-rw-rw---- 1 sanlock sanlock  1048576 Dec  9 04:39 __LIBVIRT__DISKS__

# 计算磁盘全路径的md5值,可以看到文件名即为磁盘全路径的md5值
[root@compute01 ~]# python -c "import hashlib; print hashlib.md5('/var/lib/libvirt/sanlock/cirros.disk').hexdigest()"
0f2d1b2c88ac72e97d4a9c4d13fe4db0

通过sanlock direct dump命令查看磁盘锁文件中的内容,own为0001,即编号为1的主机,timestamp不为0,说明此时主机1获得了对磁盘/var/lib/libvirt/sanlock/cirros.disk的租期

[root@compute01 ~]# sanlock direct dump /var/lib/libvirt/sanlock/0f2d1b2c88ac72e97d4a9c4d13fe4db0
  offset                            lockspace                                         resource  timestamp  own  gen lver
00000000                   __LIBVIRT__DISKS__                 0f2d1b2c88ac72e97d4a9c4d13fe4db0 0000005856 0001 0001 1

尝试在计算节点2上用相同的命令创建虚拟机,从命令输出中可知获取磁盘的写锁失败了,此结果说明sanlock有效的解决了多个虚拟机同时对一个磁盘进行读写的问题

[root@compute02 ~]# virt-install --import \
--name cirros-vm --vcpus 1 --memory 64 \
--disk /var/lib/libvirt/sanlock/cirros.disk,format=qcow2,bus=virtio \
--network bridge=virbr0,model=virtio \
--graphics vnc,listen=0.0.0.0 \
--console pty,target_type=virtio

Starting install...
ERROR    internal error: process exited while connecting to monitor: 2019-12-09T11:07:18.947726Z qemu-kvm: -drive file=/var/lib/libvirt/sanlock/cirros.disk,format=qcow2,if=none,id=drive-virtio-disk0: Failed to get "write" lock
Is another process using the image [/var/lib/libvirt/sanlock/cirros.disk]?
Domain installation does not appear to have been successful.
If it was, you can restart your domain by running:
virsh --connect qemu:///system start cirros-vm
otherwise, please restart your installation.

在计算节点1上关闭cirros-vm

[root@compute01 ~]# virsh destroy cirros-vm
Domain cirros-vm destroyed

# 从磁盘锁文件的内容可知,timestamp被置为0,租期释放
[root@compute01 ~]# sanlock direct dump /var/lib/libvirt/sanlock/0f2d1b2c88ac72e97d4a9c4d13fe4db0
  offset                            lockspace                                             resource  timestamp  own  gen lver
00000000                   __LIBVIRT__DISKS__                     0f2d1b2c88ac72e97d4a9c4d13fe4db0 0000000000 0001 0001 1

在计算节点2上重启创建虚拟机cirros-vm成功

[root@compute02 ~]# virt-install --import \
--name cirros-vm --vcpus 1 --memory 64 \
--disk /var/lib/libvirt/sanlock/cirros.disk,format=qcow2,bus=virtio \
--network bridge=virbr0,model=virtio \
--graphics vnc,listen=0.0.0.0 \
--console pty,target_type=virtio

[root@compute02 ~]# virsh list
Id    Name                           State
----------------------------------------------------
2     cirros-vm                      running

# 查看租期文件,own为0002,timestamp不为0,即主机2获得了磁盘租期
[root@compute02 ~]# sanlock direct dump /var/lib/libvirt/sanlock/0f2d1b2c88ac72e97d4a9c4d13fe4db0
  offset                            lockspace                                         resource  timestamp  own  gen lver
00000000                   __LIBVIRT__DISKS__                 0f2d1b2c88ac72e97d4a9c4d13fe4db0 0000007694 0002 0001 2

在计算节点1上启动cirros-vm,从输出信息可知启动失败的原因是获取lock失败

[root@compute01 ~]# virsh start cirros-vm
error: Failed to start domain cirros-vm
error: internal error: process exited while connecting to monitor: 2019-12-09T11:18:18.811215Z qemu-kvm: -drive file=/var/lib/libvirt/sanlock/cirros.disk,format=qcow2,if=none,id=drive-virtio-disk0: Failed to get "write" lock
Is another process using the image [/var/lib/libvirt/sanlock/cirros.disk]?

3. 问题

当虚拟机被删除后,位于/var/lib/libvirt/sanlock目录下自动创建的锁文件将会残留,长时间会占用大量的磁盘空间,因此必须要定期对这些自动创建的锁文件进行清理,可以通过下面的命令完成清理操作,通过定时任务每周执行一次即可

# virt-sanlock-cleanup对资源租期文件的清理原理利用了资源租期,即尝试获取目标资源的租期
# 如果获取成功,则对目标资源执行rm -f操作,如果获取失败,则资源租期文件不会被删除,命令如下:
#    sanlock client command -r $RESOURCE -c /bin/rm -f "$LOCKDIR/$MD5"

# 在前面的例子中,$RESOURCE的值为__LIBVIRT__DISKS__:0f2d1b2c88ac72e97d4a9c4d13fe4db0
# :/var/lib/libvirt/sanlock/0f2d1b2c88ac72e97d4a9c4d13fe4db0:0,$LOCKDIR/$MD5的值
# 为/var/lib/libvirt/sanlock/0f2d1b2c88ac72e97d4a9c4d13fe4db0

[root@compute01 ~]# virt-sanlock-cleanup

到目前为止,初步的学习了sanlock用于libvirt磁盘锁的使用方法,但要将其应用到openstack中管理虚拟机和磁盘,还面临比较多的问题。

前面一直采用的libvirt自动对磁盘进行加锁(即auto_disk_leases=1)操作,在openstack中如果直接使用磁盘自动加锁是有问题的,如:

  • 如果共享存储在不同的计算节点上路径不同,则生成的磁盘锁文件是不同的,会导致对同个磁盘的加锁操作失败;
  • cinder支持多挂载的情况下,如果采用自动加锁则会导致挂载同一个数据盘的多个虚拟机无法启动的问题;
  • 当虚拟机通过config drive进行配置时,实际上config drive创建的磁盘也是不需要进行加锁操作的,因为该磁始终是只读的;

因此在实际将sanlock应用到openstack中实现虚拟机高可用时,不能采用磁盘自动加锁的方式。对残留的资源租期文件清理操作,还需要做到高可用,不能因为单个主机挂掉导致残留资源的清理失效。另外如果openstack环境对接的是Ceph RBD或IPSAN,libvirt目前不支持对ceph rbd的加锁操作,同时虽然支持对通过iscsi挂载到主机上的磁盘进行加锁,但是同一个盘在不同的主机上其挂载路径很可能是不同的,导致磁盘锁无法生效。


参考资料:

原文链接:https://cloud.tencent.com/developer/article/1658665

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 虚拟机总脑裂,写坏磁盘怎么办?

    鹏 飞 专注于OpenStack计算、Python。 热爱大海、雪山。 ? 导 语 在云中使用虚拟机HA,热迁移等功能的时候,可能会出现两个主机上的虚拟机同时...

    腾讯云TStack
  • Sanlock原理与基本使用

    Sanlock是一个基于共享存储的分布式锁管理器,集群中的每个节点都各自运行sanlock服务,锁的状态都被写到了共享存储上,所有节点都能访问共享存储,共同维护...

    jiang
  • qemu-libvirt-磁盘加密

    # qemu-img convert -f qcow2 -O qcow2 -o encryption template.img encry.qcow2

    虚拟化云计算
  • KVM+Qemu+Libvirt实战

    上一篇的文章是为了给这一篇文件提供理论的基础,在这篇文章中我将带大家一起来实现在linux中虚拟出ubuntu的server版来 我们需要用KVM+Qemu+L...

    用户1195962
  • 虚拟化iothread特性

    在现代虚拟化大环境下,主机逐渐向多核多磁盘高性能计算机发展,为了更好的利用多CPU并行能力,磁盘的高速读写能力,如何使虚拟机更好的使用宿舍主机的硬件资源,成了一...

    sidzhan
  • KVM虚拟机安装、管理

    KVM全称Kernel-based Virtual Machine,翻译过来是基于内核的虚拟机,实际它是Linux内核的一个模块。该模块将Linux变为一个Hy...

    用户8704835
  • libvirt-虚拟机qos控制

    libvirt提供了一系列tune的方式,来实现对虚拟机的qos精细控制。下面介绍cpu、内存、磁盘io、网络带宽的qos控制方式。

    虚拟化云计算
  • Linux KVM 安装使用手册

    如果flags: 里有 vmx 或者 svm 就说明支持 VT;如果没有任何的输出,说明你的 cpu 不支持,将无法成功安装 KVM 虚拟机。2. 确保BIOS...

    高楼Zee
  • 测试开发之系统篇-按需创建测试虚拟机

    新建KVM虚拟机时,可以指定另一磁盘文件作为BackingFile。BackingFile是一个只读的虚拟磁盘基础映像,可以在多个虚拟机间进行共享。基于Back...

    陈琦聊测试
  • 虚拟机磁盘加密之LUKS

    LUKS是一种基于device mapper机制的加密方式。使用加密磁盘前要先mapper映射,映射时需要输入密码,写入和读取磁盘时不需要再输入密码。LUKS可...

    虚拟化云计算
  • xen杂记(3)

    连接控制界面: [root@node1 xen]# xl console centos-001

    py3study
  • 基于QMP实现对qemu虚拟机进行交互

    qemu对外提供了一个socket接口,称为qemu monitor,通过该接口,可以对虚拟机实例的整个生命周期进行管理,主要有如下功能

    小慢哥Linux运维
  • KVM虚拟化平台部署及管理

    前言 KVM即Kernel Virtual Machine,最初是由以色列公司Qumranet开发。2007年2月被导入Linux 2.6.20核心中,成为内核...

    小小科
  • Virsh管理kvm虚拟机

    L宝宝聊IT
  • CentOS7环境下使用Cockpit创建KVM虚拟机

    yum -y install qemu-kvm qemu-kvm-tools qemu-img virt-manager libvirt libvirt-pyt...

    yuanfan2012
  • CentOS 6.6下Xen虚拟化实战

    因为从RHEL6版本开始,RedHat就不在原生支持Xen,改为投奔KVM的怀抱。尽管KVM号称支援HVM技术的全虚拟化,但KVM毕竟起步晚,远不如Xen技术成...

    小小科
  • KVM学习及应用的七个阶段

    KVM虚拟化的学习,也可以分为七个阶段,经过七个阶段的学习,就在生产环境中完成虚拟化任务。

    力哥聊运维与云计算
  • KVM存储池和存储卷

    KVM的存储选项有多种,包括虚拟磁盘文件、基于文件系统的存储和基于设备的存储。

    L宝宝聊IT
  • kvm研究和实践

    qemu-kvm 该软件包主要包含KVM内核模块和基于KVM重构后的QEMU模拟器。KVM模块作为整个虚拟化环境的核心工作在系统空间,负责CPU和内存的调度。...

    初心不改

扫码关注云+社区

领取腾讯云代金券