記一次被Multipath坑苦的經(jīng)歷
本文轉(zhuǎn)載自微信公眾號「int32bit」,作者int32bit 。轉(zhuǎn)載本文請聯(lián)系int32bit公眾號。
今天使用Packer制作SUSE鏡像,之前磁盤格式使用的是IDE,這次換成SCSI,由于磁盤類型變了,為了保險起見,我重新生成了initramfs加載ahci驅(qū)動以支持在引導階段下加載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模塊,這是環(huán)境要求根文件系統(tǒng)必須做LVM,在云環(huán)境下其實我是非常不推薦使用的。
fstab全部使用塊設(shè)備UUID而非邏輯卷路徑(/dev/sdX),擔心邏輯卷路徑由于磁盤驅(qū)動發(fā)生改變,誰知道會不會由/dev/sda1變成/dev/vda1呢。
當時想到這么做一定萬無一失了吧,啟動虛擬機驗證下,結(jié)果出人意外,系統(tǒng)進入了emergency模式,幸好我在initramfs中配置了rd.shell,否則就不知道如何進入調(diào)試了。
輸入root密碼進入bash,發(fā)現(xiàn)原因是/boot沒有掛載上,嘗試手動掛載看看啥錯誤:
- mount -a #重新安裝fstab掛載卷
提示設(shè)備already mounted or mount point busy。
mount point掛載點/boot肯定是沒有被掛載,那肯定就是設(shè)備問題,從錯誤中提示是該磁盤設(shè)備已經(jīng)掛載了,但是無論如何df、lsblk都找不到掛載記錄。
嘗試各種lsof、fuser命令發(fā)現(xiàn)也沒有任何進程占用了該設(shè)備。
那顯然只有一種情況,我猜想這個設(shè)備被dm(device mapper)映射了。
使用dmsetup查看所有的dm列表,除了LV映射,果然多了很多0QEMU_QEMU_HARDDISK開頭的dm設(shè)備:
- 0QEMU_QEMU_HARDDISK_bcd82475-9f57-43e6-a-part
lVM是會被dm映射的,這沒有問題,但是/boot是一個物理分區(qū),并沒有做PV加到任何VG,那是誰把這個設(shè)備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服務(wù)發(fā)現(xiàn)是disabled的,那應(yīng)該開機是沒有啟動multipathd服務(wù)的。
使用lsmod發(fā)現(xiàn)multipath內(nèi)核模塊確實是加載的,難道是其他依賴模塊拉起來的?
為了確定是multipath服務(wù)導致的,運行如下命令確保multipath是停止的,并且強制把multipath內(nèi)核模塊加到黑名單列表中。
- 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"
- }
重啟虛擬機,結(jié)果還是一樣的問題,multipath還是堅強地起來了。
難道真的是其他服務(wù)把multipath啟動的,為了排除這種可能,把/usr/lib/systemd/system/multipathd.service挪走了,這下沒有誰能啟動這個服務(wù)了吧。
重啟虛擬機,結(jié)果還是令人意外的一樣,這個multipath還是起來了,夠玄乎。
更絕的我把/sbin/multipath以及/sbin/multipathd都挪走刪除了,這讓服務(wù)再無可能運行了吧。
再次重啟虛擬機,讓人懷疑人生的是multipathd服務(wù)像打不死的小強寧死不屈,依然運行了。
Google倒是找到有類似的問題System exit to emergency shell at boot with multipath enabled (SLES12, MPIO)[1],解決方法也無非是disable multipath服務(wù)或者把設(shè)備添加到multipath blacklist,但根本沒有效果。
在百思不得解的情況下,突然靈光一現(xiàn),難道是initramfs的問題?這個multipath在initramfs掛載rootfs就已經(jīng)做過了?
順著這個思路,唯有重新做initramfs鏡像,并把multipath模塊加到omit黑名單列表中:
- dracut -f -N \
- ...
- -o "... multipath" \
- ...
替換原來的initrd-xxx文件后啟動虛擬機,虛擬機終于神奇地啟動成功了。
最后歸根到底原來是initramfs boot階段加載了multipath模塊,因此在用戶態(tài)怎么修改禁用multipath都是沒用的。后來在SUSE文檔中也找到了相關(guān)說明: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