raspberry pi でPXE+overlayfs/tmpfsでディスクレスブート

概要

Raspberry Pi 4 Model B (RAM 8GB) 上で Gentoo Linux を ディスクレス運用 (ネットワークブート) し、ルートファイルシステムを NFS 経由の読み取り専用 とすることで基盤イメージを保護しつつ、OverlayFS を用いた一時的な書き込みを可能にする手法について解説します。 参考1 , 参考2 この構成では、ベースとなるルートFSをNFSサーバから読み出し専用でマウントし、書き込み変更はすべてクライアント側RAM上の tmpfs に保存されるため、システム稼働中のみ有効で再起動で破棄されます。 これにより、SDカード無しでの起動や基盤イメージの一元管理が可能になるだけでなく、アプリケーションから見ると通常通り書き込み可能な環境を提供しながら基盤イメージの破損や意図しない変更を防止できます。 また多数の読み込みが発生する場合でもクライアント側メモリキャッシュを活用しパフォーマンス向上が期待できます。

本記事ではネットブート用のNFSルート設定と、Gentoo環境でのカスタム initramfs(dracutモジュール overlay-root)による OverlayFS 構成の具体的手順を示します。 読者は LinuxのネットワークブートやGentooの基本管理に習熟していることを前提とし、技術的背景も交えながら詳細に説明します。

本文中の 192.0.2.0/24 は説明用の documentation range である。homecluster-infra から OpenWrt 実機へ反映する場合、router hostvars の openwrt_lan_ipaddropenwrt_dhcp_ntp_serversopenwrt_gentoo_server_host を外部 inventory で明示し、NFS root / TFTP / dnsmasq の endpoint に documentation range が残っていれば反映前に止める。

システム構成と前提条件

