点击▲关注 “
IT168企业级
”给公众号置顶
更多精彩 第一时间直达
今天使用Packer制作SUSE镜像,之前磁盘格式使用的是IDE,这次换成SCSI,由于磁盘类型变了,为了保险起见,我重新生成了initramfs加载ahci驱动以支持在引导阶段下加载SATA。
BINARY_DEPS=
"tail head awk ifconfig cut expr route ping nc wget tftp grep"
DRACUT_DRIVERS=
"virtio virtio_net virtio_blk"
dracut -f -N
--install
"
$BINARY_DEPS"
--kernel-cmdline
"rd.shell rd.driver.pre=ahci"
--kver
"
$(uname -r)"
--add-drivers
"
$DRACUT_DRIVERS"
--add lvm
--mdadmconf
--lvmconf
-o
"dash plymouth"
initrd-$(uname -r)
至于为什么需要加载lvm模块,这是环境要求根文件系统必须做LVM,在云环境下其实我是非常不推荐使用的。
fstab全部使用块设备UUID而非逻辑卷路径(/dev/sdX),担心逻辑卷路径由于磁盘驱动发生改变,谁知道会不会由
/dev/sda1
变成
/dev/vda1
呢。
当时想到这么做一定万无一失了吧,启动虚拟机验证下,结果出人意外,系统进入了
emergency
模式,幸好我在initramfs中配置了
rd.shell
,否则就不知道如何进入调试了。
输入root密码进入bash,发现原因是
/boot
没有挂载上,尝试手动挂载看看啥错误:
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设备:
0QEMU_QEMU_HARDDISK_bcd82475-9f57-43e6
-a-part
lVM是会被dm映射的,这没有问题,但是
/boot
是一个物理分区,并没有做PV加到任何VG,那是谁把这个设备dm了呢?
使用
dmsetup info
查看下线索:
dmsetup info 0QEMU_QEMU_HARDDISK_bcd82475-9f57-43e6
-a-part
Name: 0QEMU_QEMU_HARDDISK_bcd82475-9f57-43e6
-a-part
State: ACTIVE
Read Ahead: 1024
Tables present: LIVE
Major, minor: 254,1
Number of targets: 1
UUID: part1-mpath-0QEMU_QEMU_HARDDISK_bcd82475-9f57-43e6
-a-part
其他信息没有什么有用,唯独看到
UUID
中包含
mpath
,猜测可能就是由于
multipath
导致的。
使用
multipath -l
命令查看果然:
size=40G features=
'0' hwhandler=
'0' wp=rw
policy=
'service-time 0' prio=0 status=active
2:0:0:0 sda 8:0 active undef running
居然整个sda都被multipath映射了。
找到原因心想解决思路就明朗了,检查了multipathd服务发现是
disabled
的,那应该开机是没有启动multipathd服务的。
使用
lsmod
发现
multipath
内核模块确实是加载的,难道是其他依赖模块拉起来的?
为了确定是multipath服务导致的,运行如下命令确保multipath是停止的,并且强制把multipath内核模块加到黑名单列表中。
systemctl
disable multipathd
echo
"blacklist multipath" >>/etc/modprobe.d/50-blacklist.conf
并修改了
/etc/multipath.conf
配置文件显式把
sda
添加到blacklist中。
blacklist {
devnode
"^(td|hd|vd)[a-z]"
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黑名单列表中:
dracut -f -N
...
-o
"... multipath"
...
替换原来的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