1 ポイント 投稿者 GN⁺ 2024-07-03 | まだコメントはありません。 | WhatsAppで共有
  • ローカルディスクやNFSの代わりに、Google DriveをルートファイルシステムとしてArch Linuxをブートする実験
  • initramfs段階でFUSEファイルシステムをマウントし、Dracutでネットワークと必要なバイナリを含むカスタムEFIイメージを作成
  • まずS3とs3fsで概念実証を行い、その後switch_rootpivot_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モジュールにはfusermountfuseisomkisofsのような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/initInput/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.confnameserver 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.deviceJobTimeoutSec=infinityを設定し、/etc/login.defsLOGIN_TIMEOUT0に変更してログインタイムアウトを回避
  • キャッシュが蓄積された後は、ファイル読み込みは最初ほど遅くなくなった

ストレージのないノート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の導入を考えている

まだコメントはありません。

まだコメントはありません。