grub损坏,是导致系统启动失败比较常见的原因。如何解决这类问题呢?
解决问题,好用的工具很重要。我们先讨论下好用的工具。
三大利器
关于工具的重要性我们就不絮叨了。解决启停问题,一定要有三大利器的辅助
- 快照
- VNC
- 录屏工具
快照
快照对排查启停问题,有三个方面的用处。一是保留现场。有了这个现场,不管我们排查中做了什么变更,我们总是能够回撤到现场。这是现实版后悔药。二是在没有办法进入系统的情况下,快照可以让我们把问题磁盘挂载到其他实例上。这样我们有了一个排查、诊断和修复的途径。三是快照提供了多种可选择的途径让我们可以使用修复后的数据和结构。比如新建磁盘挂载拷贝、制作安装镜像覆盖有问题的系统盘等等。
VNC
高速公路是有应急车道的。同样我们的业务系统也需要应急车道,用以解决异常、紧急等非常规问题。VNC就是我们的应急车道。
当然,VNC不是唯一可用的方案。这里的关键是在系统异常时,提供一个root shell供排查只用就好。
录屏工具
各主流平台都有好用的录屏工具,功能大同小异,大家使用顺手即可。为什么我们要建议大家都配备录屏工具呢?
系统启停时,Linux控制台上的系统输出很快。有些关键的报错信息,你可能完全没有机会看到就过去了。如果类似信息完全没有记录到日志中。那么,你可能被后面的日志给误导。
题外话:bind挂载
修复启停时经常需要做chroot操作,即我们要在一个新的根文件系统内操作。但是,只执行chroot是不够的。我们还需要挂载/dev、/proc和/sys目录。
但是,因为/dev、/proc和/sys不是设备,直接挂载是不可行的。
mount --bind /olddir /newdir # bind挂载选项实例
for d in dev proc sys;do mount /$d /new_root_dir/$d;done # 切换根文件执行chroot前,先挂载需要的系统目录
回到话题
如何复现现场?
我们通过覆盖磁盘第一扇区来破坏grub的引导代码部分,观察下grub被破坏后,实例启动的情况
具体操作的命令如下。注意,危险操作,切勿随意模仿。
fdisk -l -u /dev/{
xvda,vda} # 确定系统盘设备路径
dd if=path_to_sys_disk bs=448 count=1 2>/dev/null | od -tx1 # 查看MBR内容
dd if=/dev/zero bs=448 count=1 of=path_to_sys_disk # 覆盖MBR
dd if=path_to_sys_disk bs=448 count=1 2>/dev/null | od -tx1 # 验证已经覆盖了MBR
reboot # 重启
执行过程如下(fdisk操作没有显示)
修复
那么,怎么修复呢?grub损坏的修复方法简洁明了:重新安装grub即可。但是当前实例启动失败了,无法对问题系统进行读写处理。
所以我们需要解决的问题是两个:
- 通过什么方式来处理系统盘。
- 怎么重新安装grub。
解决第一个问题的方法很多。这里我们给大家推荐能够使用快照的方法。这个方法虽然稍显啰嗦,但是却能让我们全程掌控。
如何使用快照?
我们为问题实例的系统盘做快照。然后再从快照新建磁盘。新建磁盘和系统盘内容一样,但是可以作为数据盘挂载到正常实例上。
这样我们就可以在正常实例上对新创建的磁盘做处理。调整配置、适当修改,而后重新安装grub。
整个思路图示如下
具体操作示例如下
首先做快照
给快照个显著的名字
良好规划和维护的系统盘,一般都尺寸不大
现在新建磁盘
处理系统盘的问题解决了。那么,怎么重新安装grub呢?
重装grub
主流Linux发行版都提供了grub-install工具(名称也可能是grub2-install),大家直接调用即可。但是有几点大家要注意。
小提示
首先,grub的引导器默认使用BIOS的磁盘命名惯例,这与Linux是不同。所以grub提供了配置文件,用来在BIOS的磁盘命名和Linux系统的磁盘命名之间转换。
这些配置文件如下:
版本 | 应用配置 | 系统配置 |
---|---|---|
grub | /boot/grub/device.map | /etc/{sysconfig,default}/grub |
grub2 | /boot/grub2/device.map | /etc/{sysconfig,default}/grub |
如果是KVM实例,则磁盘是vda;如果是较老的XEN实例,则磁盘是xvda。
第二,grub-install的操作对象是磁盘还是分区。不要给错参数。
第三,如果您的系统比较老。那么,您可能会碰到已知bug:grub-install工具不能处理/dev/xvda*路径。
重装步骤
有了以上的铺垫,我们给出重新安装grub的步骤
- 把新建磁盘挂载到正常实例上,以便对之读写、修改。
- 挂载目标根文件系统,我们需要改动grub的device.map文件。
- 把/dev、/proc和/sys挂载到新挂载文件系统。这样我们就能够使用内核导出的系统数据了。
- chroot到目标根文件系统,使之成为当前跟文件系统。
- 检查和核实/boot/{grub,grub2}/device.map和/etc/{sysconfig,default}/grub配置文件中磁盘名称是否正确。
- 使用grub-install来重新安装grub。
这些步骤,用脚本来表达,如下
# 1. 挂载新建磁盘到正常实例需要在控制台操作
# 2. 把新建磁盘在实例内部挂载上。这里我们假设/dev/vdb是系统盘
mount /dev/vdb1 /mnt
# 3. 通过bind方式,挂载系统目录到新根文件系统
for d in dev proc sys;do mount --bind /$d /mnt/$d;done
# 4. 切换到新根文件系统
chroot /mnt
# 5. 检查/boot/grub/device.map或者/boot/grub2/device.map文件,确认磁盘名称不当。如有则修改
cat /boot/{
grub,grub2}/device.map
# 6. 重新安装grub。因为是在其他实例上以数据盘的方式,因此是第二块磁盘。
grub-install /dev/vdb
我们按照上面的步骤,把前面破坏的那台实例的grub重新安装下。
首先,挂载磁盘到正常实例
实例内部挂载
接下来我们bind挂载/dev、/proc和/sys
现在切换到新根文件系统
第五步,检查磁盘名称是否需要修改,需要则修改之
最后一步,重新安装grub
再次请快照出场
怎么通过修正完毕的新建磁盘来修复问题实例的系统呢?这里需要注意
- 我们没有办法直接使用新建的快照回滚问题实例的系统盘。
- 数据盘的快照不能创建安装镜像。但是,开通了白名单就可以。
我们新创建磁盘是数据盘,其创建的快照是不能回滚问题实例的系统盘的。所以我们只能通过把新创建磁盘转为系统盘,而后创建安装镜像的方式来恢复问题实例。当然,这需要开通白名单。
即整体思路是这样的
怎么把数据盘转为系统盘?我们会专题讨论下。
终焉
祝探索愉快。