最近、Dracutを使ってinitrdをカスタマイズしたのでその時のことをまとめます。
DracutはRed Hat系のディストリビューションで使われているinitrdをカスタマイズするためのツールです。
バージョンは041を対象とします。
ブートプロセス
本題ではないのですが、簡単に説明しておきます。
-
GRUBなどのブートローダが起動する
-
ブートローダがカーネルを読み込み。initrdを仮のrootfsとして起動する
-
その後、本物のrootfsをマウントして、本物のinitを起動する
ここ5年くらいのLinuxだと、こんな感じです。 initrdを作るツールがDracutだったり、initramfs-toolsだったり、本物のinitがsystemdだったり、シェルスクリプトだったりします。
initrd の展開方法
まずはinitrdの中身を確認する方法を紹介します。自分が作ったinitrdが意図通りできているかどうか確認したり、他の人が作ったinitrdを展開して確認したりするために必要です。
ほとんどの場合はgzipで圧縮されたcpioアーカイブなので以下のコマンドでカレントディレクトリに展開することができます。
$ mkdir -p /tmp/initrd
$ cd /tmp/initrd
$ zcat /boot/initrd.img | cpio -idmv
展開すると以下のようなディレクトリ構成になっています。 initrdは仮のrootfsなので、見覚えのある感じではないでしょうか。
$ tree -F -L 1
.
├── bin -> usr/bin/
├── dev/
├── etc/
├── init -> /usr/lib/systemd/systemd
├── lib -> usr/lib/
├── lib64 -> usr/lib64/
├── proc/
├── root/
├── run/
├── sbin -> usr/sbin/
├── shutdown*
├── sys/
├── sysroot/
├── tmp/
├── usr/
└── var/
14 directories, 2 files
Red Hat系ではinitにsystemdを採用しているのでinitが/usr/lib/systemd/systemdへのシンボリックリンクになっています。
このうちDracutに関係するファイルはusr/lib/dracut/以下にまとまっています。
initrdのカスタマイズ方法
initrdをカスタマイズする目的は、いくつかあります。
-
ISOイメージからrootfsをマウントしたい -> LiveDVD や LiveCD
-
ネットワークからrootfsをマウントしたい -> ディスクレスブート、シンクライアント
-
暗号化されたディスクを復号してrootfsとしてマウントしたい
-
OSの起動前に、OSのバージョンチェックをしたい -> キオスク端末の自動更新
Dracutは、シェルスクリプトをモジュール化して管理しています。 initrdの中身では、Dracut関連のファイルはusr/lib/dracut/以下にあり、フックごとにまとまっているためどのモジュールのファイルなのかわかり辛くなっています。
フックの種類は以下の通りです。
-
cmdline
- カーネルのブートオプションをパースするとき
-
pre-udev
- udev を初期化する前にudevのルールをここで生成する
-
pre-trigger
- デバイスの初期化をすることが多い
-
initqueue
- 時間のかかる処理をキューに登録する
-
pre-mount
- マウント前に必要な処理をする
-
mount
- ファイルシステムをマウントする
-
pre-pivot
- switch_root する前に実行する
-
cleanup
- 本物の init を実行する前に実行される
Dracutのモジュールの作り方
Dracutのモジュールを自作すれば、上記のフックを利用して目的に合うrootfsを作ることができます。
Dracutのモジュールは作るだけなら簡単です。
dracutコマンドを実行するホスト上の/usr/lib/dracut/以下に所定のファイルを置くだけです。 例えば、LiveISOを起動するためのモジュールは以下のようになっています。
$ tree /usr/lib/dracut/modules.d/90dmsquash-live/
/usr/lib/dracut/modules.d/90dmsquash-live/
├── apply-live-updates.sh
├── checkisomd5@.service
├── dmsquash-live-genrules.sh
├── dmsquash-live-root.sh
├── dmsquash-liveiso-genrules.sh
├── iso-scan.sh
├── module-setup.sh
├── parse-dmsquash-live.sh
└── parse-iso-scan.sh
このうち必須のファイルは module-setup.sh のみです。 module-setup.sh にモジュールをどのようにインストールするかをルールに従って記述します。
以下の4つの関数を定義すると、dracutコマンドから自動的に実行されます。
-
install()
- コマンド、スクリプト、フック等をinitrdに組込む
-
installkernel()
- initrdに組込むカーネルモジュールを指定する
-
depends()
- このモジュールが依存している他のモジュールを指定する
-
check()
- initrdにこのモジュールがインストール可能かどうかチェックする
詳細はREADME.modulesを参照してください。
モジュールを所定のパスに置いたら、設定ファイルを/etc/dracut.conf.d/以下に置きます。
filesystems+="vfat msdos isofs ext4 xfs btrfs "
add_dracutmodules+=" my-module"
add_drivers+=" sr_mod sd_mod ide-cd cdrom ehci_hcd uhci_hcd ohci_hcd usb_storage usbhid uas "
hostonly="no"
dracut_rescue_image="no"
設定ファイルを用意したらdracutコマンドでinitrdを生成します。
# dracut /boot/initramfs-$(uname -r).img
まとめ
Dracutの使い方を簡単に紹介しました。
Dracutのモジュールを自作すれば、目的に合ったinitrdを作ることができますが、実際に作るためには様々な知識が必要になります。 例えば、FedoraのLiveISOを起動できるようなDracutのモジュールを自作することを考えると、次のような知識が必要となります。
-
device-mapper
-
squashfs
-
loop back device
-
udev rules
-
plymouth
-
SELinux
Dracutのリポジトリに含まれているドキュメントやモジュールを読むだけでも、かなり色々なことがわかるのでDracutのモジュールを自作する必要があるときは、Dracutのソースコードを読むことをおすすめします。