ネットブート構成: Raspberry Pi 4B(ARM64, 8GB RAM)がクライアントとなり、ネットワーク経由でOSをブートします。 ブートに必要なファームウェア・カーネルはTFTPサーバから取得し、ルートファイルシステムはNFSサーバからマウントします。 Raspberry Pi 4はEEPROMのネットブート機能が利用可能で、あらかじめブートローダ設定でネットワークブートが有効になっている必要があります (raspi-configで Boot Order を 0xf21 に設定し再起動すると、有効になったことを確認できます

  • Gentoo Linux (arm64) 環境: NFSサーバ側にGentooのルートファイルシステムを用意します。
    • これは例えば公式Stage3から展開したディレクトリや、既存のGentooシステムから構築したイメージでも構いません。
    • 後述するように、このルートFSはサーバ側では読み取り専用でエクスポートします。クライアントRaspberry PiはこのNFS共有を自分のルートとして使用します。
  • NFS サーバ: Raspberry Piがルートとして利用するGentooイメージをエクスポートするNFSサーバです。
    • NFSのバージョンは 4.2 (NFSv4.2) を使用します。NFSv4はポートマッパを必要とせずファイアウォール設定が簡略になる利点があります。
    • 例えばエクスポート元のext4パーティションをnoaclオプション付きでマウントする、あるいはエクスポート設定でACLをオフにしておきます。ACLが有効のままだとOverlayFSの要求する属性サポートを満たせず動作に問題が生じるためです。
    • なぜ ACL が絡むか
      • OverlayFS は上層 (upper)/下層 (lower) を重ねることで仮想マージドファイルシステムを実現。書き込み時には lower から upper への copy_up が起き、属性(メタデータ/xattr) もコピーされます。
      • かし lower が NFS (特に NFSv4) 経由でマウントされた場合、lower 側が提供する拡張属性 (xattr) — 特に ACL (posix または NFS4 ACL) や “trusted.overlay.” 系 xattr — に関して、OverlayFS は「期待する機能 (trusted. の作成、正しい d_type + readdir の挙動など)」が十分でないとみなす。
      • 結果、copy_up や whiteout / opaque ディレクトリ管理などがうまく機能せず、書き込みが EOPNOTSUPP になる不具合が報告されている。
        • 2019年のレポートだけどRead-only nfsroot with NFS v4 and overlayfs
          • The initrd of FAI mounts the nfsroot read only and then puts a tmpfs ram disk on top of it using overlayfs. The result is a new merged file system which is writable. This works nicely since several years when using NFSv3. But when using NFSv4 we can read from a file, but writing always reported

          • openat(AT_FDCWD,….) = -1 EOPNOTSUPP (Operation not supported)

            • 実例として、ある read-only NFS root + tmpfs 上に overlay をかぶせる構成では、NFSv3 では動いていたものが NFSv4 では write 時に必ず EOPNOTSUPP になる、という報告がある。
        • 有効な回避策としての報告
          • read-only root + overlayfs のケースでは、NFS エクスポート元のローカルファイルシステム (たとえば ext4) を noacl オプションで再マウントすることで、overlayfs が “ACL サポートなし” と認識し、copy_up が成功、その後正常に書き込み可能になるという報告がある。
          • without any errors. When talking to some overlayfs guys they ask me to disable acl for the exported NFS file system. There’s an noacl option listed on nfs(5), but it’s for NFS version 2 and 3 only, not for NFS v4. You cannot disable ACL on a NFS v4 mount.

            • この時期(2019/Sep/26)のNFS v4 の実装では noacl のオプションは上手く機能しない、という指摘がある
        • 2023年の話として
          • Why doesn’t overlayroot work properly with a net-booted NFS root on a RPi4?
            • I was able to simplify the problem to one not involving boot, but instead just overlayfs and NFS exports. With an NFS export of an Ubuntu image served from an Ubuntu machine (which does implement NFSACLv3) and a directory named /tmp/overlaygames/ with empty upper,work, and overlay directories within, the following script would run without error:

              • NFS v3 だとエラーが起きない、という話がある
      • NFS v4 でのACL実装の状況(2025年)の状況を確認
      • 現実解として考えられる方向性:
        • エクスポート元 FS の ACL を無効化する
          • ext4 なら mount -o remount,noacl /srv/gentoo/… のように noacl をつける
          • 実際にここでもNFS v4 + noacl で試している
          • 「NFSv4 の wire プロトコルとしては ACL あり」だが、「実体 FS 的には ACL なし」として動かすイメージ
        • rootfs 用 NFS は v3 に落として POSIX ACL に寄せる
          • rootfs 共有用途であれば、v4 特有の ACL/状態管理をそもそも使わず、v3 + POSIX ACL 前提で揃える方がトラブルは減ります
          • v4 特有の機能(pNFS、delegation 等)が不要なら、敢えて v3 のほうが Overlay との相性はまだマシ
        • Overlay の lower に NFS を使うのを諦める(私はこれは避けたい)
          • NFS 上の stage3/rootfs から ローカル FS (ext4/btrfs 等) に rsync してローカル root にする
          • そのローカル root に対して overlayfs(lower=ro root, upper=tmpfs) をやる
        • テスト環境限定で richacl パッチや別 FS を試す
    • 私が使ってるファイルシステムはnoaclをサポートしているか?
  • TFTP ブートローダ: Raspberry Pi 4はブートROMがネットワークブート(PXE類似)に対応しており、まずDHCPでTFTPサーバとブートファイル名を取得しに行きます。
  • Gentooカーネルとinitramfs:
    • クライアント用にビルドした64bitカーネルが必要です(Raspberry Pi 4対応のデバイスツリーとドライバを含むもの)。
    • GentooではカーネルにNFSクライアント(特にNFSv4.2)およびOverlayFSのサポートを有効にしておく必要があります。
    • OverlayFSはカーネルオプションCONFIG_OVERLAY_FSで提供され、モジュール(overlay.ko)としてビルドしておくことを推奨します。
    • 今回はinitramfs内でOverlayFSを扱うため、モジュールとしてビルドしておくとinitramfsでロード可能です
    • 組み込みでも動作自体は可能ですが、dracutモジュールのデフォルト実装上はモジュール存在をチェックして動的ロードする設計になっています
    • また、ネットワーク関連ではBroadcom GENET Ethernetドライバ(Pi4の有線LAN)、DHCPクライアント、NFSクライアントなどがinitramfsから利用可能である必要があります。
      • Gentooの場合、initramfs生成に dracut を使用しますが、dracutをネットブート対応させるにはnetworkモジュールおよびnfsモジュールが必要です
    • Gentoo環境でsys-kernel/dracutパッケージをインストールする際にUSEフラグでnetworkやusrmountが有効になっていることを確認してください(典型的にはnetUSEでdracut-networkサブパッケージが導入されます)。
    • なお最新版dracutでは代替として90dmsquash-liveモジュールでのOverlayFS対応が進んでいますが、NFSルートへの直接overlayには未対応のため、ここでは独自モジュールを用います。

1. NFSサーバ側の準備 (Gentooルートファイルシステムのエクスポート)

まず、GentooのルートファイルシステムとなるディレクトリをNFSサーバ上に用意します。 例として、 /srv/gentoo/latest/nfs にGentooのシステムを用意したとします。 このディレクトリをNFSでエクスポートし、Raspberry Piからマウントできるよう設定します。 エクスポート設定: /etc/exports ファイルに以下のようなエントリを追加します(環境に合わせて調整してください):

/srv/gentoo/latest/nfs *(ro,no_subtree_check,no_root_squash,fsid=0)

設定項目の説明:

  • ro
    • 読み取り専用エクスポートを意味します。
    • クライアントから直接この共有に書き込むことを禁止します。
    • OverlayFS経由での書き込みはクライアント側RAM上で行われ、NFSサーバ上には反映されません。
  • no_subtree_check
    • サブツリーチェック無効化で、NFSのパフォーマンスと安定性のための一般的な設定です。
  • no_root_squash
    • クライアント側のrootユーザIDをサーバ側でもrootとして扱う設定です。
    • これにより、クライアント(Raspberry Pi)でroot権限のプロセスがNFS経由でファイルアクセスする際に権限不足にならずに済みます
    • デフォルトではrootは匿名ユーザにマップされるため読み取り専用でも問題になる可能性があります
  • fsid=0( このオプションは階層の中で1度だけ使用できます。サブディレクトリでもfsidを付けるとエラーになります)
    • このエクスポートをNFSv4のルート(起点)として指定するオプションです。
    • NFSv4では単一のfilesystem IDをエクスポートルートに設定する必要があります。
    • 上記のように設定すれば、クライアント側では nfsserver:/ というパスで /srv/gentoo/latest/nfs をマウントできます。

私の設定です。

# cat /etc/exports
/srv *(rw,crossmnt,no_subtree_check,no_root_squash)
/srv/gentoo *(ro,nohide,no_subtree_check,no_root_squash,fsid=0)
/srv/nfs/overlay *(rw,no_subtree_check,no_root_squash)
/srv/nfs/ansible-logs *(rw,no_subtree_check,no_root_squash)

設定後、エクスポートを反映します。例:

# exportfs -rav        # 設定を再読み込みしエクスポート
# systemctl restart nfs-server rpcbind   # NFSサービス再起動 (ディストリによる)
  • NFSv4 用設定:
    • NFSv4では、エクスポートするディレクトリ階層全体に fsid=0 のエントリが必要です。
    • 上記では直接 /srv/gentoo/latest/nfs をfsid=0にしています。
    • 他にNFSv4の設定として、/etc/idmapd.confでドメイン設定を合わせる必要がある場合がありますが、今回はAUTH_SYS(UID/GIDベース)で運用し、かつno_root_squashを指定しているため特別なIDマッピング設定は不要です。
    • ACLに関しては前述の通り、エクスポート元ファイルシステム(例えばext4)をnoaclでマウントするなどし、POSIX ACLを無効化してください
  • GentooルートFSの構成:
    • /srv/gentoo/latest/nfs 以下にはGentooの完全なルートディレクトリ構成が存在しているものとします。
    • 例えばStage3を展開して必要なツール
      • sys-boot/raspberrypi-firmwareのブートファイル
      • sys-kernel/linux-firmware等のファームウェア
      • net-misc/dhcpcdなどDHCPクライアント を導入済み、カーネルイメージやモジュール類も配置済みであることが前提です。
    • 後述のinitramfsを使うため、/srv/gentoo/latest/nfs 内にカーネルモジュール(/lib/modules/<kernel-version>/)も展開されている必要があります。
    • また、NFS共有上のGentooルートは基本的に読み取り専用で運用するため、/etc/fstab 内で不要な自動書き込みマウントはオフにする(/etc/fstabで/エントリにdefaults,roを指定する等)か、起動後に書き込みが必要な一時ディレクトリ(/varや/tmpなど)はtmpfsにマウントするよう調整しておくと良いでしょう。
    • ただしOverlayFSにより原則として全体が書き込み可能になるため、特別な調整なしでも大半のサービスは動作します。
    • ログディレクトリ/var/logなどもOverlayFS経由でRAM上に書かれるため、長期運用ではメモリ消費に留意してください(後述)。

2. Raspberry Pi 4B のブートファイル配置 (TFTPサーバ設定)

次に、Raspberry Piが起動時に取得するブート関連ファイルをTFTPサーバ上に用意します。 多くの場合、NFSサーバと同じホストでTFTPも提供する設定にしますが、別ホストでも構いません。TFTPルートディレクトリ(例: /tftpboot)に以下を準備します:

  • Raspberry Pi ファームウェア: bootcode.bin, start4.elf, fixup4.dat などPi4のブートに必要なファームウェアファイル群を配置します。
  • カーネルイメージ:
    • Gentooでビルドしたカーネル(例えばImageやImage.gzもしくはkernel8.imgという名前にリネーム)を配置します。
    • 一般的にRaspberry Piの64bitカーネルはブートローダ設定でkernel=kernel8.imgと指定しますので、その名前で配置するのが分かりやすいです。
  • デバイスツリーブロブ (DTB):
    • カーネルに対応するRaspberry Pi 4用のDevice Treeバイナリ (bcm2711-rpi-4-b.dtb など) と、必要に応じてオーバレイ (*.dtbo) を配置します。
    • 通常Gentooカーネルをビルドするとarch/arm64/boot/dts/broadcom/以下にdtbが生成されますので、それをコピーします。
  • config.txt:
    • Raspberry Piのブート構成ファイルを作成します。最低限以下の内容を含めます:
# /tftpboot/config.txt
arm_64bit=1
enable_uart=0      # UARTコンソールが必要なら1に
kernel=kernel8.img
initramfs initrd.img followkernel   # initramfsを読み込む指示
  • arm_64bit=1
    • Pi4を64bitモードで起動する設定です(64bit Gentooを動かすため)。
  • kernel=kernel8.img
    • 起動するカーネルイメージ名指定です。上でカーネルをkernel8.imgとして配置した場合の例です。
  • initramfs initrd.img followkernel はinitramfsイメージをロードする指示です。
    • initrd.imgという名前で後述のdracut生成initramfsを配置することを想定しています
    • ファイル名は任意ですが、config.txt内で一致させます
    • followkernel はカーネルと同じメモリアドレスに続けて配置するオプションで、RPi特有の指定です
    • Piブートローダはこの記述に従い、TFTP経由でinitrd.imgを取得しカーネルとともに渡します
    • cmdline.txt:
      • カーネルに渡すコマンドラインパラメータを設定します。1行のテキストファイルです。今回のポイントは、NFSルート関連の設定およびOverlayFS有効化用パラメータです。例:

      • /tftpboot/cmdline.txt

  - > console=serial0,115200 console=tty1 root=nfs4:192.0.2.100:/20251214/nfs,vers=4.2,proto=tcp ip=dhcp rw rd.neednet=1 rd.net.timeout.carrier=30 rootwait cgroup_enable=cpuset cgroup_enable=memory cgroup_memory=1 rd.info rd.debug rd.overlayfs=1 rd.shell

上記は一例で、環境に応じてIPやオプションは変更してください。各項目の説明:

以上を設定したconfig.txtとcmdline.txt、およびカーネル・initramfs・DTB類をTFTPサーバの適切な場所に配置します。Raspberry Pi 4のブートROMは、デフォルトではDHCPから得たfilename(無い場合MACアドレスベースのフォールバック名)をTFTPで取りに行きますが、config.txtを読むためにまずstart4.elf等を取得・実行し、その中でconfig.txtに従ってさらにkernel8.imgやinitrd.imgを取得します。正しく配置・設定されていれば、Pi起動時にTFTPログにこれらファイルの要求が記録されるでしょう

3. dracut-ng の OverlayFSの構成について

dracutで作るinitramfsにcmdlineに rd.overlayfs を付けると、overlayfsでのマウント処理をしてくれます。 この処理がどのようなものか追いました。

dracut-ngのoverlayfsモジュール

下記のようなオプションでマウントしています。

mount -t overlay LiveOS_rootfs \
  -o "$ovlfs",upperdir=/run/overlayfs,workdir=/run/ovlwork \
  "$NEWROOT"

全体像(設計意図)

この mount は

  • 既存の rootfs(読み取り専用)を壊さず
  • 書き込みは RAM 上(tmpfs)に逃がし
  • 最終的に systemd が見る / を「書ける root」に見せる ためのものです。

dracut の 70overlayfs モジュールは 「LiveOS / NFS root / squashfs root などを “mutable root” に変換する」 という役割を担っています。

mount -t overlay の基本構文

OverlayFS の mount は概念的にこうなります:

overlayfs =
  lowerdir : 読み取り専用の土台
  upperdir : 書き込み内容
  workdir  : 内部作業用

結果として見えるファイルシステム:

      overlay mount point (NEWROOT)
               |
        -----------------
        |               |
   upperdir         lowerdir
 (変更・新規)      (元rootfs)

各要素の詳細

① -t overlay LiveOS_rootfs

LiveOS_rootfs とは?

  • OverlayFS の「擬似的なデバイス名」
  • 実体は不要(/dev/… ではない)
  • dracut / livecd 系で慣例的に使われる名前 つまり: 「LiveOS_rootfs という名前の overlayfs を作る」 という意味合いです。 ( この名前は機能的意味はほぼ無く、dracut-ngのoverlayfsのモジュールが使う識別用のラベルです。)

② -o “$ovlfs”,upperdir=…,workdir=

$ovlfs の中身(重要) $ovlfs には lowerdir 指定が入っています。 典型的にはこんな値です:

ovlfs="lowerdir=/sysroot"

あるいは複数指定:

ovlfs="lowerdir=/run/rootfsbase:/run/rootfsro"

つまりこの mount 行は:

lowerdir = 既にマウント済みの LiveOS / NFS root
upperdir = /run/overlayfs
workdir  = /run/ovlwork

を合成している、ということです。

③ upperdir=/run/overlayfs

役割

  • 書き込み内容の保存先
  • 新規作成・変更・削除はすべてここに入る
  • dracut では通常 tmpfs 上(RAM)

例:

touch /etc/foo

と書き込んでみると、 → 実体は:

/run/overlayfs/etc/foo

に書き込まれます。 lowerdir(今回はNFS) は一切変更されません

④ workdir=/run/ovlwork

これは何?

OverlayFS が内部で使う 作業ディレクトリです。

  • rename
  • copy-up
  • whiteout 管理
  • inode 整合性管理

などに使われます。

⚠️ ただし制約が厳しい

  • upperdir と 同じ filesystem 上
  • 空であること
  • 他用途に使ってはいけない

dracut では upper/work を両方 /run(tmpfs)に置くことで、この制約を確実に満たしています。

⑤ “$NEWROOT”

これはどこ? dracut が 最終的に root として切り替えるディレクトリ 通常 /sysroot または /newroot ここに overlayfs を mount することで: systemd から見た / が overlayfs になる という仕組みです。

処理順を時系列で見ると

(1) 読み取り専用 rootfs を mount
    例: /sysroot (NFS, squashfs, etc)

(2) tmpfs を用意
    /run/overlayfs
    /run/ovlwork

(3) overlayfs を構築
    lowerdir = /sysroot
    upperdir = /run/overlayfs
    workdir  = /run/ovlwork

(4) overlayfs を NEWROOT に mount

(5) switch_root / pivot_root

なぜ dracut はこの方式を選んでいるのか

利点

  • NFS root / squashfs root を 完全に read-only に保てる
  • ノードごとの差分は RAM 上だけ
  • reboot でクリーンに戻る
  • ストレージ不要(PXE / diskless 向き)

制限

  • upperdir が RAM → メモリ消費
  • NFS を upperdir にすると ACL / rename / locking 問題が出やすい
  • crash 時に差分は失われる

今回の私の構成

  • lowerdir = NFSv4.2 root(ro)
  • upperdir = tmpfs
  • workdir = tmpfs

参考資料

dracutのrd.breakのフェーズ

dracut は「hook」と呼ばれるタイミングごとに /init がシェルスクリプトを読み込んで実行します。代表的なもの:

  • cmdline:カーネル引数を解析するフェーズ
  • pre-udev / pre-trigger:udev 関連処理の前
  • initqueue / initqueue/finished:root デバイスが現れるのを待つループ
  • pre-mount:root をマウントする前(NFS だとこの時点で root がマウント済みのこともある)
  • mount:root をマウントする処理の中
  • pre-pivot:switch_root で本物の root に切り替える直前
  • emergency:緊急シェルを起動する前後

dracut.modules(7) や dracut の HTML ドキュメントに hook 一覧があります。

たとえば「root マウント前に overlayfs や何かの前処理をしたい」なら、pre-mount hook にスクリプトを差し込む、という感じです。

dracut.conf.d でモジュールを有効化する

モジュールディレクトリを置いただけでは、ディストリによっては自動で有効にならないことがあります。 確実に使うために、/etc/dracut.conf.d に設定を追加します

# /etc/dracut.conf.d/95-myscript.conf
add_dracutmodules+=" myscript "

NFSv4(ReadOnly) + PXE Diskless boot + OverlayFS(tmpfs) 構成の注意点、トラブルシューティング

NFSv4の仕様とNFSサーバ側ファイルシステムのACLの問題

NFS側で /dev のディレクトリがあるとoverlayfsでのsystemdのswitch-rootで失敗する

journalctl のログ、あるいは rd.bream=mount でシェルに入って確認すると Object is remote と表示される

systemdのswitch-rootがエラーになる

cannot access '/sysroot/dev': Object is remote
Failed to create /sysroot/dev: Object is remote
Failed to switch root

lsしてもアクセスできない

ls: cannot access '/sysroot/dev': Object is remote
d?????????  ? ?    ?       ?            ? dev

NFSサーバ( ReadOnly ) + OverlayFS + tmpfs の構成ができていてもNFSに/devが存在するとエラーが発生する

NFSv4/Unix環境でEREMOTE: “Object is remote” 基本的な意味

EREMOTE (“Object is remote”) は元々 RFS(Remote File Sharing) のエラーで、 「ローカルノード上にないオブジェクトをローカル処理しようとした」、 「リモート上のリソース/パス/デバイスへ不正にアクセスしようとした」などを示します。 (ユーザー空間の NFSv4 や VFS でも同名で伝播するケースがあります) https://software.fujitsu.com/jp/manual/manualfiles/M090058/J2X14260/05Z200/pclmsab/pclms130.html

“Object is remote” は単なる socket や transport error ではなく、 NFSv4 プロトコル層で “意図したオブジェクトがこのノードにない” と解釈された場合に返るエラー です。 これは原因が単一ではなく、ファイルハンドル、export namespace、RPC auth、ネットワーク切断、map-id など複合的に絡む可能性があります

今回の問題としてはdracut, initramfsの挙動としては

  • /sysroot は「完成後の rootfs」
  • /sysroot/dev は 後で必ず devtmpfs を mount する
    • rootfs 内に dev を含めない( 含めると devtmpfs の mount に支障がある )

どのように切り分けられるか? だが、これは単純に ls で確認できる dracutの起動中にエラーでシェルに入ったら ls /dev devが存在するとエラーが発生する 起動プロセスに関係なくエラーになる。これは

  • devtmpfs が まだマウントされていない
  • overlayfs が lowerdir の dev を見ようとして失敗
  • 結果として lookup 時点でエラー

カーネルバージョンを指定する必要があった

ちょっとややこしいのですが、dracut の「モジュール」には二種類あります:

    1. カーネルモジュール (driver)
    • /lib/modules/$KVER/kernel/…/overlay.ko[.xz] みたいなやつ
    • dracutのオプション –add-drivers overlay で指定しているのはこちら。
    • dracut は /lib/modules/カーネルバージョン/ の下を探して overlay というカーネルモジュールを探します。
    1. dracut モジュール (userspace のスクリプト群)

カーネルモジュールはカーネルにビルドイン(=y)されている場合と、モジュールでロードする場合があります 今回のラズパイ向けのカーネルはoverlayはモジュールでロードする形でした このため、dracutのビルド時、 –add-drivers overlay でカーネルモジュールの追加を行いました

dracut, systemdが特定箇所でループする

dracut の initqueue は下記の条件が揃わない限り 永久ループします:

  • rootfs がマウントできる
  • すべての finished hook が成功
  • emergency に落とされない

overlay root + NFSv4 なので、この層で落ちる可能性もあります。

  • NFSv4 の ACL が壊れていたり
  • noacl で export しているのにクライアントが ACL を期待したり
  • dracut 側で overlayfs モジュールがうまくロードされていない

すると nfsroot.sh → mount → overlay → mount失敗 → initqueue 繰り返し の流れになります。

トラブルシューティングはいくつかあります

(1) カーネル cmdline の最終的なパラメータを確認

cat /proc/cmdline

期待する形は例えば:

root=nfs4:192.0.2.100:/gentoo/20251123/nfs \
ip=dhcp \
rd.neednet=1 \
rd.net.timeout.carrier=30 \
rd.debug

(2) サーバ側の NFSv4 export 設定

/srv/gentoo/latest/nfs 192.0.2.0/24(rw,no_root_squash,fsid=0)

fsid=0 が無いと NFSv4 root として扱われず、クライアントからの PATH 解決に失敗します。 fsid=0は/etc/exportsで指定できる箇所は一つだけです( 2箇所で記述しているとNFS起動に失敗します )

(3) クライアント側の NFS mount が成功しているか

rd.break=pre-mount を付けて drop し、手動でマウント:

mount -t nfs4 -o vers=4.2 192.0.2.100:/gentoo/20251123/nfs /mnt

機能すれば overlayfs レイヤに進めます。

(4) overlay モジュールが initramfs に存在するか

lsinitrd | grep overlay

存在しなければ:

add_dracutmodules+=" overlay "

(5) カーネルモジュールが存在するか?

dracutでinitramfsを作る際に適切なカーネルモジュール( /lib/modules/$KVER/kernel/ )が存在しないとループします。 この可能性を確認するにはcmdline.txtに rd.break=mount などで dracutシェルに入り、lsmodでカーネルモジュールの確認をします。 全く読み込まれてない場合、dracutが違うアーキテクチャのカーネル向けのモジュールをinitramfsに組み込んでいる可能性があります。 uname -a でカーネルバージョンを確認し、/lib/modules/ 以下にそのバージョンのディレクトリが存在するか確認します。

NFSv4 の ACL機能は優秀、ただファイルシステムのACLがNFSv4の求めているACL機能を満たしていない場合、オフにした方が良い

私がNFSv4で使っているサーバでのファイルシステムはf2fsです(通常はext4などが多いと思う。ext4でもNFSv4を使う場合はACLをオフにした方がよいと思います) ただファイルシステム側の実装でACLをオフにすることが可能か?( noaclオプションがあるか? )という観点で確認が必要です

背景と問題点 — なぜ ACL が絡むか

Linux における NFSv4 ACL 実装の限界

NFSv4 ACL と POSIX ACL のねじれ

richacl プロジェクトは事実上「採用されず」

NFSv4 ACL に近い「RichACL」を Linux に入れよう、というパッチセット・プロジェクトがありました ですが、これはmainlineにマージされていません acl - How to apply and use Rich Access Control Lists with BTRFS - Unix & Linux Stack Exchange

NFSv4 ACL 周りで過去に上がっている問題(OverlayFS 抜きの話)

NFSv4 ACL 単体でも、かなり長いことイシューが積み上がっています。

ACL ツールやライブラリとの齟齬

ACL 継承やマスクがおかしくなるバグ

Red Hat のナレッジベースに、

NFSv4 で ACL を継承したときにマスクが失われる/サブディレクトリに ACL が継承されない という問題が上がっており、RHEL 6.5/7 系まで影響しているケースが報告されています

OverlayFS + NFSv4 + ACL に特化したイシュー

現実解として考えられる方向性

  • エクスポート元 FS の ACL を無効化する
    • ext4 なら mount -o remount,noacl /srv/gentoo/… のように noacl をつける
    • 「NFSv4 の wire プロトコルとしては ACL あり」だが、「実体 FS 的には ACL なし」として動かすイメージ
  • rootfs 用 NFS は v3 に落として POSIX ACL に寄せる
    • rootfs 共有用途であれば、v4 特有の ACL/状態管理をそもそも使わず、v3 + POSIX ACL 前提で揃える方がトラブルは減ります
    • v4 特有の機能(pNFS、delegation 等)が不要なら、敢えて v3 のほうが Overlay との相性はまだマシ

私はACLを無効化する方向で行いました

initramfsの中身の確認方法

  • lsinitrd /boot/initramfs-$(uname -r).img
  • bsdtar -tvf initramfs-pxe.img

overlay が見つからない場合

以下のように /etc/dracut.conf.d/overlayfs.conf を作成:

add_dracutmodules+=" overlayfs "
add_drivers+=" overlay "
  • add_dracutmodules: dracutモジュール
  • add_drivers: カーネルモジュール

dracutのモジュールのセットアップが分からないな…ので調べた

root@OpenWrt:/srv/gentoo/latest/tftp# bsdtar -tvf initramfs-pxe.img | grep overlay
-rwxr-xr-x 1 0 0 697 Dec 8 14:12 var/lib/dracut/hooks/pre-mount/01-prepare-overlayfs.sh
-rwxr-xr-x 2 0 0 0 Dec 8 14:12 var/lib/dracut/hooks/mount/01-mount-overlayfs.sh
-rwxr-xr-x 2 0 0 664 Dec 8 14:12 var/lib/dracut/hooks/pre-pivot/10-mount-overlayfs.sh link to var/lib/dracut/hooks/mount/01-mount-overlayfs.sh
-rwxr-xr-x 1 0 0 980 Dec 7 00:14 var/lib/dracut/hooks/pre-pivot/95-pxe-overlay-hook.sh

dracutで作成する initramfsに usr/lib/dracut/modules.d/70overlayfs/ ディレクトリが存在しないのはなぜか?

dracut のモジュール展開ロジック

module-setup.sh による登録例(dracut-ng/modules.d/70overlayfs/module-setup.sh )

install() {
    inst_hook pre-mount 01 "$moddir/prepare-overlayfs.sh"
    inst_hook mount     01 "$moddir/mount-overlayfs.sh"
    inst_hook pre-pivot 10 "$moddir/mount-overlayfs.sh"
}

この inst_hook は以下のような動作するようだ

cp "$moddir/prepare-overlayfs.sh" $initrd_root/var/lib/dracut/hooks/pre-mount/01-prepare-overlayfs.sh

initramfs のビルド時の dracut のオプションに –no-kernel を付けてはいけない

TFTPブート時にサイズが小さくなって嬉しいかな?と思って –no-kernel を付けてしまったが、こうするとカーネルモジュールがまるごと入らない これはnfs, overlay などのカーネルモジュールの読み込みができなくなる ( 自前でカーネルをビルドするのであれば問題ないかもしれないが、今回はモジュールを追加した )

起動しているカーネルとdracutに組み込まれたカーネルモジュールのバージョンが違う

unameコマンドで確認できる起動しているカーネルは 6.12.61-v8+ ただdracutでinitramfsを作った際には 6.12.61-v8-rt+ としてカーネルモジュールをインストールしてしまっていた。 6.12.61-v8-rt+ この rt ってどういう意味なのか。

-rtの意味は?

6.12.61-v8-rt+ のようなカーネルバージョンに付く -rt は:

  • PREEMPT_RT パッチが適用されたリアルタイムカーネル
  • make menuconfig などで CONFIG_PREEMPT_RT_FULL=y などが有効になっている
  • レイテンシ(遅延)を減らすため、割り込みやスケジューラの動作が改良されている
  • オーディオ/制御システム/産業用Linux などで使われることが多い

🧪 Gentoo の場合、sys-kernel/rt-sources や自前でパッチを当てたカーネルで構成していると -rt 接尾辞が付きます。

/lib/modules/6.12.61-v8+ にある .ko がロードされるべきなのに dracut は /lib/modules/6.12.61-v8-rt+/ を参照して initramfs を作ってしまっている

dracut に対象カーネルバージョンを明示する方法

dracut --kver 6.12.61-v8+ --force /boot/initramfs-6.12.61-v8+.img