记一次被Multipath坑苦的经历

开发 前端
今天使用Packer制作SUSE镜像,之前磁盘格式使用的是IDE,这次换成SCSI,由于磁盘类型变了,为了保险起见,我重新生成了initramfs加载ahci驱动以支持在引导阶段下加载SATA。

[[377578]]

本文转载自微信公众号「int32bit」,作者int32bit 。转载本文请联系int32bit公众号。

今天使用Packer制作SUSE镜像,之前磁盘格式使用的是IDE,这次换成SCSI,由于磁盘类型变了,为了保险起见,我重新生成了initramfs加载ahci驱动以支持在引导阶段下加载SATA。

  1. BINARY_DEPS="tail head awk ifconfig cut expr route ping nc wget tftp grep"  
  2. DRACUT_DRIVERS="virtio virtio_net virtio_blk"  
  3. dracut -f -N \ 
  4.      --install "$BINARY_DEPS" \ 
  5.      --kernel-cmdline "rd.shell rd.driver.pre=ahci" \ 
  6.      --kver "$(uname -r)" \ 
  7.      --add-drivers "$DRACUT_DRIVERS" \ 
  8.      --add lvm \ 
  9.      --mdadmconf \ 
  10.      --lvmconf \ 
  11.      -o "dash plymouth" \ 
  12.      initrd-$(uname -r) 

至于为什么需要加载lvm模块,这是环境要求根文件系统必须做LVM,在云环境下其实我是非常不推荐使用的。

fstab全部使用块设备UUID而非逻辑卷路径(/dev/sdX),担心逻辑卷路径由于磁盘驱动发生改变,谁知道会不会由/dev/sda1变成/dev/vda1呢。

当时想到这么做一定万无一失了吧,启动虚拟机验证下,结果出人意外,系统进入了emergency模式,幸好我在initramfs中配置了rd.shell,否则就不知道如何进入调试了。

输入root密码进入bash,发现原因是/boot没有挂载上,尝试手动挂载看看啥错误:

  1. mount -a #重新安装fstab挂载卷 

提示设备already mounted or mount point busy。

mount point挂载点/boot肯定是没有被挂载,那肯定就是设备问题,从错误中提示是该磁盘设备已经挂载了,但是无论如何df、lsblk都找不到挂载记录。

尝试各种lsof、fuser命令发现也没有任何进程占用了该设备。

那显然只有一种情况,我猜想这个设备被dm(device mapper)映射了。

使用dmsetup查看所有的dm列表,除了LV映射,果然多了很多0QEMU_QEMU_HARDDISK开头的dm设备:

  1. 0QEMU_QEMU_HARDDISK_bcd82475-9f57-43e6-a-part 

lVM是会被dm映射的,这没有问题,但是/boot是一个物理分区,并没有做PV加到任何VG,那是谁把这个设备dm了呢?

使用dmsetup info查看下线索:

  1. dmsetup info 0QEMU_QEMU_HARDDISK_bcd82475-9f57-43e6-a-part 
  2. Name: 0QEMU_QEMU_HARDDISK_bcd82475-9f57-43e6-a-part 
  3. State: ACTIVE 
  4. Read Ahead: 1024 
  5. Tables present: LIVE 
  6. Major, minor: 254,1 
  7. Number of targets: 1 
  8. UUID: part1-mpath-0QEMU_QEMU_HARDDISK_bcd82475-9f57-43e6-a-part 

其他信息没有什么有用,唯独看到UUID中包含mpath,猜测可能就是由于multipath导致的。

使用multipath -l命令查看果然:

  1. size=40G features='0' hwhandler='0' wp=rw 
  2.   policy='service-time 0' prio=0 status=active 
  3.   2:0:0:0 sda 8:0 active undef running 

居然整个sda都被multipath映射了。

找到原因心想解决思路就明朗了,检查了multipathd服务发现是disabled的,那应该开机是没有启动multipathd服务的。

使用lsmod发现multipath内核模块确实是加载的,难道是其他依赖模块拉起来的?

为了确定是multipath服务导致的,运行如下命令确保multipath是停止的,并且强制把multipath内核模块加到黑名单列表中。

  1. systemctl disable multipathd 
  2. echo "blacklist multipath" >>/etc/modprobe.d/50-blacklist.conf 

并修改了/etc/multipath.conf配置文件显式把sda添加到blacklist中。

  1. blacklist { 
  2.     devnode "^(td|hd|vd)[a-z]" 
  3.     devnode "sda" 

重启虚拟机,结果还是一样的问题,multipath还是坚强地起来了。

难道真的是其他服务把multipath启动的,为了排除这种可能,把/usr/lib/systemd/system/multipathd.service挪走了,这下没有谁能启动这个服务了吧。

重启虚拟机,结果还是令人意外的一样,这个multipath还是起来了,够玄乎。

更绝的我把/sbin/multipath以及/sbin/multipathd都挪走删除了,这让服务再无可能运行了吧。

再次重启虚拟机,让人怀疑人生的是multipathd服务像打不死的小强宁死不屈,依然运行了。

Google倒是找到有类似的问题System exit to emergency shell at boot with multipath enabled (SLES12, MPIO)[1],解决方法也无非是disable multipath服务或者把设备添加到multipath blacklist,但根本没有效果。

在百思不得解的情况下,突然灵光一现,难道是initramfs的问题?这个multipath在initramfs挂载rootfs就已经做过了?

顺着这个思路,唯有重新做initramfs镜像,并把multipath模块加到omit黑名单列表中:

  1. dracut -f -N \ 
  2.      ... 
  3.      -o "... multipath" \ 
  4.      ... 

替换原来的initrd-xxx文件后启动虚拟机,虚拟机终于神奇地启动成功了。

最后归根到底原来是initramfs boot阶段加载了multipath模块,因此在用户态怎么修改禁用multipath都是没用的。后来在SUSE文档中也找到了相关说明:Always Keep the initrd in Synchronization with the System Configuration[2]。

这个问题整整折腾了两个多小时,虽然问题很简单,花了很多时间在OS的trace上,万万没想到initramfs是问题的根源。

参考资料

[1]System exit to emergency shell at boot with multipath enabled (SLES12, MPIO): https://www.suse.com/support/kb/doc/?id=000019607

[2]Always Keep the initrd in Synchronization with the System Configuration: https://documentation.suse.com/sles/15-SP1/html/SLES-all/cha-multipath.html#sec-multipath-planning-initrd

 

责任编辑:武晓燕 来源: int32bit
相关推荐

2013-04-01 10:27:37

程序员失业

2013-01-17 10:31:13

JavaScriptWeb开发firebug

2022-01-07 11:48:59

RabbitMQGolang 项目

2020-11-23 07:13:13

Nodejs源码

2018-12-06 16:25:39

数据库服务器线程池

2020-02-10 10:15:31

技术研发指标

2012-08-28 09:21:59

Ajax查错经历Web

2022-12-17 19:49:37

GCJVM故障

2023-03-31 09:22:40

Hi3861芯片Flash

2019-05-28 11:49:09

2023-03-29 09:36:32

2018-04-28 09:35:46

2021-12-06 19:29:17

LRU内存算法

2014-08-06 11:24:24

Elasticsear劫持挂马

2011-04-13 09:21:30

死锁SQL Server

2016-12-06 09:34:33

线程框架经历

2021-04-13 18:17:48

Hbase集群配置

2021-11-11 16:14:04

Kubernetes

2011-02-22 09:29:23

jQueryJavaScript

2019-03-15 16:20:45

MySQL死锁排查命令
点赞
收藏

51CTO技术栈公众号