systemdブート問題の解決:一般的な問題と解決策
Linuxのブート問題は、システム管理者やパワーユーザーにとって最も頭を悩ませる問題の1つです。システムが起動しない場合、最初のステップは、ブートプロセスが正常に完了するのを妨げている「何か」を特定することです。最新のLinuxディストリビューションにおける主要なシステムおよびサービスマネージャーとして、systemdは初期のカーネルハンドオーバーから必要なすべてのサービスの起動に至るまで、ブートシーケンスのオーケストレーションにおいて極めて重要な役割を果たします。
この記事は、systemd関連の一般的なブート障害を理解し、解決するための包括的なガイドです。ブートログの分析、問題のあるサービスの特定、複雑なユニット順序付けの競合のトラブルシューティングに関する実践的な方法について深く掘り下げます。この記事を読み終える頃には、ブート問題の診断と修正のための体系的なアプローチを習得し、自信を持ってLinuxシステムを正常な状態に戻せるようになるでしょう。
systemdブートプロセスの理解
Systemdは、「ユニット」のシステムを通じてLinuxのブートプロセスを管理します。これらのユニットは、サービス(.service)、マウントポイント(.mount)、デバイス(.device)、ターゲット(.target)など、さまざまなシステムリソースとサービスを記述します。ターゲットは他のユニットをグループ化し、multi-user.target(従来のランレベル3)やgraphical.target(ランレベル5)のように、ブートプロセス中の特定の同期ポイントや状態を表す特殊なユニットです。
ブートプロセスは通常、次のステップを含みます。
1. カーネル初期化: カーネルがロードされ、ハードウェアが初期化されます。
2. Initramfsステージ: ルートファイルシステムをマウントするために必要な必須のドライバとツールを含む、初期RAMファイルシステムがロードされます。
3. systemd起動: systemdがPID 1として制御を引き継ぎ、default.target(多くの場合、multi-user.targetまたはgraphical.targetへのシンボリックリンク)を起動します。
4. ユニットのアクティベーション: systemdはユニットファイルを読み取り、依存関係を解決し、高い並行性でサービスとマウントを開始します。
ブート問題はこれらのステージのいずれかで発生する可能性がありますが、この記事では主にsystemdが起動した後に現れる問題に焦点を当てます。
初期トリアージ:ブートログへのアクセス
システムが正常にブートしない場合、最初かつ最も重要なステップはブートログにアクセスすることです。これらのログは、何が問題だったかの手がかりを提供します。システムがグラフィカル環境や標準のTTYにさえブートしない場合は、代替手段を使用する必要があります。
1. journalctlの使用(レスキューモード/緊急モード、またはライブメディアから)
journalctlはsystemdジャーナルを照会するためのユーティリティです。システムがレスキューモードまたは緊急モードで起動できる場合、あるいはディスクにアクセスするためにライブUSB/CDを使用している場合、journalctlが主要なツールとなります。
前回のブートのログを表示するには:
journalctl -b -1
システムが起動してからのすべてのメッセージを表示するには:
journalctl -b
失敗したユニットに関連するログを表示するには:
journalctl -b -p err..emerg # エラー、クリティカル、アラート、緊急メッセージを表示
journalctl -b --since "-5min" # 現在のブートの過去5分間のログを表示
ライブ環境を使用している場合は、まずシステムのルートパーティションにchrootして、そのジャーナルファイルにアクセスする必要があります。
2. dmesgの使用
dmesgはカーネルリングバッファを表示し、ブート中にカーネルから送られたメッセージが含まれています。これは、systemdが完全に制御を引き継ぐ前、ブートプロセスの非常に初期に発生する問題に特に役立ちます。
dmesg
3. ユニットステータスの確認
使用可能なシェル(レスキューモード、緊急モード、またはchrootを使用したライブ環境)に入ったら、すべてのsystemdユニットのステータスを確認できます。
systemctl --failed
このコマンドは、起動に失敗したすべてのユニットをリストアップします。特定の失敗したユニットの詳細情報を表示するには、次のようにします。
systemctl status <unit_name>.service
その特定のジャーナルエントリを表示するには:
journalctl -u <unit_name>.service -b
一般的なsystemdブートの問題と解決策
1. サービス障害とユニットの失敗
問題: 重要なサービスが起動に失敗し、システムが目的のターゲット(例:multi-user.target)に到達できなくなります。これは、システムが緊急モードに陥ることで現れることがよくあります。
症状: systemctl --failedが「failed」状態の1つ以上のユニットを示す。journalctl -u <unit_name>.serviceがサービスが起動できなかった理由を示すエラーメッセージを明らかにします。
一般的な原因:
* 設定の誤り: 設定ファイル内のタイポ、パスの誤り、依存関係の欠落。
* ファイル/依存関係の欠落: サービスが、存在しない、またはアクセスできないファイルやディレクトリにアクセスしようとする。
* リソース枯渇: サービスが過剰なメモリやその他のリソースを割り当てようとする。
* 権限の問題: サービスがファイルやコマンドの実行に必要な読み取り/書き込み権限を持っていない。
解決策:
1. 失敗したユニットの特定: systemctl --failedを使用します。
2. ログの検査: 詳細なエラーメッセージについては、journalctl -u <unit_name>.service -bを実行します。
3. 設定の修正: サービスの設定ファイル(例:/etc/systemd/system/<unit_name>.serviceまたは/etc/内のファイル)を編集します。ExecStart、WorkingDirectory、User、Group、Environmentディレクティブに注意してください。
4. 依存関係の確認: すべてのWants=、Requires=、After=、Before=ディレクティブが正しく指定されており、必要なサービスが有効になっていることを確認します。
5. 再起動と再有効化: 変更を加えた後、systemctl daemon-reloadを実行し、次にsystemctl start <unit_name>.serviceおよびsystemctl enable <unit_name>.serviceを試みます。
例: カスタムWebサービスmywebapp.serviceが、データベースを利用できないために失敗します。
# ステータスの確認
systemctl status mywebapp.service
# 手がかりのためにログの確認
journalctl -u mywebapp.service -b
# ユニットファイルの編集(例:/etc/systemd/system/mywebapp.service内)
# データベースが先に起動するようにAfterディレクティブを追加/変更
# 例: After=postgresql.service mysql.service
# systemdをリロードして再試行
systemctl daemon-reload
systemctl start mywebapp.service
systemctl enable mywebapp.service # 次のブート時に起動するようにする
2. ファイルシステムの問題
問題: ファイルシステムの破損や/etc/fstabの不正確なエントリにより、重要なパーティションのマウントができなくなり、緊急モードにつながります。
症状: fsckの失敗、mountエラーに関するエラーメッセージ、または「メンテナンスのためにrootパスワードを入力してください(またはControl-Dを押して続行)」というメッセージとともにシステムがemergency modeに陥ること。
一般的な原因:
* ダーティファイルシステム: 不適切なシャットダウン、停電。
* /etc/fstabの誤り: UUID/デバイスパスのタイポ、ファイルシステムタイプの誤り、非重要マウントに対するnoautoの欠落。
* ハードウェア障害: ディスクの破損。
解決策:
1. 緊急モードへのアクセス: プロンプトが表示された場合は、rootパスワードを入力します。
2. /etc/fstabの確認: /etc/fstabを注意深く確認し、エラーがないか確認します。疑わしい行は一時的に#でコメントアウトします。
3. fsckの実行: ファイルシステムを手動でチェックおよび修復します。例えば、/dev/sda1がルートパーティションの場合:
bash
# 可能であればアンマウント(ルート以外のパーティションの場合)、またはfsckパラメータを指定してリブート
umount /dev/sda1
fsck -y /dev/sda1
ヒント: ルートパーティションをアンマウントできない場合は、ライブUSBからブートして、そこからfsckを実行する必要があるかもしれません。
4. 再起動: 変更を加えた後、またはfsckを実行した後、再起動を試みます。
3. 依存関係の競合とユニットの順序付け
問題: サービスが間違った順序で起動したり、ユニット間で依存関係が競合したりすることで、デッドロックや失敗が発生します。
症状: サービスのタイムアウト、依存関係が準備できていないためにサービスが失敗する、systemd-analyze plotが長いチェーンやサイクルを示す。
一般的な原因:
* ユニットファイル内のWants=、Requires=、After=、Before=ディレクティブの設定ミス。
* リソースがまだ利用可能でないことを想定しているユニット。
解決策:
1. ブートシーケンスの分析: systemd-analyzeを使用してブートプロセスを視覚化します。
* systemd-analyze blame: 起動時間順にサービスをリスト表示し、遅いユニットを強調表示します。
* systemd-analyze critical-chain: 全体的なブート時間に直接影響を与えるユニットのクリティカルパスを示します。
* systemd-analyze plot > boot.svg: 複雑な問題に非常に役立つ、ブート依存関係グラフ全体のSVG画像を生成します。
-
ユニット依存関係の検査:
systemctl list-dependencies <unit_name>を使用して、ユニットが必要とするものと、それに依存するものを確認します。 -
ユニットファイルディレクティブの調整:
After=、Before=: ユニットの順序を制御します。A.serviceがAfter=B.serviceを持つ場合、B(起動する場合)の後にAが起動します。ほとんどの順序付けのニーズにはAfter=を使用します。Wants=: 弱い依存関係を表します。A.serviceがWants=B.serviceを持つ場合、Aが起動するときにBも起動しますが、Bが失敗してもAは続行します。Requires=: 強い依存関係を表します。A.serviceがRequires=B.serviceを持つ場合、Aが起動するときにBも起動し、Bが失敗または停止した場合、Aも停止します。Conflicts=: 現在のユニットが起動された場合、特定のユニットが停止することを保証し、その逆も同様です。PartOf=: あるユニットのライフサイクルを別のユニットにリンクします(例:sliceが停止されると、それにPartOfであるすべてのユニットも停止されます)。
ヒント: デッドロックや障害の連鎖を防ぐために、タイトな結合を避けるため、ほとんどの依存関係には常に
After=とWants=を優先してください。
4. カーネルパニック/Initramfsの問題
問題: システムが非常に早い段階で起動に失敗し、systemdが完全に制御を引き継ぐ前に、「Kernel panic - not syncing」やdracutやinitramfsに関するメッセージが表示されることが多いです。
症状: 早期のブート失敗。スタックトレースや、ルートデバイスの欠落、/dev/rootが見つからないなどに関するメッセージがテキストで大量に表示されることが多いです。
一般的な原因:
* カーネルモジュールの欠落: Initramfsにルートファイルシステム(LVM、RAID、特定のディスクコントローラなど)に必要なドライバが含まれていない。
* カーネル/Initramfsの破損: ファイルが損傷している。
* カーネルパラメータの誤り: GRUBのroot=パラメータが間違ったデバイスを指している。
解決策:
1. Initramfsの再構築: これは一般的な修正方法です。ライブ環境または別のカーネルでブートし、システムにchrootして、initramfsを再構築します。
```bash
# Dracut(Fedora/RHEL/CentOS)の例
dracut -f -v /boot/initramfs-$(uname -r).img $(uname -r)
# mkinitcpio(Arch Linux)の例
mkinitcpio -P
# update-initramfs(Debian/Ubuntu)の例
update-initramfs -u -k all
```
- GRUB設定の検証: 適切な
root=パラメータとinitrdパスのために/boot/grub/grub.cfg(または再生成する場合は/etc/default/grub)を確認します。 - カーネルパラメータ: 特定のモジュールが不足している、または問題を引き起こしていると思われる場合は、GRUBでカーネルパラメータを追加してみてください(例:initramfsシェルでデバッグするために
rd.break)。
5. GRUB/ブートローダーの問題
問題: システムはカーネルがロードされる段階にさえ到達しないか、GRUBメニューで停止します。
症状: 「No boot device found」というメッセージ、GRUBレスキュープロンプト、またはGRUBがカーネルのロードに失敗する。
一般的な原因:
* ブートローダーの破損。
* 存在しないカーネル/initramfsを指す不正確なGRUB設定。
* 適切なブート順序を防ぐBIOS/UEFI設定。
解決策:
1. GRUBの再インストール: ライブUSBからブートし、システムにchrootして、MBR/EFIパーティションにGRUBを再インストールします。
```bash
# 例
mount /dev/sdaX /mnt # ルートパーティションのマウント
mount /dev/sdaY /mnt/boot/efi # 別のEFIパーティションがある場合
for i in /dev /dev/pts /proc /sys /run; do mount --bind $i /mnt$i; done
chroot /mnt
grub-install /dev/sda # メインディスクへのインストール
grub-mkconfig -o /boot/grub/grub.cfg # GRUB設定の再生成
exit
umount -R /mnt
reboot
```
- BIOS/UEFI設定の確認: 適切なブートドライブが優先順位付けされていることを確認します。
高度なトラブルシューティング技術
レスキューモード/緊急モードでの起動
これらのモードは、トラブルシューティングのための最小限の環境を提供します。これらに入るには:
- GRUB中:
eを押してカーネルコマンドラインを編集します。 linux行の特定:linux(またはlinuxefi)で始まる行を見つけます。- レスキューモードの場合: レスキューモード(ほとんどのサービスは停止され、シングルユーザーシェル)の場合は、
systemd.unit=rescue.targetを追記します。 - 緊急モードの場合: 緊急モード(最小限のサービス、多くの場合ルートが読み取り専用)の場合は、
systemd.unit=emergency.targetを追記します。 Ctrl+XまたはF10を押してブートします。
Initramfsデバッグのためのrd.breakの使用
GRUBのカーネルコマンドラインにrd.breakを追記すると、実際のルートファイルシステムがマウントされる前に、initramfs 内のシェルにドロップされます。これは、LVM/RAID設定の問題やドライバの欠落など、initramfsの問題をデバッグするのに非常に役立ちます。
initramfsシェルに入ると、次のことが可能です。
* lsblk、mountの検査。
* /sysroot内のファイルの確認。
* ルートファイルシステムを手動でマウントしようとすること。
ブートパフォーマンスの分析
これは厳密には「障害」ではありませんが、ブート時間の遅延は、根本的な問題や非効率的なサービス設定を示している可能性があります。
systemd-analyze blame: 起動に最も時間がかかるサービスを特定します。systemd-analyze critical-chain: 全体的なブート時間に影響を与える依存関係のクリティカルパスを理解します。
これらのツールを使用してボトルネックを特定し、After=、Requires=、TimeoutStartSec=、またはType=ディレクティブを調整することで、ユニットの起動を最適化します。
予防とベストプラクティス
- 変更のテスト: ユニットファイルの変更を本番環境にデプロイする前に、ステージング環境でテストします。
- 設定のバックアップ:
/etc/、または少なくとも重要な/etc/systemd/system/ファイルを定期的にバックアップします。 - ユニットディレクティブの理解:
systemd.service(5)およびsystemd.unit(5)のマニュアルページをしっかり理解することは非常に貴重です。 - ドロップインファイルの使用: (更新によって上書きされる可能性がある)
/lib/systemd/system/のユニットファイルを直接変更する代わりに、ドロップインファイル(/etc/systemd/system/<unit_name>.service.d/*.conf)を使用してカスタム設定を行います。 - カーネルの保持: 新しいカーネルが問題を引き起こした場合に備えて、常に少なくとも1つの既知の正常な古いカーネルをシステムに保持しておきます。
結論
systemdのブート問題の解決には体系的なアプローチが必要です。効果的なログ分析から始めることが重要です。systemdのユニットベースのアーキテクチャを理解し、journalctl、systemctl、systemd-analyzeなどのツールを活用することで、設定ミスのあるサービス、ファイルシステムの問題、または複雑な依存関係の競合など、ブート障害の根本原因を効率的に特定できます。レスキューモードまたは緊急モードで起動する機能と高度なデバッグ技術を組み合わせることで、たとえシステムが完全に反応しないように見えても、制御を取り戻すことができます。これらの戦略とベストプラクティスにより、ほとんどのsystemdブートの課題に対処し、安定した信頼性の高いLinux運用を維持するための十分な準備が整います。