
2026/06/16 1:03
ヌードLinux をブートする
RSS: https://news.ycombinator.com/rss
要約▶
Japanese Translation:
本記事では、不要なコンポーネントを最小限のカーネルから削除し、単一の C プログラムベースの「init」プロセスのみをホストすることで Linux の起動時間を劇的に短縮する方法を紹介します。標準的なディストリビューションが大型の
initrd イメージ(2163 ファイルを含む約 73MB)を使用し、マルチコアシステムで起動に約 1 分かかるのに対し、このアプローチでは簡易 C プログラムを静的コンパイルしてメッセージを表示し、順序立てたシャットダウンのため reboot(RB_POWER_OFF) を呼び出すことで、コンパクトな単一ファイルの initramfs を作成します。この技術は、デバイスアクセスが手動でマウントされる仮想化環境(例:KVM/QEMU)と、EFI パーティションおよびユニファイドカーネルイメージを必要とする実機ハードウェアセットアップの両方の起動に対応しています。結果として得られるシステムフットプリントは標準構成と比較して約 2MB に減少しますが、主なメリットは著しく高速な応答時間と攻撃対象領域の縮小です。このプロセスには make tinyconfig を使用するなどの特定のビルド手順や、「Initramfs unpacking failed」のような潜在的なデバッグエラーの処理が含まれ、最終的には複雑な起動シーケンスを効率的な埋め込みシステムまたは仮想システム向けに置換することを目的としています。本文
起動時間を 1 秒未満に短縮:最小限の Linux カーネルでの体験
2026 年 5 月 19 日、従来のオペレーティングシステム全体を起動するのではなく、単一のプロセスのみをホストするためのLinux カーネルを実行し、起動時間を 1 秒未満に短縮した取り組みをご紹介します。
背景と動機
- 過剰な保護から脱却: 子供の頃はコンピュータが長時間稼働する必要はなく、電源を切って再起動するだけで数秒でディスク内容を読み込める時代でした。
- SSD 以降の停滞: 2000 年代初期に SSD の登場で一時的に速度が向上しましたが、業界は既存の慣例に従い続ける結果、現在では高性能なマシンでも起動に 1 分かかることが珍しくなくなっています。
- 別のアプローチ: 機能のない状態ではなく、**「極めて少ないもののみ」**を残して Linux カーネルを維持し、その枠内でシステムを実装する試みを始めました。
【更新】 「Rust を用いて最小限の Linux から構築する方法(Building a tiny Linux from scratch)」というリソースを発見しました。これは 1 年前に発表されたもので、私が行うことの多くを実装しており、一読の価値があります。
Hello, World!:最小限の Init プログラム
Linux の起動では、最初の動作として init プログラムが実行されます。これを作るには、以下のような単純な C コードを用意します。
基本例:init.c
init.cこのプログラムはメッセージを表示し、その後コンピュータを再起動(VM をシャットダウン)するだけで、カーネルのパニックを防ぐ設計です。
#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); }
単一ファイルの initrd を作成
現代的な Linux は「initrd」や「initramfs」などを活用した複雑な起動プロセスを使いますが、ここでは静的リンク(静的ライブラリを含めた)コンパイルを行い、必要なライブラリを自前で用意して単一ファイルの自分専用の initrdを作成します。
以下のコマンドを実行することで作成可能です:
gcc -static init.c -o init echo 'init' | cpio -o --format=newc | gzip -c > initrd
起動時の確認ポイント
カーネルメッセージを確認し、以下の点に注意してください。
- 正常な展開:
と表示され、その後Trying to unpack rootfs image as initramfs...
とメッセージが出れば成功です。Run /init as init process - エラーチェック:
: 形式や圧縮方式が合っていない場合。Initramfs unpacking failed: no cpio magic
: ファイルが見つからない場合(check access for rdinit=/init failed: -2
)。-ENOENT
補足: 多数のファイルを圧縮したい場合は、以下のコマンドを使用します。
(cd $SOURCE_DIR; find . | cpio -o -H newc) | gzip -c > $OUTPUT_FILE
仮想環境(QEMU/KVM)での動作検証
実際にハードウェアで動かす前に、実験用に KVM または QEMU を使用してシミュレーションを行います。カーネルと initrd のみをコマンドラインからブートさせる設定です。
カーネルの準備
システムのカーネルをコピーし、所有者権限を変更します(または自前でビルド):
sudo cp /boot/vmlinuz . sudo chown $USER:$GROUP vmlinuz
KVM での起動テスト
以下のコマンドで仮想システムを起動し、標準出力ログから
Hello from init.c! を確認します。
kvm -m 1G -nographic -kernel vmlinuz \ -initrd initrd -append "console=ttyS0"
期待されるログ:
[ 0.000000] Linux version 6.8.0-... ... [ 0.493923] Trying to unpack rootfs image as initramfs... [ 0.712522] ... [ 0.816634] Run /init as init process Hello from init.c! <-- ここです! [ 0.819849] reboot: Power down
デバイスと永続ストレージのアクセス
ファイルシステムなしでも、永続的なストレージへのアクセスは可能です。そのためには起動時に
/dev マウントが必要です。
devtmpfs のマウントと読み取りテスト
C コード内で
mount("devtmpfs", "/dev") を呼び出し、/dev/sda にアクセスしてデータを読み取る実装となります。
#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <sys/mount.h> // ... その他のヘッダ int main(int argc, char **argv) { fprintf(stderr, "Hello from init.c!\n"); // /dev を devtmpfs マウント 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])); reboot(RB_POWER_OFF); }
注意: 実際のコードではエラーハンドリングや
の確認は必須ですが、ここでは簡潔さのために省略しました。errno
テスト環境での実行
ランダムデータを生成したイメージファイル(
diskimage)を用意し、KVM で起動します。
dd if=/dev/random of=diskimage bs=1K count=1K gcc -static -o init init.c echo 'init' | cpio -o --format=newc | gzip -c > initrd kvm -m 1G -nographic -kernel vmlinuz \ -initrd initrd -append "console=ttyS0" \ -no-reboot -hda diskimage
結果として、ブートからディスク読み取りまでの時間が1 秒未満となりました。
実ハードウェアへのインストール手順
USB メモリに EFI ブートを追加し、実際に動作させるための手順です。注意深く操作してください(データ破損のリスクがあります)。
1. USB ドライブの初期化
- USB を接続し、
でドライブを特定します(例:lsblk
)。/dev/sda - 重要: パーティションテーブルをゼロ化する前に注意を払いましょう。
# パーティションテーブルと既存データをリセット (データ消去に注意!) dd if=/dev/zero of=/dev/sda bs=1M count=1 # パーティション編集ツール起動 sudo cfdisk /dev/sda
cfdisk での設定:
- フォーマット形式:
dos - パーティション 1: 512M, タイプ
(Hex ID ef) → ブート可能にマークEFI - パーティション 2: 残り全て, タイプ
(Hex ID 83)Linux
2. ファイルシステムの作成
sudo mkfs.fat -F 32 /dev/sda1 # EFI パーティション sudo mkfs.ext3 /dev/sda2 # ルートパーティション(今回は ext3)
注意: UEFI は
ファイルが必要ですが、一部の環境ではブートローダスタブで自動取得される場合があります。ここでは明示的にファイルを確保しました。/EFI/BOOT/BOOTX64.EFI
3. ユニファイドカーネルの作成と配置
カーネル (
vmlinuz) と initrd (initrd) を ukify ツールを使って結合し、EFI ファイルとして配置します。
sudo apt install systemd-ukify systemd-boot-efi ukify build --linux=vmlinuz --initrd=initrd # 作成された EFI カーネルをコピー sudo mount /dev/sda1 /mnt sudo mkdir -p /mnt/EFI/BOOT sudo cp vmlinuz.unsigned.efi /mnt/EFI/BOOT/BOOTX64.EFI sudo umount /mnt
これで USB メモリにブート可能なシステムが完成します。再起動直後に写真撮影のために
sleep(5) を追加した例などはありますが、実質的な動作は以下のようになります:
[ 0.816634] Run /init as init process Hello from init.c! <-- 起動完了の表示
マイクロカーネル(Tiny Kernel)のビルド
既存のカーネルをコピーするだけでなく、より小さく安全な独自のミニマルな Linux カーネルをビルドすることも可能です。
ビルドプロセス
git clone https://github.com/torvalds/linux.git cd linux make tinyconfig # 基本設定でほぼ機能しないため make menuconfig # 必要な機能を手動で有効化 make -j 8 # コンパイル(結果約 1~2MB)
重要な構成オプション (menuconfig
)
menuconfig以下の項目について確認・設定が必要です:
- General setup
- ロカルバージョン名:
に設定。tiny - Initramfs/Initrd サポート:
で圧縮されたもののみ残す。gzip - コンパイル最適化: サイズ重視 (
)。-Os - 多ユーザー/グループ機能: 無効化(セキュリティ向上)。
: 有効にしておく(起動エラーの原因調査に必須)。printk
- ロカルバージョン名:
- Processor type and features
- SMP (シンメトリックマルチプロセッシング) を有効。コア数制限を設ける。
- クラスタースケジューラなどは無効化。
- Block Layer
- ブロックデバイス (
) アクセスは必須(有効)。/dev/sda - 自動ロードやマウント時書き込みは不可にする。
- ブロックデバイス (
- Executable File Formats
- ELF バイナリ: 有効。
- Shell スクリプト (
) 解析: 無効化(シェルがないため)。#!
- Device Drivers
マウント用/dev
: 必須(有効)。devtmpfs- TTY: 必須(有効)。
- シリアルドライバ (8250/16550): QEMU エミュレーション用に有効。
- File Systems
- ext3, ext4: 有効化(将来の拡張用)。
- FAT/vFAT/exFAT: EFI パーティション読み取り用に有効化。
- UEFI Stub の設定順序
- ACPI と UEFI runtime サポート、EFI stub support を順番に有効にする必要がある。
これをやる価値はあるか?
このアプローチには明確なメリットがあります:
- スリムさ: より多くの空間を確保でき、起動速度が向上します。
- 攻撃 표면の削減: 利用していないカーネル機能やライブラリがないため、セキュリティが向上する可能性があります。
- 単一ファイル化:
と組み合わせることで、ブート時に外部への依存関係を持たせず、たった一つのファイルでシステムを動作させられます。ukify - カスタマイズ性: 自身の環境に最適化された微小なカーネルを構築できます。
まとめ: 最小限のシステムにおいて、いかにして必要な機能だけを確実につなげるかは、技術的な挑戦であり興味深い冒険です。
次号: '森林のための木' — 最小主義的システムにおける構造化データの冒険へ続く…