当因为更新导致 Amazon EC2 实例无法成功重启时,如何恢复到已知的稳定内核?

上次更新时间:2021 年 8 月 30 日

当因为更新导致 Amazon Elastic Compute Cloud (Amazon EC2) 实例无法成功重启时,如何恢复到稳定的内核?

简短描述

如果您已对 EC2 Linux 实例执行内核更新,但是内核现已损坏,则实例无法重启。您无法使用 SSH 连接到受损实例。

要恢复到以前的版本,请执行以下操作:

1.    访问实例的根卷。

2.    更新 GRUB 引导程序中的默认内核。

解决方法

访问实例的根卷

有两种方法可以访问根卷:

方法 1:使用 EC2 串行控制台

如果您为 Linux 启用了 EC2 串行控制台,则可以使用它来排查受支持的基于 Nitro 的实例类型问题。串行控制台可帮助您排查启动问题、网络配置和 SSH 配置问题。串行控制台无需网络连接即可连接到您的实例。您可以使用 Amazon EC2 控制台或 AWS 命令行界面 (AWS CLI) 访问串行控制台。

在使用串行控制台之前,请在账户层面授予对串行控制台的访问权限。然后,创建 AWS Identity and Access Management (IAM) 策略,授予对 IAM 用户的访问权限。此外,每个使用串行控制台的实例都必须至少包含一个基于密码的用户。如果您的实例无法访问,并且尚未配置对串行控制台的访问权限,请按照方法 2 中的说明进行操作。有关为 Linux 配置 EC2 串行控制台的信息,请参阅配置对 EC2 串行控制台的访问权限

注意:如果在运行 AWS CLI 命令时遇到错误,请确保您使用的是最新版本的 AWS CLI

方法 2:使用救援实例

创建一个临时救援实例,然后将您的 Amazon Elastic Block Store (Amazon EBS) 卷重新挂载到该救援实例上。从该救援实例中,您可以将 GRUB 配置为使用以前的内核进行启动。

重要提示:请勿在实例存储支持的实例上执行此操作。由于此恢复方法需要首先停止然后再重启实例,该实例上的任何数据都将丢失。有关更多信息,请参阅确定实例的根设备类型

1.    为根卷创建 EBS 快照。有关更多信息,请参阅创建 Amazon EBS 快照

2.    打开 Amazon EC2 控制台

注意:请确保您位于正确的区域。

3.    从导航窗格中选择实例,然后选择受损的实例。

4.    选择 Instance State(实例状态)、Stop Instance(停止实例),然后选择 Stop(停止)。

5.    在 Storage(存储)选项卡的 Block devices(块储存设备)下,为 /dev/sda1 或 /dev/xvda 选择 Volume ID(卷 ID)

注意:根设备因 AMI 而异,但 /dev/xvda/dev/sda1 将为根设备预留。例如,Amazon Linux 1 和 2 使用 /dev/xvda。其他发行版(如 Ubuntu 14、16、18、CentOS 7 和 RHEL 7.5)使用 /dev/sda1

6.    依次选择操作断开卷,然后选择是,请分离。记下可用区。

注意:您可以在分离 EBS 卷之前对其进行标记,以便在后面的步骤中识别它。

7.    在同一可用区中启动一个救援 EC2 实例。

注意:您可能需要启动与操作系统类型相同的 EC2 实例,具体取决于产品代码。例如,如果受损的 EC2 实例是付费的 RHEL AMI,则您必须使用相同的产品代码启动 AMI。有关更多信息,请参阅获取实例的产品代码

如果原始实例正在运行 SELinux(例如 RHEL、CentOS 7 或 8),请从使用 SELinux 的 AMI 启动救援实例。如果您选择运行其他操作系统的 AMI(例如 Amazon Linux 2),则原始实例上的任何修改后的文件都会损坏 SELinux 标签。

8.    启动救援实例后,从导航窗格中选择,然后选择受损实例已分离的根卷。

9.    依次选择操作附加卷

10.    选择救援实例 ID (id-xxxxx),然后设置一个未使用的设备。在本示例中为 /dev/sdf

11.     使用 SSH 连接到救援实例。

12.    运行 lsblk 命令以查看可用的磁盘设备:

lsblk

以下是该输出的示例:

NAME    MAJ:MIN RM  SIZE RO TYPE MOUNTPOINT
xvda    202:0     0   15G  0 disk
└─xvda1 202:1     0   15G  0 part /
xvdf    202:0     0   15G  0 disk
    └─xvdf1 202:1 0   15G  0 part

