Linuxでkexecを使う:BIOS/UEFIをスキップして超高速カーネル再起動を実現する

Linux tutorial - IT technology blog
Linux tutorial - IT technology blog

BIOSのPOSTだけで3分かかるサーバー再起動——もっと速い方法はないのか?

本番サーバーでカーネルを更新するたびに、あの長々とした起動プロセスを待たされる:BIOSがRAM、CPU、デバイスをチェックし、ブートローダーに制御を渡し、ようやくカーネルを読み込む。4GBのRAMを搭載した古い物理サーバーでは、POSTフェーズだけで90秒かかる。10台のサーバーに掛け算すると、カーネルパッチのたびに約15分のダウンタイムになる。

問題はLinuxの起動が遅いわけではない——カーネルの交換とは無関係なBIOS/UEFIハードウェアが、システム全体をその手順に通すことを強要しているのだ。kexecはまさにこの問題を解決するために生まれた。

kexecとは何か、なぜ機能するのか

kexec(kernel executeの略)はLinuxカーネルのシステムコールで、実行中のカーネルが別のカーネルを直接メモリに読み込み、制御を引き渡すことを可能にします——BIOS/UEFIとブートローダー(GRUB)を完全にスキップして。

動作メカニズムは2つの独立したフェーズから構成されます:

  1. ロードフェーズkexec -lコマンドを使って、カーネルイメージを予約メモリ領域に読み込む。このステップはシステムが通常稼働中に実行され、サービスを中断しない。
  2. 実行フェーズkexec -e(またはsystemctl kexec)コマンドで実際に新しいカーネルへ移行する。ここで現在のカーネルはファイルシステムをアンマウントし、プロセスを停止してから、新しいカーネルのエントリポイントへ直接ジャンプする。

POSTなし。メモリテストなし。GRUBのカウントダウンなし。新しいカーネルは、まるでブートローダーから制御を受け取ったかのようにstart_kernel()から実行を開始する。

私が管理しているRAM 4GBのUbuntu 22.04サーバーでは、通常の再起動の約3分からkexecを使うことで30秒未満へと、処理時間が大幅に短縮されることを確認している。

実践:kexecのインストールと使い方

ステップ1:kexec-toolsのインストール

kexec-toolsはkexec(2)カーネルシステムコールと対話するためのユーザースペースツールを提供します。

# Ubuntu / Debian
sudo apt install kexec-tools -y

# RHEL / AlmaLinux / Rocky
sudo dnf install kexec-tools -y

# Arch Linux
sudo pacman -S kexec-tools

インストール後、Ubuntu/Debianではkexec-load.serviceというsystemdユニットが追加されます——このユニットはシャットダウン時に現在のカーネルを自動的にメモリに読み込み、kexec再起動の準備をします。

ステップ2:使用中のカーネルとinitrdを確認する

実行中のカーネルイメージとinitramfsの正確なパスを確認する必要があります:

# 実行中のカーネルバージョンを確認
uname -r
# 出力例: 6.8.0-45-generic

# Ubuntuでの通常のパス
ls /boot/vmlinuz-$(uname -r)
ls /boot/initrd.img-$(uname -r)

# 使用中のcmdlineを確認(ブートパラメータ)
cat /proc/cmdline

ステップ3:カーネルをメモリに読み込む

このステップは安全です——実行中のシステムを中断しません:

KERNEL_VER=$(uname -r)

sudo kexec -l /boot/vmlinuz-${KERNEL_VER} \
  --initrd=/boot/initrd.img-${KERNEL_VER} \
  --reuse-cmdline

# --reuse-cmdline: /proc/cmdlineの全パラメータを再利用する
# "root=UUID=... quiet splash"を再入力する必要がない

カーネルが読み込まれたか確認:

cat /sys/kernel/kexec_loaded
# 出力: 1 = 読み込み済み、0 = 未読み込み

ステップ4:kexec再起動を実行する

kexecをトリガーする方法は3つあります。制御レベルに応じて選択できます:

# 方法1: systemctl(推奨——グレースフルシャットダウンを先に実行)
sudo systemctl kexec

# 方法2: kexecを直接実行(グレースフル、先にサービスを停止)
sudo kexec -e

# 方法3: 通常のrebootに統合(Ubuntu/Debianのみ)
# kexec-toolsがインストールされていると、カーネルが読み込まれている場合は通常のrebootコマンドが自動的にkexecを使用する
sudo reboot

