6月15日、Nick Thomas氏が「Boot Naked Linux · ... and another thing ...」と題した記事を公開した。Linuxカーネルを起動してたった1つのプロセスだけを動かす最小構成のシステムを、1秒以内で起動する実験だ。
現代のPCは16コアのCPUと高速SSDを搭載していても起動に1分かかる。一方、IoTデバイスや産業機器、車載システムでは、電源投入から1秒以内に動作開始することが求められる場面が増えている。エッジコンピューティングの普及により、クラウドに依存しない高速起動の需要はさらに高まっている。Thomas氏は通常のUbuntuで2163個のファイルを含む73MBのinitrd(初期RAMディスク)を使うところを、静的リンクされた実行ファイル1つだけに削ぎ落とし、超高速起動を実現した。
最小限のinitプログラム
Linuxシステムが最初に実行する「init」プログラムは、特別なものではなく通常の実行可能ファイルやスクリプトに過ぎない。Thomas氏は以下のようなシンプルなC言語のプログラムを作成した。
#include <stdio.h>
#include <stdlib.h>
#include <sys/reboot.h>
int main(int argc, char **argv) {
fprintf(stderr, "Hello from init.c!");
reboot(RB_POWER_OFF);
}
このプログラムはメッセージを表示して、コンピュータをシャットダウンするだけだ。initプロセスが終了するとカーネルパニックが起きるため、reboot(RB_POWER_OFF)で仮想マシンを正常にシャットダウンしている。
たった1つのファイルだけのinitrd
現代のLinuxディストリビューションでは、ブートプロセスで巨大なinitrdファイルシステムを使用する。Thomas氏のPCでは73MBで2163個のファイルが含まれていた。対して、最小構成では静的にコンパイルした実行ファイル1つだけを含むinitrdで済む。
gcc -static init.c -o init
echo 'init' | cpio -o --format=newc | gzip -c > initrd
ここで使われるcpioは非常に古いアーカイブツールで、tarよりもさらにユーザー非友好的なコマンドラインを持つ。実際、シェルのファイル名グロビング(ワイルドカード展開)よりも古い。
QEMUでの起動テスト
実機でのテストはUSBメモリの抜き差しが面倒なため、QEMUを使って仮想システムで実験を行った。
kvm -m 1G -nographic -kernel vmlinuz \
-initrd initrd -append "console=ttyS0"
カーネルが起動すると、initrdをRAMディスクに展開してinitバイナリを実行する。
[ 0.489390] Trying to unpack rootfs image as initramfs...
[ 0.805419] Run /init as init process
Hello from init.c!
[ 0.807535] reboot: Power down
電源投入から1秒以内でプログラムが実行された。
デバイスへのアクセス
ストレージなどのデバイスにアクセスするには、カーネルのdevtmpfs機構を使う必要がある。devtmpfsは、カーネルが自動的にデバイスファイルを作成・管理する仮想ファイルシステムだ。initが実行される時点ではまだルートファイルシステムがマウントされていないため、通常のデバイスファイルは利用できない。
Thomas氏はC言語のプログラムからmount("devtmpfs", "/dev", "devtmpfs", 0, NULL)を呼び出してdevtmpfsをマウントし、QEMUの-hdaオプションで渡したディスクイメージ(/dev/sdaとして見える)の先頭数バイトを読み込むコードを追加した。
mount("devtmpfs", "/dev", "devtmpfs", 0, NULL);
int fd = open("/dev/sda", O_RDWR);
uint32_t buffer[2];
read(fd, buffer, sizeof(buffer));
close(fd);
fprintf(stderr, "Read %08x %08x\n",
ntohl(buffer[0]), ntohl(buffer[1]));
この結果、1秒以内に起動してディスクから読み込みを行うことに成功した。
実機での起動
実際のハードウェアで起動するために、USBメモリにEFIブート可能な構成を作成した。多くの情報源が混在していたが、最終的には以下の手順で動作したという。
- USBメモリに「dos」形式のパーティションテーブルを作成
- EFIタイプ(hex id
ef)の512MBパーティションを作成してブート可能にマーク - FAT32でフォーマット
ukifyツールで統合カーネルを作成(ローダースタブ、カーネル、initrdを1つのファイルに)/EFI/BOOT/BOOTX64.EFIとして配置
sudo apt install systemd-ukify systemd-boot-efi
ukify build --linux=vmlinuz --initrd=initrd
この統合カーネルをUSBメモリに配置することで実機での起動に成功した。ただしあまりに速く再起動してしまうため、写真を撮るためにsleep(5);を追加する必要があったという。

より小さなカーネルへ
最初に使ったのはUbuntuデスクトップのカーネルで、かなり大きい。そこでLinuxカーネルを最小構成でビルドし直すことにした。
git clone https://github.com/torvalds/linux.git
cd linux
make tinyconfig
make menuconfig
make tinyconfigはほぼすべてのオプションを無効化するが、無効化しすぎて動かないため、いくつかの設定を有効に戻す必要がある。30年にわたって新規ユーザーを困惑させ続けてきたテキストメニューシステムで、以下のような設定を調整した。
- initramfs/initrdサポートの有効化
- gzip圧縮サポート
- printk(ログ出力)の有効化
- 64ビットカーネル
- ELFバイナリサポート
最適化レベルは「Optimize for size (-Os)」に変更し、不要な機能を削減している。
組み込みシステムへの応用
この手法は、産業機器や医療機器、車載システムなど、単一の目的に特化した組み込みLinuxシステムで有用だ。systemdやその他の初期化システムを省略し、必要最小限のドライバだけを有効にすることで、起動時間を劇的に短縮できる。また、攻撃対象領域(アタックサーフェス)が小さくなるため、セキュリティ面でもメリットがある。
Thomas氏の実験は、Linuxシステムがいかに柔軟で、用途に応じて極限まで削ぎ落とせるかを示している。通常のディストリビューションが数千のファイルと複雑な初期化プロセスを持つのに対し、静的リンクされた1つの実行ファイルだけで実用的なシステムを構築できる。詳細はBoot Naked Linux · ... and another thing ...を参照していただきたい。