LoginSignup
3
4

More than 3 years have passed since last update.

VPSサーバー(CentOS8.1)が yum update 後に起動できなくなる現象の回避策

Last updated at Posted at 2020-11-21
../

VPSサーバー(CentOS8.1)の構築中に yum update を実行すると再起動できなくなるという洗礼を受けた。yum update中に /boot/grub2/grub.cfg の変更が行われ、その影響のようだ。回避するには、サーバー構築の最初の段階で /boot/grub2/grub.cfg を退避しておき、yum update 後に元に戻してやるといい。

どういった症状なのか

GMO VPSで利用可能となったサーバー(CentOS8.1)を VPSポータルから通常モードで起動して「ON」状態になったら、TeraTermで接続してrootでログインする。VPSポータルのコンソールからログインしても同様である。そして、yum updateを実行し、サーバーを再起動する。


login: root
Password: ***
$ yum update -y
$ reboot

すると、TeraTermからは接続できなくなり、VPSポータルのコンソールからだとGRUB選択画面が開いて、進めなくなる。

なぜ起きるのか

GRUBは、ブートローダーであり、どこからOSイメージを読み込んで起動するかを選択するためのもの。古いGRUB(GRUB Legacy)と新しいGRUB2がある。GRUB2はCentOS7以降からだ。GRUB LegacyとGRUB2のどちらを使うか、どのOSイメージを使うかを選択して、そのOSイメージをロードして、OSが起動される。通常、どのOSイメージを使うかは初期設定されたものや初回にユーザーが選択したものを覚えていて、自動で一連の動作を行ってくれる。それが、yum updateの実行によって、OSイメージの選択が自動で行えなくなってしまうようだ。そのため、TeraTermからは接続時にタイムアウトし、VPSポータルのコンソールからはGRUB LegacyとGRUB2の選択画面で止まってしまう。

VPSポータルのコンソールでは、GRUB選択画面からGRUBのコマンドで対処できるのかもしれない。WindowsPCからはキーバインドも異なり、コピペもできず、GRUBコマンドの知見もないので、私は早々にあきらめた。

CentOS8.1では、GRUB2が使われる。起動時の制御は、/etc/default/grubファイルで指定できる。GRUB_TIMEOUTでタイムアウト秒数、GRUB_DEFAULTでOSイメージを指定する。タイムアウト秒数を経過したら指定のOSイメージが自動で起動される。正確には、事前にgrub2-mkconfigコマンドを実行して、grubファイルと/etc/grub.d/配下のファイルの記述にもとづいて、/boot/grub2/grub.cfgファイルを生成しておくのである。起動時にはgrub.cfgファイルが実行されるのであって、起動時にgrubファイルを解釈する訳ではない。GRUB2の詳細は、https://documentation.suse.com/ja-jp/sles/12-SP4/html/SLES-all/cha-grub2.html などを参照のこと。

つまり、yum updateによって、grub.cfgファイルが書き換わっているか、grub.cfgファイルの記述どおりに実行できない状況(例えば、必要なファイルがないなど)に陥っているのだ。

また、起動時には /boot/grub2/grubenvも参照する。これは前回の起動時の設定を保存し、次回の起動時に参照するものである。GRUB_DEFAULT=saved の指定の時に利用される。起動後に grubenv ファイルに修正を加えることで、次回の起動を制御できる。例えば、grub2-set-default コマンドを実行することで、/etc/default/grub を介さずにダイレクトにsaved_entryを変更することができる。

回避する手順

初回のログイン後に、grub.cfgファイルを退避しておき、yum update後に戻してやれば、なんとかなりそうだ。以下、手順を説明する。

(1) VPSポータルからサーバーを通常モードで起動し、TeraTermからrootでログインする。そして、初期状態でバージョンを確認する。CentOS8.1である。


$ cat /etc/redhat-release   
CentOS Linux release 8.1.1911 (Core) 

(2) yum update後にブートできなくなるので、事前に以下のファイルを退避しておく。実際には、grub.cfgファイルだけでもいいが、他のファイルも合わせて退避しておくとよい。


$ cp /etc/default/grub /etc/default/grub.original
$ cp /boot/grub2/grub.cfg /boot/grub2/grub.cfg.original
$ cp /boot/grub2/grubenv /boot/grub2/grubenv.original

実は、grubファイルは既にgrub.rpmsaveとしてバックアップされており、grub.cfgファイルもgrub.cfg.rpmsaveとしてバックアップされている。それらのファイルで十分かもしれないが、上記手順では明示的に退避するようにした。ちなみに/etc/default/grubは、以下のようになっている。


