Linuxのブータブルディスクの仕組みが気になったので手作りする方法を調べてみました。
ちなみにRedHat系OSであればloraxパッケージに含まれるlivemedia-creatorコマンドで簡単に作成できます。[1]
# livemedia-creator --make-iso --ks=/path/to/valid/kickstart.ks --no-virt
ブータブルISOについて
ISOの規格
ご存知のとおり、CD/DVDのフォーマットはISO9660で標準化されていますが、オリジナルの規格はファイル名等の制約が厳しいため様々な拡張規格が定義されています。
ISOファイルからのシステムブートはEl Toritoという拡張規格で定義されています。[2]
Linuxのブータブルディスク
LinuxシステムをISOからブートするにはISOLINUXという軽量ブートローダーを利用します。ISOLINUXはSYSLINUXに含まれるコンポーネントの一つです。
SYSLINUXはLinux向けの軽量ブートローダーを提供するプロジェクトで、いくつかのコンポーネントを含んでいます。例えばSYSLINUXコンポーネントはFAT32ファイルシステムから、PXELINUXはネットワークからシステムをブートするためのブートローダーを提供しています。[3]
例としてCentOS7のインストーラを見てみます。
CentOS7のインストーラーもCD/DVDからブートするLinuxシステムです。
インストーラーISOマウントすると(もしくはCentOSミラーの os/x86_64/ ディレクトリを開くと)isolinuxというディレクトリが含まれています。このディレクトリにはブートローダーである isolinux.bin、ブートメニューや起動オプション等を指定するisolinux.cfg、そのほかカーネルイメージvmlinuzや初期RAMディスクinitrd.imgが含まれています。
http://one.of.a.mirror/centos/7/os/x86_64/isolinux/
boot.msg 2018-05-03 20:34 84
grub.conf 2018-05-03 20:34 281
initrd.img 2018-05-03 20:34 50M
isolinux.bin 2018-05-03 20:34 24K
isolinux.cfg 2018-05-03 20:34 3.0K
memtest 2016-11-05 16:27 186K
splash.png 2015-09-30 19:58 186
vesamenu.c32 2016-11-05 17:41 149K
vmlinuz 2018-04-20 16:57 5.9M
ちなみにルートファイルシステムは LiveOS/squashfs.img にあります。
このイメージはsquashfsという圧縮された読み取り専用のファイルシステムです。
イメージの中には LiveOS/rootfs.img が含まれていて、これがルートファイルシステムのイメージファイルになります。
ルートファイルシステムにはAnaconda(Pythonの環境構築ツールではありません)というプログラムが含まれていて、このプログラムがハードディスクにLinuxをインストールします。[4]
ブータブルISOを手作りする
環境と必要なツール類
このサンプルはVirtualBox上にインストールしたCentOS 7.5の環境で実行しています。作成したISOの起動試験もVirtualBox上の仮想マシンイメージで行っています。
なお作業はすべてroot権限で行っています。
SELinuxを無効化します。
# setenforce 0
必要なパッケージをインストールします。
# yum install genisoimage squashfs-tools
ルートファイルシステムの作成
最初に作業ディレクトリを掘ります。これ以降、特に明示していない場合はこの作業ディレクトリ内でコマンドを実行しています。
TMP="/var/make-disk/"
mkdir -p $TMP
cd $TMP
ルートファイルシステムとなるイメージを作成してEXT4でフォーマットします。
# dd if=/dev/zero of=rootfs.img bs=1M count=1200
# mkfs.ext4 -F rootfs.img
# file rootfs.img
rootfs.img: Linux rev 1.0 ext4 filesystem data, UUID=b1fd3d60-a9f0-4684-a45d-44332478be76 (extents) (64bit) (large files) (huge files)
ルートイメージをマウントして sys, proc, dev ディレクトリをマウントします。
# mkdir -p ./rootdir
# mount -o loop,rw,sync rootfs.img rootdir
# mkdir ./rootdir/{dev,proc,sys}
# mount -o bind /dev ./rootdir/dev
# mount -o bind /proc ./rootdir/proc
# mount -o bind /sys ./rootdir/sys
yumコマンドでルートイメージ内にLinuxの実行環境をインストールします。
yum install -y --installroot=${TMP}/rootdir --releasever=7 kernel coreutils passwd sudo
ユーザー cos を作成して root を無効化します。
cosにはパスワードなしでsudoを実行する権限を与えます。(パスワードなしでrootログインできるようにしてもいいですが...)
# chroot rootdir
(in chroot)# useradd cos
(in chroot)# passwd -d cos
(in chroot)# visudo
---
#%wheel ALL=(ALL) ALL
(...omit)
%wheel ALL=(ALL) NOPASSWD: ALL
---
(in chroot)# usermod -aG wheel cos
(in chroot)# usermod -L root
(in chroot)# exit
他にもキーボードやタイムゾーン等必要に応じて設定します。
これでルートファイルシステムは出来上がりです。この後カーネルと初期RAMディスクを取り出すのでイメージはマウントしたままにしておきます。
ISOの作成
ディレクトリを掘ります。
# mkdir -p mkdir isoroot/{boot,isolinux}
SYSLINUXをダウンロードして、解凍したディレクトリにあるブートローダーisolinux.binと ldlinux.c32モジュールをコピーします。
# curl -LO https://mirrors.edge.kernel.org/pub/linux/utils/boot/syslinux/syslinux-6.03.tar.gz
# tar -xvzf syslinux-6.03.tar.gz
# cp -a syslinux-6.03/bios/core/isolinux.bin isoroot/isolinux/
# cp syslinux-6.03/bios/com32/elflink/ldlinux/ldlinux.c32 isoroot/isolinux/
isolinux.cfgを作成します。詳しい設定はSYSLINUXのWebページを参照してください。[5]
# vi isoroot/isolinux/isolinux.cfg
---
default basic0
label basic0
kernel /boot/vmlinuz0
append initrd=/boot/initrd0 root=live:CDLABEL=linux rootfstype=auto ro rd.live.image rhgb rd.luks=0 rd.md=0 rd.dm=0
---
ルートファイルシステムにchrootしてISO用の初期RAMディスクを作成します。
既定で作成される初期RAMディスクには、ISOに含まれるルートファイルシステムをマウントするためのモジュールが含まれていないため、そのままでは使用できません。
# chroot ./rootdir
(in chroot)# dracut --xz --add "dmsquash-live convertfs pollcdrom" --omit plymouth --no-hostonly --no-early-microcode /boot/initrd0 `ls /lib/modules`
(in chroot)# exit
カーネルと初期RAMディスクをISOのディレクトリにコピーします。
# cp -a rootdir/boot/vmlinuz-3.10.0-862.9.1.el7.x86_64 ./isoroot/boot/vmlinuz0
# cp -a rootdir/boot/initrd0 ./isoroot/boot/initrd0
コピーしたらルートファイルシステムの/bootディレクトリにあるファイルは不要なので削除します。
# rm -rf rootdir/boot/*
rootファイルシステムイメージをアンマウントしてsquashfsで圧縮します。
# umount rootdir/sys
# umount rootdir/proc
# umount rootdir/dev
# umount rootdir
# mkdir -p squashfsroot/LiveOS
# mv rootfs.img squashfsroot/LiveOS/
# mksquashfs squashfsroot squashfs.img
作成したsquashfsイメージをISOのLiveOSディレクトリにコピーします。
# mkdir isoroot/LiveOS
# mv squashfs.img isoroot/LiveOS/
最終的にISOに含まれるファイルはこんな感じです。
./isoroot/
./isoroot/boot
./isoroot/boot/vmlinuz0
./isoroot/boot/initrd0
./isoroot/isolinux
./isoroot/isolinux/isolinux.bin
./isoroot/isolinux/ldlinux.c32
./isoroot/isolinux/isolinux.cfg
./isoroot/LiveOS
./isoroot/LiveOS/squashfs.img
最後にISOファイルを作成します。
# cd isoroot
# mkisofs -o ../cos7.iso -R -J -T -V linux -b isolinux/isolinux.bin -no-emul-boot -boot-load-size 4 -boot-info-table .
使用しているmkisofsの主要なオプションは次のような感じです
- -o 出力ファイル名
- -R, -J, -T ISO9660標準ではサポートされないファイル名を扱うためのオプションです。
- -V LABEL ISOのラベルを指定しています。上のサンプルでは "linux" を指定していますが、このディスクのラベルはisolinux.cfgに定義した"root=live:CDLABEL=linux"と対応させておく必要があります。
- -b El Toritoブートローダーであるisolinux.binを指定します。
作成したISOイメージを適当な仮想マシンにアタッチして起動してみてください。
手順に誤りがなければCentOS 7が起動してcosユーザーでログインできるはずです。
[1]https://access.redhat.com/documentation/ja-jp/red_hat_enterprise_linux/7/html/installation_guide/sect-disk-image-installation-automatic
[2]https://ja.wikipedia.org/wiki/ISO_9660
[3]https://www.syslinux.org/wiki/index.php?title=The_Syslinux_Project
[4]https://fedoraproject.org/wiki/Anaconda
[5]https://www.syslinux.org/wiki/index.php?title=Config