注意:基于 Nitro 的实例会将 EBS 卷作为 NVMe 块储存设备公开。lsblk 命令在基于 Nitro 的实例上生成的输出显示磁盘名称为 nvme[0-26]n1。有关更多信息,请参阅 Linux 实例上的 Amazon EBS 和 NVMe。以下是在基于 Nitro 的实例上的 lsblk 命令输出示例:

NAME           MAJ:MIN RM  SIZE RO TYPE MOUNTPOINT
nvme0n1        259:0    0    8G  0 disk 
└─nvme0n1p1    259:1    0    8G  0 part /
└─nvme0n1p128  259:2    0    1M  0 part 
nvme1n1        259:3    0  100G  0 disk 
└─nvme1n1p1    259:4    0  100G  0 part /

13.    运行以下命令以成为根:

sudo -i

14.    将已挂载卷的根分区挂载到 /mnt。在上例中,已挂载卷的根分区为 /dev/xvdf1 或 /dev/nvme2n1p2。有关更多信息,请参阅使 Amazon EBS 卷可在 Linux 上使用。注意,在以下示例中,将 /dev/xvdf1 替换为卷的正确根分区。

mount -o nouuid /dev/xvdf1 /mnt

注意:如果您的配置中不存在 /mnt,请创建一个挂载目录,然后将已挂载卷的根分区挂载到此新目录。 

mkdir /mnt
mount -o nouuid /dev/xvdf1 /mnt

现在,您可以通过挂载目录,访问受损实例的数据。

15.    将救援实例的 /dev/run/proc/sys 挂载至与新挂载卷相同的路径:

for m in dev proc run sys; do mount -o bind {,/mnt}/$m; done

调用 chroot 函数来更改为挂载目录。

注意:如果您有一个单独的 /boot 分区,请在运行以下命令之前将其挂载到 /mnt/boot

chroot /mnt

更新 GRUB 引导程序中的默认内核

当前损坏的内核位于列表中的位置 0(零)。最新的稳定内核位于位置 1。要将损坏的内核替换为稳定的内核,请根据您的发行版使用以下其中一项操作:

  • 适用于 Red Hat 6 和 Amazon Linux 的 GRUB1(旧版 GRUB)
  • 适用于 Ubuntu 14 LTS、16.04 和 18.04 的 GRUB2
  • 适用于 RHEL 7 和 Amazon Linux 2 的 GRUB2
  • 适用于 RHEL 8 和 CentOS 8 的 GRUB2

适用于 Red Hat 6 和 Amazon Linux 1 的 GRUB1(旧版 GRUB)

使用 sed 命令,将损坏的内核替换为 /boot/grub/grub.conf 文件中的稳定内核:

sed -i '/^default/ s/0/1/' /boot/grub/grub.conf

适用于 Ubuntu 14 LTS、16.04 和 18.04 的 GRUB2

1.    使用 /etc/default/grub 文件中稳定的 GRUB_DEFAULT=saved 值替换损坏的 GRUB_DEFAULT=0 默认菜单项:

sed -i 's/GRUB_DEFAULT=0/GRUB_DEFAULT=saved/g' /etc/default/grub

2.    运行 update-grub 命令以便 GRUB 识别更改:

update-grub

3.    运行 grub-set-default 命令,以便下次重启时加载稳定的内核。在本示例中,位置 0 中的 grub-set-default 被设置为 1

grub-set-default 1

适用于 RHEL 7 和 Amazon Linux 2 的 GRUB2

1.    使用 /etc/default/grub 文件中稳定的 GRUB_DEFAULT-saved 值替换损坏的 GRUB_DEFAULT=0 默认菜单项:

sed -i 's/GRUB_DEFAULT=0/GRUB_DEFAULT=saved/g' /etc/default/grub

2.    更新 GRUB,以重新生成 /boot/grub2/grub.cfg 文件:

grub2-mkconfig -o /boot/grub2/grub.cfg

3.    运行 grub2-set-default 命令,以便下次重启时加载稳定的内核。在本示例中,位置 0 中的 grub2-set-default 被设置为 1

grub2-set-default 1

适用于 RHEL 8 和 CentOS 8 的 GRUB2

RHEL 8 和 CentOS 8 中的 GRUB2 将 blscfg 文件和 /boot/loader 中的条目用作启动配置,不再使用以前的 grub.cfg 格式。最佳实践是使用 grubby 工具来管理 blscfg 文件和检索 /boot/loader/entries/ 中的信息。如果在此缺失 blscfg 文件或该文件损坏,则 grubby 不会显示任何结果。您必须重新生成文件才能恢复功能。因此,内核的索引取决于位于 /boot/loader/entries 下的 .conf 文件和内核版本。索引被配置为保留具有最低索引的最新内核。有关如何重新生成 BLS 配置文件的信息,请参阅如何恢复因 Grub2 BLS 配置文件问题而启动失败的 Red Hat 8 或 CentOS 8 实例?