新しいカーネルを読み込む(apt upgrade後)

これが最も実践的なユースケースです——ダウンタイムを最小限に抑えたカーネルアップデート:

# カーネルをアップデート
sudo apt update && sudo apt upgrade -y

# 最新のインストール済みカーネルを検索
NEW_KERNEL=$(ls /boot/vmlinuz-* | sort -V | tail -1 | sed 's|/boot/vmlinuz-||')
echo "新しいカーネル: ${NEW_KERNEL}"

# 新しいカーネルをメモリに読み込む(まだ再起動しない)
sudo kexec -l /boot/vmlinuz-${NEW_KERNEL} \
  --initrd=/boot/initrd.img-${NEW_KERNEL} \
  --reuse-cmdline

# 準備:不要なサービスを停止し、データを同期
sudo sync

# kexec再起動——BIOS/UEFIを完全にスキップ
sudo systemctl kexec

# 起動後に確認
uname -r

複数サーバーへの自動化スクリプト

複数のノードにカーネルアップデートを展開する際に使用するスクリプトです:

#!/bin/bash
# fast-reboot.sh — 最新カーネルでkexec再起動
set -e

NEW_KERNEL=$(ls /boot/vmlinuz-* | sort -V | tail -1 | sed 's|/boot/vmlinuz-||')
CURR_KERNEL=$(uname -r)

if [ "${NEW_KERNEL}" = "${CURR_KERNEL}" ]; then
  echo "新しいカーネルはありません。現在使用中: ${CURR_KERNEL}"
  # 現在のカーネルを再読み込み(コールドリブートより速い)
fi

echo "カーネルを読み込み中: ${NEW_KERNEL}"
kexec -l "/boot/vmlinuz-${NEW_KERNEL}" \
  --initrd="/boot/initrd.img-${NEW_KERNEL}" \
  --reuse-cmdline

echo "5秒後にkexec再起動を開始します..."
sleep 5
systemctl kexec

kexecを使う際の注意点

kexecがすべての状況に適しているわけではない

通常の再起動が適切な場面もあります:

  • ファームウェア/BIOSのアップデート:新しいファームウェアをフラッシュするにはPOSTを完全に通過する必要があります。
  • カーネルパニックやメモリ破損:kexecは古いカーネルから壊れたハードウェア状態を引き継ぐ可能性があります。
  • ハードウェアの変更(RAM追加、ディスク追加):BIOSが新しいデバイスを再検出する必要があります。
  • EFI Secure Bootのシステム:一部のディストリビューションはSecure Bootが有効な状態でkexecをサポートしていません(カーネル設定に依存)。

カーネルがkexecをサポートしているか確認する

# CONFIG_KEXECを確認
grep CONFIG_KEXEC /boot/config-$(uname -r)
# 確認が必要: CONFIG_KEXEC=y

# CONFIG_KEXEC_FILEを確認(kexec -lはこれを使用)
grep CONFIG_KEXEC_FILE /boot/config-$(uname -r)
# CONFIG_KEXEC_FILE=y

Ubuntu、Debian、RHELのデフォルトカーネルはほとんどがどちらも有効になっています。自分でビルドしたカーネルの場合は、make menuconfigProcessor type and featuresセクションで有効にしてください。

kdumpとkexec:どんな関係があるのか

kdump——カーネルクラッシュダンプをキャプチャするツール——も内部でkexecを使用しています。kdumpは小さなキャプチャカーネルを予約メモリ領域に読み込み、メインカーネルがパニックすると、コアダンプを書き込むためにキャプチャカーネルへ自動的にkexecします。kdumpを使用している場合でも心配不要です——独立したメモリ領域を使用するため、通常のkexec再起動と競合しません。

まとめ

kexecはLinuxの知られざる機能の中でも、極めて実用的なものの一つです。カーネルパッチ適用時のダウンタイムを最小化したい本番サーバーには、kpatchやlivepatchのような複雑なライブパッチングよりも、はるかにシンプルで効果的な解決策です。

典型的なフロー:apt upgrade → 新しいカーネルをkexec -l → サービスのグレースフルシャットダウン → systemctl kexec。再起動プロセス全体が3分ではなく30秒未満で完了します。多数のノードを運用するシステムでは、この差が積み重なると非常に大きなものになります。

Linuxサーバーを運用していてまだkexecを知らなかったなら、次回のカーネルアップデート時にぜひ試してみてください——初めて使ったときから違いは一目瞭然です。

Share: