Linux の chroot を使いこなす:Live USB からのシステム救出とリカバリ

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

クイックスタート:5分以内に chroot 環境へ入る

サーバーが起動しない。深夜2時。手元には Live USB と締め切りがある。これが最速で動作する chroot 環境に入る方法だ。

Live USB(Ubuntu、Debian、Arch — どれでも大差ない)から起動してターミナルを開き、以下を実行する:

# ルートパーティションを確認する
lsblk

# 壊れたシステムのルートパーティションをマウントする
mount /dev/sda2 /mnt

# 必須の仮想ファイルシステムをマウントする
mount --bind /dev /mnt/dev
mount --bind /proc /mnt/proc
mount --bind /sys /mnt/sys
mount --bind /run /mnt/run

# 壊れたシステムへ入る
chroot /mnt /bin/bash

以上だ。これで root として壊れたシステムのファイルシステムの内部で操作できる。パスワードのリセット、ブートローダーの再インストール、壊れたパッケージの修復など、通常の稼働中システムでできることはすべて実行可能になる。

一点注意しておくと、LVM 構成のシステムや、ルートパーティションが分かりにくいディスクにある場合、lsblk の出力が異なって見えることがある。迷ったら fdisk -lblkid で確認し、実際にマウントしたいデバイスを特定しよう。

chroot が内部で実際に何をしているか

chroot(「change root」の略)は、現在のプロセスとそこから生成されるすべてのプロセスに対してルートディレクトリを再マッピングする Unix システムコールだ。chroot 内のプロセスからは /mnt/ として見える。そのマウントポイントより上は一切見えない。

救出作業においては、まさにそれが必要なものだ。パッケージマネージャー、ブートローダーツール、設定ファイルはすべて、壊れたシステムが正常に動作しているかのように振る舞う。それらの視点からすれば、実際そうなのだから。

仮想ファイルシステムのマウントが欠かせない理由

/dev/proc/sys/run への --bind マウントは飾りではない。一つでも省略すると、欠落したマウントとはまったく無関係に見えるエラーが発生する:

  • /dev — デバイスノードがなくなる。grub-install はこれがないと何も言わずに失敗する
  • /proc — プロセス情報が取得できなくなる。ほとんどのシステムツールがクラッシュするか誤った値を返す
  • /sysカーネルインターフェースが失われる。ハードウェア関連の操作が動作しなくなる
  • /run — ランタイムデータが失われる。systemd に触れるものはすべて誤動作する

これらを一つでも忘れると、本当の原因に気づくまで謎のエラーを20分追いかけることになる。

EFI と独立した boot パーティションの扱い

最近のシステムの多くは、専用の EFI システムパーティション(ESP)を持つ UEFI を使用している。ブートローダーを修復するにはそれもマウントする必要がある:

# EFI パーティションを探す(通常は FAT32、約 512MB)
lsblk -f | grep -i vfat

# マウントする
mount /dev/sda1 /mnt/boot/efi

# /boot も独立したパーティションの場合
mount /dev/sda3 /mnt/boot

ディスクレイアウトを決め打ちにする前に、必ず fstab と照合して確認しよう:

cat /mnt/etc/fstab

実際の救出シナリオと実用コマンド

シナリオ1:忘れた root パスワードをリセットする

Live USB を引っ張り出す最も一般的な理由だ。chroot に入ってしまえば、コマンド2つで完了する:

passwd root
# または特定ユーザーの場合:
passwd username

シングルユーザーモードのやり方を覚える必要も、カーネルのブートパラメータをいじる必要もない。これだけで終わりだ。

シナリオ2:アップデート失敗後に GRUB を再インストールする

本番の Ubuntu 22.04 サーバーで実際にやられた話だ。カーネルアップデート中に停電が重なり、システムは GRUB rescue プロンプトで止まって先に進む方法が見当たらなかった。chroot 内からのコマンド2つで完全に修復できた:

# chroot 内から(BIOS/MBR システムの場合)
grub-install /dev/sda
update-grub

UEFI システムの場合は少し異なる:

grub-install --target=x86_64-efi --efi-directory=/boot/efi --bootloader-id=ubuntu
update-grub

GRUB rescue プロンプトから直接作業するのは苦痛だ。環境が切り詰められていて、使いたいコマンドの半分がない。chroot があればシステムのフルツールセットが使えるので、10分で終わる修復と1時間の試行錯誤の差が生まれる。

シナリオ3:壊れたパッケージマネージャーを修復する

中断された apt upgradedpkg の実行により、パッケージデータベースが半設定状態で止まることがある。chroot 内から:

# 中断されたインストールを再開する
dpkg --configure -a

# 特定の壊れたパッケージを強制再インストールする
apt-get install --reinstall linux-image-generic

# apt 自体が問題の場合
dpkg --audit
apt-get -f install

RPM ベースのシステム(RHEL、AlmaLinux、Fedora)には対応するコマンドがある:

rpm --rebuilddb
dnf reinstall systemd

シナリオ4:/etc/fstab の誤編集から回復する

/etc/fstab の1文字のミスで、起動時にシステムが緊急モードに落ちることがある。原因はほとんどの場合、UUID の入力ミスだ。chroot からは単純なファイル編集で済む:

nano /etc/fstab
# または
vim /etc/fstab

正しい UUID は blkid で確認できる。すべてのブロックデバイスとその UUID が一覧表示されるので、コピー&ペーストで確実に入力できる:

blkid

シナリオ5:chroot 前に LUKS 暗号化ボリュームをアンロックする

フルディスク暗号化の場合、マウント前にもう一手順必要だ:

# LUKS コンテナを開く
cryptsetup open /dev/sda2 cryptroot

# 復号化したボリュームをマウントする
mount /dev/mapper/cryptroot /mnt

# LUKS の上に LVM がある場合
vgscan
vgchange -ay
mount /dev/mapper/ubuntu--vg-ubuntu--lv /mnt

深夜2時に本当に助かる実践的なコツ

救出スクリプトを手元に置いておく

プレッシャーの中でマウントコマンドを記憶から打ち込むのはタイポの原因になる。このスクリプトを USB スティックやパスワードマネージャーのメモに保存しておこう。マウントとクリーンアップを自動で処理してくれる:

#!/bin/bash
# rescue-chroot.sh — マウントして chroot へ入る
set -e

ROOT_PART="${1:-/dev/sda2}"
MOUNT_POINT="/mnt"

mount "$ROOT_PART" "$MOUNT_POINT"
for fs in dev proc sys run; do
  mount --bind "/$fs" "$MOUNT_POINT/$fs"
done

echo "$ROOT_PART の chroot へ入ります..."
chroot "$MOUNT_POINT" /bin/bash

# 終了時にクリーンアップ
for fs in run sys proc dev; do
  umount "$MOUNT_POINT/$fs"
done
umount "$MOUNT_POINT"
echo "クリーンにアンマウントしました。"

使い方:bash rescue-chroot.sh /dev/sda2

必ずクリーンにアンマウントする

作業が終わったら chroot シェルを抜け、逆順にアンマウントする:

exit

umount /mnt/run
umount /mnt/sys
umount /mnt/proc
umount /mnt/dev
umount /mnt

これを省略するとファイルシステムのジャーナルが汚れた状態になる。最善の場合は次回起動時の fsck に余計な時間がかかるだけだが、最悪の場合は実際のファイルシステム破損につながる。深夜3時にどちらも遭遇したくない結末だ。

chroot 内で DNS が動かない場合の解決策

chroot 内からパッケージをダウンロードしたりアップデートを実行したりする必要がある場合、名前解決はデフォルトで壊れている。次のコマンド1つで修正できる:

cp /etc/resolv.conf /mnt/etc/resolv.conf

Live 環境の DNS 設定を chroot 内にコピーすることで、aptdnf が正常にインターネットへアクセスできるようになる。

Exec format error:アーキテクチャ不一致の問題

chroot: failed to run command '/bin/bash': Exec format error が出る場合、Live USB とターゲットシステムの CPU アーキテクチャが異なっている。よくあるのは、x86_64 のノート PC から Raspberry Pi や ARM サーバーのイメージに chroot しようとするケースだ。修正には QEMU ユーザーモードエミュレーションが必要になる:

apt-get install qemu-user-static
cp /usr/bin/qemu-aarch64-static /mnt/usr/bin/
chroot /mnt /bin/bash

通常の x86 サーバーと並行して ARM ハードウェアを管理するようになると、これに出くわす頻度は思っているより高くなる。

正しいシステムの内部にいることを確認する

chroot に入った直後に行うサニティチェックは10秒で済み、多くの混乱を防いでくれる:

# Live USB のホスト名ではなく、壊れたシステムのホスト名が表示されるはず
hostname

# 壊れたシステムの OS リリース情報が表示されるはず
cat /etc/os-release

# 壊れたシステムにインストールされたパッケージが表示されるはず
dpkg -l | head -20

これらのいずれかが壊れたシステムではなく Live USB のデータを表示している場合、マウントに問題がある。正しいパーティションを指定したか確認しよう。USB から起動している場合、/dev/sda2/dev/sdb2 の取り違えがほとんどの原因だ。

Share: