続・玩式草子 ―戯れせんとや生まれけん―

第54回Plamo Linux の遊び方(その5)

ここしばらく年末年始の雑用に忙殺されて間が空いてしまったものの、前回紹介した既存インストーラの改造に続き、今回はインストーラ用にinitramfsを新しく作成する手順を紹介しましょう。

仮想環境で小規模システムの構築

前回も触れたように、Plamo Linuxのインストーラは小さいながらも独立したLinux環境なので、カーネルやCライブラリ、シェル、設定ファイル、各種ツール等が必要になります。それらを手っ取り早く揃えるには仮想マシン上に小規模なシステムを構築するのが簡単で、今回はVirtualBoxを使ってインストーラ用のシステムを作ってみます。

コンテナ環境LXCにはPlamo用のコンテナを作るためのテンプレートが用意されているので、"lxc-create"コマンド1つで小規模なPlamo環境を作ることが可能なものの、この方法で作った環境は設定ファイルの一部がコンテナ用にカスタマイズされるため、自立した環境として使うには向いていません。

VirtualBoxにはインストールに使うISOイメージに応じて各種ディストリビューションに適した環境を自動的に用意する機能がありますが、残念ながらPlamo Linuxは対象外なので、今回は「64ビット版の2.6以降のLinux」「メモリは8GB」⁠HDDは32GB」⁠非EFI」な汎用環境にインストールすることにします。

図1 VirtualBox仮想マシンの設定
図1 VirtualBox仮想マシンの設定

EFIへの対応はインストーラではなくブートローダの仕事なので、この環境でEFIの有無は関係ありません。⁠非EFI」にしているのは、EFI環境にインストールするのに必要なESP(EFI System Partition)を作る手間を省くためだけです。

ISOイメージから起動してroot/rootでログイン、"setup"を実行してからのインストール手順は通常のPlamo Linuxと変わるところはありません。あえて注意すべき点をあげるなら、この環境は必要なファイル類を吸い出すための最小規模Linuxなので、⁠スワップパーティションは設定不要」⁠ファイルシステムは一番シンプルなext2で十分」といったところでしょうか。

インストールするパッケージは"01_minimum"カテゴリに限定しておきます。Plamo Linuxでは、ソフトウェアパッケージを用途ごとの「カテゴリ」に分類、整理しており、"01_minimum"はLinuxの基本コマンドをCUI環境で使えるようにするためのパッケージ群です。

図2 インストールするパッケージの選択
図2 インストールするパッケージの選択

インストール方法は"RECOM"を指定し、"00_base"と"01_minimum"カテゴリのパッケージを全てインストールします。インストール後のシステム設定ではgrubのインストールやrootパスワードの設定が求められるので適宜設定してください。

インストールが終了すれば再起動し、新しい環境が正しく動作することを確認します。確認できればいったんshutdownし、仮想マシンを停止します。

インストールしたシステムの吸い出しとinitramfs化

次は、この仮想環境のファイル一式をホスト側に吸い出す作業です。その際にはVirtualBoxに付属のvboximg-mountコマンドが便利です。"vboximg-mount"は、VirtualBoxが利用している仮想HDDをfuseを使ってホスト側から見えるようにするためのツールです。

"vboximg-mount"はVirtualBoxと共にインストールされ、通常は/opt/VirtualBox/に配置されます。

fuse(Filesystem in USErspace)は、本来はカーネルが担当するファイルシステムの操作をユーザ領域のアプリケーションから実現するための仕組みで、カーネルが対応していない種類のファイルシステムを操作する際に使われます。fuseを利用するにはカーネルモジュール(fuse.ko)が必要なので、まずこのモジュールをロードしておきます。

$ sudo modprobe fuse

デフォルトでは、fuseマウントした環境はそのマウントを実行した利用者しかアクセスできないものの、ファイルの吸い出しはroot権限で実行したいため、他の利用者からもfuseマウント環境を利用可能にしておきます。そのためにはfuse用の設定ファイル/etc/fuse.confに"user_allow_other"を追加します。

$ cat -n /etc/fuse.conf 
   1  # Set the maximum number of FUSE mounts allowed to non-root users.
   ...
   8  #
   9  user_allow_other

まずは、vboximg-mount -lでVirtualBox用に作成した仮想HDDを調べます。VirtualBoxが使用するHDDは、ファイルシステム上の位置に関係なくUUIDで識別されます。

$ vboximg-mount -l
-----------------------------------------------------------------
VM:   Plamo_installer
UUID: 8b803653-d056-4a96-bcd4-73b43dd98db2

    Image:   Plamo_installer.vdi
    UUID:    4792f9c4-244a-4017-a3c6-552d923e2edd

次にこの仮想HDDを適当なディレクトリにマウントします。fuseマウントは空でないディレクトリにマウントしようとするとエラーになるので、新たに"Tmpmnt"というディレクトリを作り、そこにマウントすることにします。"-o allow_root"はfuseマウントした内容にroot権限でのアクセスを可能にする指定です。

$ mkdir ./Tmpmnt
$ vboximg-mount -i 4792f9c4-244a-4017-a3c6-552d923e2edd -o allow_root ./Tmpmnt
$ ls ./Tmpmnt/
Plamo_installer.vdi@  vhdd  vol0

この Tmpmnt/以下に見えているのがVirtualBoxの仮想HDDの内部構成で、そのうちの"vol0"が実際のファイルシステムイメージです。このファイルシステムイメージをloopback経由でマウントして中身を取り出そう、というわけです。

$ sudo mount -o loop ./Tmpmnt/vol0 /loop
$ ls /loop
bin/   cdrom/  etc/   lib/    lost+found/  mnt/   root/  sbin/  tmp/  var/
boot/  dev/    home/  lib64/  media/       proc/  run/   sys/   usr/

仮想HDDを壊すと面倒なので、以後の作業用に/loop以下の環境一式を新たに作成したVboxHDDディレクトリに吸い出しておきます。

$ su
# mkdir VboxHDD ; cd VboxHDD
# cp -av /loop/* .
'/loop/bin' -> './bin'
'/loop/bin/bzip2' -> './bin/bzip2'
'/loop/bin/dialog' -> './bin/dialog'
...
# ls -alr
合計 32,768
drwxr-xr-x 12 root   root    190  3月  1日 2022年 var/
drwxr-xr-x 15 root   root    221  4月 18日 2023年 usr/
drwxrwxrwt  2 root   root     10  5月 30日 2017年 tmp/
...

ここまでの操作で./VboxHDD/以下に最小規模のPlamo Linux環境を取り込めました。次にこの環境をinitramfs用にするため、ルートディレクトリにinitを置きます。というのも、通常のHDD上のルートパーティションの場合とは異なり、initramfsでは/sbin/initではなく/initを起動するようになっているからです。そのため、/initから/sbin/initへのシンボリックリンクを作成します。

# ln -sf ./sbin/init .
# ls -l
合計 28,672
drwxr-xr-x  2 root root 4,096  2月 25日  14:38 bin/
...
lrwxrwxrwx  1 root root    11  2月 26日  23:45 init -> ./sbin/init*
...

この環境のboot/以下には起動用のカーネルイメージが置かれているものの、initramfsはブートローダによってカーネルと共に読み込まれるので、内部にカーネルを置く必要はありません。もっとも、ここにあるカーネルイメージは後でisolinux用に使うので、削除するのではなく、このディレクトリの外側に移動させておきましょう。

# mv boot ../

次に、この環境をinitramfs化するためcpio + zstdで固めます。

# find . | cpio -ov -Hnewc | zstd -12 > ../initramfs.tzst
.
./bin
./bin/bzip2
./bin/dialog
...
./var/db/sudo/lectured
./var/krb5kdc
./init
4068768 ブロック
# ls -lh ../initramfs.tzst 
-rw-r--r-- 1 root root 746M  2月 27日  00:04 ../initramfs.tzst

これで最新のPlamo Linuxを使った新しいinitramfsが完成しました。次に、このinitramfsをカーネルと共に読み込むブートローダを用意します。

syslinux/isolinuxの設定

カーネルやinitramfsをメモリに読み込むのがブートローダの役割です。Linux用のブートローダと言うと"GRUB2"を連想するものの、CD/DVDといったISO形式のメディアやUSBメモリを起動メディアにする場合はsyslinux/isolinuxというツールが便利です。

syslinuxの開発はここ10年ばかり停滞していて、公式リリースは2014年のsyslinux-6.03のままです。このバージョンのソースコードはチェックが厳しくなった最近のコンパイラではコンパイルできなくなっているものの、上記サイトで提供されているsyslinux-6.03.tar.xzには作成済みのバイナリも同梱されており、それらは今でも使えます。

さて、まずはsyslinux-6.03をダウンロード、展開しておきます。

$ wget https://mirrors.edge.kernel.org/pub/linux/utils/boot/syslinux/6.xx/syslinux-6.03.tar.xz
...
mirrors.edge.kernel.org (mirrors.edge.kernel.org)|147.75.48.161|:443 に接続しています... 接続しました。
HTTP による接続要求を送信しました、応答を待っています... 200 OK
長さ: 6855224 (6.5M) [application/x-xz]
`syslinux-6.03.tar.xz' に保存中
...
$ tar xvf syslinux-6.03.tar.xz
syslinux-6.03/
syslinux-6.03/efi32/
syslinux-6.03/efi32/com32/
...

取り出されたsyslinux-6.03/bios/以下にあるのが作成済みの各種イメージファイルです。

$ ls syslinux-6.03/bios
codepage/  core/  dos/      extlinux/  libinstaller/  lzo/  memdisk/  sample/  utils/       version.h  win64/
com32/     diag/  dosutil/  gpxe/      linux/         mbr/  mtools/   txt/     version.gen  win32/
$ ls syslinux-6.03/bios/core/
elflink/  isolinux-debug.bin  kwdhash.gen  ldlinux.bss  legacynet/   lpxelinux.bin  lzo/  pxelinux.0    thread/
fs/       isolinux.bin        ldlinux.bin  ldlinux.sys  lpxelinux.0  lwip/    

これらを使って起動可能なISOイメージを作成するため、まずは"ISOimage"という作業用ディレクトリを作り、その下にブート用ファイルを収める"isolinux"ディレクトリを作ります。

$ mkdir -p ISOimage/isolinux
$ ls ISOimg/
isolinux/

このisolinuxディレクトリに作成したinitramfsイメージとカーネルを配置します。最後のハードリンクはISO9660形式のファイル名制限を回避するための別名付けです。

$ cd ISOimg
$ mv ../initramfs.tzst ./isolinux
$ mv ../boot/vmlinuz-6.6.15-plamo64 ./isolinux
$ ( cd isolinux ; ln vmlinuz-6.6.15-plamo64 vmlinuz )

次にsyslinux-6.03/bios/からisolinux.binldlinux.c32をコピーします。isolinux.binはISOメディアから起動するためのブートセクタで、ldlinux.c32はLinuxカーネルをロードするための機能を提供します。

$ cp ../syslinux-6.03/bios/core/isolinux.bin isolinux/
$ cp ../syslinux-6.03/bios/com32/elflink/ldlinux/ldlinux.c32 isolinux/

次にisolinux.bin用に最低限の設定ファイル(isolinux.cfg)を用意します。isolinux.binはこの設定に従ってカーネルとinitramfsを読み込みます。

$ cat -n isolinux/isolinux.cfg
   1  prompt 1
   2  timeout 100
   3  default pl_install
   4  
   5  label pl_install
   6    kernel vmlinuz
   7    append initrd=initramfs.tzst root=/dev/ram0 ro net.ifnames=0 edd=off

1-3行目は「プロンプト」を出し「一定時間(100ms⁠⁠」入力が無ければ「デフォルト指定のpl_installの内容を実行する」という全体指定、5-7行目が今回用意したカーネルとinitramfsをロードする際の設定です。initramfsを使うのでルートパーティションは"/dev/ram0"、ネットワークデバイス名を伝統的なeth0にして(net.ifnames=0⁠⁠、たまに邪魔することのあるBIOSのEDD(Enhanced Disk Drive service)を無効にしています(edd=off⁠⁠。

必要なファイルが用意できたので、xorrisofsでこれらをISOイメージにまとめます。その際、isolinux/を含むディレクトリが指定対象になるので、作業用ディレクトリ(ISOimg/)の1つ上のディレクトリでxorrisifsを実行する必要があります。

$ cd .. ; ls ISOimg
isolinux/
$ ls ISOimg/isolinux/
initramfs.tzst  isolinux.bin  isolinux.cfg  ldlinux.c32*  vmlinuz*  vmlinuz-6.6.15-plamo64*

$ xorrisofs -o testimg.iso  -b isolinux/isolinux.bin -no-emul-boot \
  -boot-load-size 4 -boot-info-table ISOimg
GNU xorriso 1.5.6.pl01 : RockRidge filesystem manipulator, libburnia project.

Drive current: -outdev 'stdio:testimg.iso'
Media current: stdio file, overwriteable
Media status : is blank
...
Written to medium : 386549 sectors at LBA 0
Writing to 'stdio:testimg.iso' completed successfully.

$ ls -lh testimg.iso 
-rw-r--r-- 1 kojima users 755M  2月 27日  11:44 testimg.iso
$ file testimg.iso 
testimg.iso: ISO 9660 CD-ROM filesystem data 'ISOIMAGE' (bootable)

"xorrisofs"に与えたオプションを説明しておくと、"-o testimg.iso"が作成するISOイメージの名前、"-b isolinux/isolinux.bin"がブートセクタの指定、最後の"ISOimg"が作成対象のディレクトリ指定です。その他はほぼ呪文のようなものですが(苦笑⁠⁠、"-no-emul-boot"はエミュレーションモードを使わない指示、"-boot-load-size 4"はブートセクタが4ブロック分ある指定、"-boot-info-table"はISOイメージの配置情報を用意する指定です。

ISOイメージからのブートは"El Torito(エル・トリート)"と呼ばれる拡張仕様で定義され、現在ではこの仕様が普及しているものの、それ以前(90年代前半)はフロッピーディスクのデータを埋め込み、FD起動をエミュレートする形でCD-ROMからの起動を実現していました。"-no-emul-boot"はそのような仕組みではなくEl Toritoの仕様に準じたbootableイメージを作る指定で、"-boot-load-size"や"-boot-info-table"もそのための指定です。

新しいISOイメージのテスト

さて、それでは新たに作成したISOイメージからの起動を試してみましょう。そのためには最初に作ったVirtualBox環境を流用するのが簡単です。

まず、中身を吸い出すためにマウントした仮想HDDをアンマウントします。これを忘れると「HDDが利用中」とされ、仮想マシンが起動しません。

$ sudo umount /loop
$ umount Tmpmnt

次に仮想マシンの「設定⁠⁠→⁠ストレージ」から、ISOイメージを新たに作成した"testimg.iso"に変更します。

図3 ISOイメージの変更
図3 ISOイメージの変更

この状態で起動すると、新たに作成した"testimg.iso"が起動メディアと認識され、"isolinux.bin"の起動メッセージが表示されます。

図4 isolinuxの起動画面
図4 isolinuxの起動画面

10秒ほど待つか、リターンキーを押せば、isolinux.cfgの"pl_install"ラベルの指定に従い、vmlinuzとinitramfs.tzstがロードされ、"root=/dev/ram0 ro net.ifnames=0 edd=off"というオプション指定でカーネルが起動されます。initramfsが正しく作成できていれば、メモリ上のみで動く小規模Linuxシステムの完成です。

図5 on memory Linuxシステムの完成
図5 on memory Linuxシステムの完成

今回は仮想環境にインストールしたPlamo Linuxをinitramfs化して、on memoryで動かすまでの手順を紹介しました。この環境はインストール済みのパッケージこそ少ないものの、通常のPlamo Linux同様に使えるので、一般ユーザを作成したり、パッケージをネットワーク経由でダウンロード、インストールして、機能を追加することも可能です。しかしながら、initramfs上で動いているため電源を落すと追加した機能は消えてしまいます。そこで次回はこの環境をカスタマイズする方法を考えます。

おすすめ記事

記事・ニュース一覧