1.    运行 grubby --default-kernel 命令以查看当前默认内核:

grubby --default-kernel

2.    运行 grubby --info=ALL 命令以查看所有可用的内核及其索引:

grubby --info=ALL

以下是 --info=ALL 命令的示例输出:

root@ip-172-31-29-221 /]# grubby --info=ALL
index=0
kernel="/boot/vmlinuz-4.18.0-305.el8.x86_64"
args="ro console=ttyS0,115200n8 console=tty0 net.ifnames=0 rd.blacklist=nouveau nvme_core.io_timeout=4294967295 crashkernel=auto $tuned_params"
root="UUID=d35fe619-1d06-4ace-9fe3-169baad3e421"
initrd="/boot/initramfs-4.18.0-305.el8.x86_64.img $tuned_initrd"
title="Red Hat Enterprise Linux (4.18.0-305.el8.x86_64) 8.4 (Ootpa)"
id="0c75beb2b6ca4d78b335e92f0002b619-4.18.0-305.el8.x86_64"
index=1
kernel="/boot/vmlinuz-0-rescue-0c75beb2b6ca4d78b335e92f0002b619"
args="ro console=ttyS0,115200n8 console=tty0 net.ifnames=0 rd.blacklist=nouveau nvme_core.io_timeout=4294967295 crashkernel=auto"
root="UUID=d35fe619-1d06-4ace-9fe3-169baad3e421"
initrd="/boot/initramfs-0-rescue-0c75beb2b6ca4d78b335e92f0002b619.img"
title="Red Hat Enterprise Linux (0-rescue-0c75beb2b6ca4d78b335e92f0002b619) 8.4 (Ootpa)"
id="0c75beb2b6ca4d78b335e92f0002b619-0-rescue"
index=2
kernel="/boot/vmlinuz-4.18.0-305.3.1.el8_4.x86_64"
args="ro console=ttyS0,115200n8 console=tty0 net.ifnames=0 rd.blacklist=nouveau nvme_core.io_timeout=4294967295 crashkernel=auto $tuned_params"
root="UUID=d35fe619-1d06-4ace-9fe3-169baad3e421"
initrd="/boot/initramfs-4.18.0-305.3.1.el8_4.x86_64.img $tuned_initrd"
title="Red Hat Enterprise Linux (4.18.0-305.3.1.el8_4.x86_64) 8.4 (Ootpa)"
id="ec2fa869f66b627b3c98f33dfa6bc44d-4.18.0-305.3.1.el8_4.x86_64"

请记下您希望为实例设置为默认值的内核的路径。在上例中,索引 2 处内核的路径为 /boot/vmlinuz- 0-4.18.0-80.4.2.el8_1.x86_64

3.    运行 grubby --set-default 命令以更改实例的默认内核:

grubby --set-default=/boot/vmlinuz-4.18.0-305.3.1.el8_4.x86_64

注意:4.18.0-305.3.1.el8_4.x86_64 替换为您的内核版本号。

4.    运行 grubby --default-kernel 命令以验证上述命令是否有效:

grubby --default-kernel

如果您使用 EC2 串行控制台访问实例,那么稳定的内核现在会进行加载,您可以重启实例。

如果您使用的是救援实例,请完成以下部分中的步骤。

卸载卷,从救援实例中分离根卷并将其连接到受损实例

注意:如果您采用的是方法 2:使用救援实例,请完成以下步骤。

1.    退出 chroot 并卸载 /dev/run/proc/sys

exit
umount /mnt/{dev,proc,run,sys,}

2.    从 Amazon EC2 控制台中,选择 Instances (实例),然后选择救援实例。

3.    选择 Instance State(实例状态)、Stop instance(停止实例),然后选择 Stop(停止)。

4.    从救援实例中分离根卷 id-xxxxx(来自受损实例的卷)。

5.    将您在第 4 步中分离的根卷作为根卷 (/dev/sda1) 连接到受损实例,然后启动该实例。

注意:根设备因 AMI 而异。名称 /dev/xvda/dev/sda1 将始终预留给根设备。例如,Amazon Linux 1 和 2 使用 /dev/xvda。其他发行版(如 Ubuntu 14、16、18、CentOS 7 和 RHEL 7.5)使用 /dev/sda1。

现在将加载稳定的内核,并重启实例。


这篇文章对您有帮助吗?


您是否需要账单或技术支持?