$ cat /etc/default/grub
GRUB_TIMEOUT=5
GRUB_DISTRIBUTOR="$(sed 's, release .*$,,g' /etc/system-release)"
GRUB_DEFAULT=saved
GRUB_DISABLE_SUBMENU=true
GRUB_TERMINAL_OUTPUT="console"
GRUB_CMDLINE_LINUX="crashkernel=auto biosdevname=0 net.ifnames=0 rhgb quiet"
GRUB_DISABLE_RECOVERY="true"
GRUB_ENABLE_BLSCFG=true
GRUB_DISABLE_UUID=true
GRUB_DISABLE_LINUX_UUID=true

GRUB_TIMEOUTとGRUB_DEFAULTは、5秒間待った後で、前回使用したOSイメージを起動することを示している。GRUB_DEFAULTは0,1,2,...のような番号で指定したり、OSイメージの名前で指定したり、"saved"で指定する。"saved"の場合には、/boot/grub2/grubenvファイルのsaved_entryで前回使用したOSイメージを識別する。


$ cat /boot/grub2/grubenv
saved_entry=20db05bac820110f5800ebe2e7262b58-4.18.0-193.28.1.el8_2.x86_64
kernelopts=root=/dev/vda1 ro crashkernel=auto biosdevname=0 net.ifnames=0 rhgb quiet
boot_success=1

(3) yum updateを実行する。問題のyum updateの実行である。200個くらいのモジュールが更新される。


$ yum update -y

(4) yum update後にバージョンを確認する。CentOS8.2に上がっている。


$ cat /etc/redhat-release
CentOS Linux release 8.2.2004 (Core)

(5) 今後はyum updateでカーネルが更新されないように設定しておく。


$ vi /etc/yum.conf
exclude=kernel* grub2*

kernel*だけでなく、kernel* grub2*にしておいた方が無難である。
※ただし、これらを除外しておくと、今後に行うinstallやupdateによって「依存性の欠如」の問題が生じる場合がある。そのときは、excludeの行をコメントアウトして、yum updateを行い、grub2の問題に手動で対処する必要がある。

(6) 退避しておいた grub.cfg を元に戻す。/etc/default/grub は変更されないので、回復は不要。grubenvは、起動時に更新されるが、通常、内容は前回と同じである。grub2-set-defaultコマンドを使うとgrubenvが書き換わるので、その場合には回復すること。


$ cp /boot/grub2/grub.cfg.original /boot/grub2/grub.cfg
$ cp /boot/grub2/grubenv.original /boot/grub2/grubenv

$ awk -F\' '$1=="menuentry " {print $2}' /boot/grub2/grub.cfg
CentOS Linux (4.18.0-147.5.1.el8_1.x86_64) 8 (Core)

(7) この時点で再起動して、TeraTermからログインできることを確認する。

(8) 再起動後にログインできたら、改めてgrubファイルを編集し、grub2-mkconfigコマンドで反映させる。grubファイルでは、GRUB_CMDLINE_LINUXのみ変更している。そして、grubenvファイルのsaved_entryで識別されたものが"Found linux"のメッセージ内に見当たるかを確認する。awkの結果でも確認できる。先頭(0番目)が該当することが分かる。


# grubファイルを編集する
$ vi /etc/default/grub
GRUB_TIMEOUT=3
GRUB_DISTRIBUTOR="$(sed 's, release .*$,,g' /etc/system-release)"
GRUB_DEFAULT=saved
GRUB_DISABLE_SUBMENU=true
GRUB_TERMINAL_OUTPUT="console"
GRUB_CMDLINE_LINUX="rd.lvm.lv=centos/root rd.lvm.lv=centos/swap 
 vconsole.font=latarcyrheb-sun16 vconsole.keymap=jp106 
 biosdevname=0 net.ifnames=0 rhgb quiet "
GRUB_DISABLE_RECOVERY="true"
GRUB_ENABLE_BLSCFG=true
GRUB_DISABLE_UUID=true
GRUB_DISABLE_LINUX_UUID=true

# grub.cfgファイルに反映させる
$ grub2-mkconfig -o /boot/grub2/grub.cfg
Generating grub configuration file ...
Found linux image: /boot/vmlinuz-4.18.0-193.28.1.el8_2.x86_64
Found initrd image: /boot/initramfs-4.18.0-193.28.1.el8_2.x86_64.img
Found linux image: /boot/vmlinuz-4.18.0-147.5.1.el8_1.x86_64
Found initrd image: /boot/initramfs-4.18.0-147.5.1.el8_1.x86_64.img
Found linux image: /boot/vmlinuz-0-rescue-20db05bac820110f5800ebe2e7262b58
Found initrd image: /boot/initramfs-0-rescue-20db05bac820110f5800ebe2e7262b58.img
done

$ awk -F\' '$1=="menuentry " {print $2}' /boot/grub2/grub.cfg
CentOS Linux (4.18.0-193.28.1.el8_2.x86_64) 8 (Core)
CentOS Linux (4.18.0-147.5.1.el8_1.x86_64) 8 (Core)
CentOS Linux (0-rescue-20db05bac820110f5800ebe2e7262b58) 8 (Core)

# grubenvファイルを確認する
$ cat /boot/grub2/grubenv
saved_entry=20db05bac820110f5800ebe2e7262b58-4.18.0-193.28.1.el8_2.x86_64
kernelopts=root=/dev/vda1 ro crashkernel=auto biosdevname=0 net.ifnames=0 rhgb quiet
boot_success=1

(9) 再度、再起動して、TeraTermからログインできれば問題ない。

補足1:grub2-mkconfigコマンド

上記手順のyum update直後にgrub2-mkconfigコマンドを実行してgrub.cfgを生成するとどうか試してみた。結果はNGだった。TeraTermからログインできなくなり、VPSポータルのコンソールからはGRUB選択画面で停止することになった。grub.cfg内のmenuentryの記述が欠落した状態になった。原因は分からない。
上記(8)(9)の手順のように、再起動した後にgrub2-mkconfigを実行するとうまくいくようだ。

補足2:grub2-set-defaultコマンド

/boot/grub2/grubenvを見ると、saved_entryには番号(0,1,2,...)ではなく、20db05bac820110f5800ebe2e7262b58-4.18.0-193.28.1.el8_2.x86_64の名前が入っている。後半の「4.18.0-193.28.1.el8_2.x86_64」の部分でマッチングされるようだ。


$ cat /boot/grub2/grubenv
saved_entry=20db05bac820110f5800ebe2e7262b58-4.18.0-193.28.1.el8_2.x86_64
kernelopts=root=/dev/vda1 ro crashkernel=auto biosdevname=0 net.ifnames=0 rhgb quiet
boot_success=1

ちなみに、grub2-set-defaultを実行することで、/etc/default/grubを介さずにダイレクトにsaved_entryを変更することができる。


$ grub2-set-default 0
$ cat /boot/grub2/grubenv
saved_entry=0
kernelopts=root=/dev/vda1 ro crashkernel=auto biosdevname=0 net.ifnames=0 rhgb quiet
boot_success=1

補足3:リカバリモードからの修復

起動できなくなったら、VPSポータルからリカバリモードでサーバー起動して、TeraTermからrootでログインして、以下の手順で修復できる。パスワードは"recovery"ではなく、初期パスワードである。VPSポータルのメッセージは間違っているようだ。本体ディスクを識別してマウントしてから操作する手順になる。


$ fdisk -l | more
  /dev/vda1
$ mount /dev/vda1 /mnt
$ cp /mnt/boot/grub2/grub.cfg.original /mnt/boot/grub2/grub.cfg

試していないが、grub.cfg.rpmsaveが既存だったので、そのファイルで回復できたかもしれない。以下のようにコピーしてサーバーを再起動すれば、上記(8)(9)の手順で回復できたかもしれない。


$ cp /mnt/boot/grub2/grub.cfg.rpmsave /mnt/boot/grub2/grub.cfg

GMOサービスセンターからのアドバイス

GMOサービスセンターにアドバイスをお願いしていたのですが、その回答をいただきました。ありがとうございます。

(1) CentOS 8においては、Kernelのアップグレード前には、yum.confに下記を追加してくださいとのことだった。grub2*も除外した方がいいそうだ。


$ vi /etc/yum.conf
exclude=kernel* grub2*

(2) また、grub2をアップデートした場合には、/etc/default/grubを編集して、GRUB_ENABLE_BLSCFGの行をコメントアウトして grub2-mkconfigを実行するとよいということだった。ただ、私もまだGRUB_ENABLE_BLSCFG=falseの挙動は未確認だ。

$ yum update grub2*
$ vi /etc/default/grub
GRUB_ENABLE_BLSCFG=true# GRUB_ENABLE_BLSCFG=true   # コメントアウトする。falseをセットしてもいい。
$ grub2-mkconfig -o /boot/grub2/grub.cfg

以上

../
3
4
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
4