- ローカルディスクやNFSの代わりに、Google DriveをルートファイルシステムとしてArch Linuxをブートする実験
- initramfs段階でFUSEファイルシステムをマウントし、Dracutでネットワークと必要なバイナリを含むカスタムEFIイメージを作成
- まずS3と
s3fsで概念実証を行い、その後switch_rootとpivot_rootの失敗を、PID 1でchrootを実行する方法で回避
- Google Driveの適用では
google-drive-ocamlfuseを使ったが、シンボリックリンク、ハードリンク、権限、速度の制約のため手動補正とタイムアウト調整が必要だった
- 最終的にストレージのないノートPCでも、USBの統合EFIファイルと有線ネットワークドライバで起動し、実用性は低いもののSSHFSやGitベースのルートといった派生案の可能性を示した
Google Driveをルートファイルシステムとして使う
- NFSからLinuxをブートした事例を見て、より厄介な対象としてGoogle Driveルートブートを試した
- 別のヘルパーマシンなしで自己完結した構成にしたかったため、ユーザー空間でファイルシステムドライバのように動くFUSEを選んだ
- 核心となる条件は、initramfsの中にFUSEプログラムとネットワーク設定を入れ、リモートのルートファイルシステムをマウントしてから通常のブートへつなげることだった
Linuxのブート過程で介入する地点
- Linuxのブートの流れは大きく次の段階に分かれる
- BIOS/UEFIファームウェアがブートローダーを起動する
- ブートローダーがカーネルをロードする
- カーネルがRAM上の一時ファイルシステムであるinitramfsを展開し、実際のファイルシステムをマウントするためのツールを使う
- カーネルが実際のファイルシステムへ切り替え、新しいファイルシステム上のinitシステムを実行する
- 3番目の段階でFUSEファイルシステムをマウントできれば、リモートストレージをルートのように使ったままブートを続けられる
Dracutで作ったS3概念実証
- カスタムinitramfsの生成にはDracutを使用
- ベースのディストリビューションには、比較的軽量で使い慣れたArch Linuxを選択
- Dracutモジュールには
fusermount、fuseiso、mkisofsのようなFUSE関連バイナリを含めた
dracut.shでEFIイメージを作成してQEMUで実行すると、root=引数がないという警告の後にデバッグシェルへ入った
- デバッグシェルではブートに必要な作業を手動で行った
modprobe fuse, modprobe e1000でドライバをロード
dhclient eth0とルーティング設定でネットワークを構成
s3fsでローカルS3バケットを/sysrootにマウント
switch_rootの失敗とchrootによる回避
/sysrootにArch Linuxのルートは見えていたが、switch_root /sysroot /sbin/initはInput/output errorで失敗
pivot_rootもinitramfsのrootfsでは使えず、Invalid argumentが発生
- 参照したStack Exchangeの回答によれば、initramfsのrootfsでは
pivot_rootやアンマウントができないため、新しいルートを上からマウントしてchrootしたうえでinitを実行する必要がある
- シェルで単純に
chroot /sysroot /sbin/initを実行しても、systemdがPID 1ではないため正常に起動できなかった
- Dracutの
init.shにネットワーク設定、s3fsマウント、/sys、/dev、/procのバインドマウントを追加し、最後にexec chroot /sysroot /sbin/initを実行するよう変更して、S3ルートブートに成功した
S3ルートで表面化したDNS問題
- ブート後の
mount結果で、/がs3fsタイプとしてマウントされていることを確認
pacman -Sy fastfetchを実行すると、geo.mirror.pkgbuild.comなどのパッケージミラーホストを解決できず失敗
- ルートファイルシステムがS3上にあるため、別のマシンでそのルートをマウントし、
chrootで入ってツールをインストールできた
systemd-resolvedはjournalソケットのstdout接続権限の問題で起動せず、/etc/resolv.confにnameserver 1.1.1.1を書いてDNSを回避した
Google Driveへ移行
- Google Drive向けのFUSE実装としてgoogle-drive-ocamlfuseを使用
- GoogleアカウントでOAuth2シークレットを作成し、APIを有効化したうえで、Arch Linux VMにAURパッケージをインストール
- Google Driveをマウントした後、長時間の
rsync作業でArch LinuxのファイルをDriveへコピー
- Google Driveベースのルートでは、ファイルシステムの挙動の違いが継続的に問題になった
- シンボリックリンクを指すシンボリックリンクが動作せず、
/usr/lib関連の項目に問題が出た
- ハードリンクが動作しない
- 相対シンボリックリンクが動作しない
- 壊れたシンボリックリンクが許可されない
- Google Drive外を指すシンボリックリンクが動作しない
- 権限と属性が機能しない
- 速度が非常に遅い
- FUSEドライバやカーネルを改変しないという条件を維持するため、失敗した
rsyncログをもとに手動でシンボリックリンクを作成して対応した
Google Drive向けinitramfsの修正
- initramfsにはノートPCで生成したトークンファイル、Google Drive FUSEバイナリ、SSL証明書を含めた
/.gdfuse/default/config、/.gdfuse/default/state、/etc/ssl、/etc/ca-certificates関連ファイルをDracutイメージに入れた
- Google Driveルートでブートすると
chroot: /sbin/init: File not foundが発生
- 実際にファイルが存在していても、依存ライブラリや動的リンカのパスがなければLinuxは
File not foundを返すことがある
- 相対シンボリックリンクの問題により、カーネルが
/sysroot内で再び/sysroot/sysrootを探す状態になっていたため、/sysroot/sysrootを作成してからその中に/sysrootをバインドマウントして解決した
- その後もブートは非常に遅かった
- 動的リンカキャッシュの再生成に約5分かかった
- systemdユニットごとに約1分かかった
/dev/ttyS0の待機タイムアウトのせいでブートが停止した
/etc/systemd/system/dev-ttyS0.deviceにJobTimeoutSec=infinityを設定し、/etc/login.defsでLOGIN_TIMEOUTを0に変更してログインタイムアウトを回避
- キャッシュが蓄積された後は、ファイル読み込みは最初ほど遅くなくなった
ストレージのないノートPCで実行
- ストレージのない予備のノートPCで実機ブートを試した
- QEMU用設定から実機向けにいくつかの項目を変更
- デフォルトの
e1000の代わりに、ノートPCのEthernetポート用**r8169ドライバ**を使用
- シリアルディスプレイを使わない
- 自宅ネットワークのトポロジーに合わせてネットワーク設定を変更
- 長いEthernetケーブルの代わりにPowerlineを使用
- 統合EFIファイルをビルドしてUSBドライブのEFIブートパスに置き、ノートPCで起動
- 内蔵キーボード用の
modprobe指定は見つけられず、hid_usbをロードして外付けキーボードでネットワークを設定した
- 最終成果物は、ストレージなしでGoogle Driveベースのルートから動作する「Cloud Native Computer」となった
可能な派生と限界
- プロジェクト自体はかなり遊び心の強いものだが、同じ方法でSSHFS上からLinuxをブートすることもできる
- gitfsを使えば、GitリポジトリからLinuxをブートし、変更をGitで追跡する方式も可能
- 可能性は多いが、実用性は限定的
- 次の実験候補としてNixの導入を考えている
まだコメントはありません。