ルートファイルシステムを保護するためにOverlayFSを正しく使用するにはどうすればよいですか?
SDカードから起動して実行する組み込みシステムがあります。突然の電源喪失が発生するので、ルートファイルシステムを保護したいと思います。 OverlayFS が最も簡単な解決策のように見えますが、私が見つける例は通常、ルートファイルシステムを含まないか、メモリが非常に少ないので私には適さないtmpfsを使用します。
CONFIG_OVERLAY_FS=y
を有効にしてLinuxカーネル4.4.0を使用しています。私のファイルシステムはxenial-base-armhf.tar.gz
で、apt install -y overlayroot
を実行しました。
SDカードは次のようになります。
# fdisk -l /dev/mmcblk1
Disk /dev/mmcblk1: 29 GiB, 31104958464 bytes, 60751872 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: dos
Disk identifier: 0x7f56a0ab
Device Boot Start End Sectors Size Id Type
/dev/mmcblk1p1 * 2048 1050623 1048576 512M c W95 FAT32 (LBA)
/dev/mmcblk1p2 1050624 1052671 2048 1M da Non-FS data
/dev/mmcblk1p3 1052672 7344127 6291456 3G 83 Linux
/dev/mmcblk1p4 7344128 60751871 53407744 25.5G 5 Extended
/dev/mmcblk1p5 7346176 13637631 6291456 3G 83 Linux
/dev/mmcblk1p6 13639680 60751871 47112192 22.5G 83 Linux
OverlayFSを作成する前に、すべてが次のようにマウントされます。
# mount
/dev/mmcblk1p3 on / type ext4 (rw,noatime,data=ordered)
devtmpfs on /dev type devtmpfs (rw,relatime,size=170440k,nr_inodes=42610,mode=755)
sysfs on /sys type sysfs (rw,nosuid,nodev,noexec,relatime)
proc on /proc type proc (rw,nosuid,nodev,noexec,relatime)
tmpfs on /dev/shm type tmpfs (rw,nosuid,nodev)
devpts on /dev/pts type devpts (rw,nosuid,noexec,relatime,gid=5,mode=620)
tmpfs on /run type tmpfs (rw,nosuid,nodev,mode=755)
tmpfs on /run/lock type tmpfs (rw,nosuid,nodev,noexec,relatime,size=5120k)
tmpfs on /sys/fs/cgroup type tmpfs (ro,nosuid,nodev,noexec,mode=755)
cgroup on /sys/fs/cgroup/systemd type cgroup (rw,nosuid,nodev,noexec,relatime,xattr,release_agent=/lib/systemd/systemd- cgroups-agent,name=systemd)
configfs on /sys/kernel/config type configfs (rw,relatime)
tmpfs on /run/user/0 type tmpfs (rw,nosuid,nodev,relatime,size=35752k,mode=700)
/dev/mmcblk1p6 on /opt type ext4 (rw,noatime,data=ordered)
/dev/mmcblk1p5 on /overlay type ext4 (rw,noatime,data=ordered)
私の計画は、/dev/mmcblk1p5
にマウントされたオーバーレイファイルシステムとして/overlay
を使用することでした。
# tree /overlay
/overlay
├── lost+found
├── root-fs
└── work
次の理由により、私は物事を間違っているか、設定に問題があります。
# mount -t overlay overlay -o lowerdir=/,upperdir=/overlay/root-fs,workdir=/overlay/work /
# mount
/dev/mmcblk1p3 on / type ext4 (rw,noatime,data=ordered)
devtmpfs on /dev type devtmpfs (rw,relatime,size=170440k,nr_inodes=42610,mode=755)
sysfs on /sys type sysfs (rw,nosuid,nodev,noexec,relatime)
proc on /proc type proc (rw,nosuid,nodev,noexec,relatime)
tmpfs on /dev/shm type tmpfs (rw,nosuid,nodev)
devpts on /dev/pts type devpts (rw,nosuid,noexec,relatime,gid=5,mode=620)
tmpfs on /run type tmpfs (rw,nosuid,nodev,mode=755)
tmpfs on /run/lock type tmpfs (rw,nosuid,nodev,noexec,relatime,size=5120k)
tmpfs on /sys/fs/cgroup type tmpfs (ro,nosuid,nodev,noexec,mode=755)
cgroup on /sys/fs/cgroup/systemd type cgroup (rw,nosuid,nodev,noexec,relatime,xattr,release_agent=/lib/systemd/systemd-cgroups-agent,name=systemd)
configfs on /sys/kernel/config type configfs (rw,relatime)
tmpfs on /run/user/0 type tmpfs (rw,nosuid,nodev,relatime,size=35752k,mode=700)
/dev/mmcblk1p6 on /opt type ext4 (rw,noatime,data=ordered)
/dev/mmcblk1p5 on /overlay type ext4 (rw,noatime,data=ordered)
overlay on / type overlay (rw,relatime,lowerdir=/,upperdir=/overlay/root-fs,workdir=/overlay/work)
それはうまくいったようですが、私が次のようなファイルを作成した場合:
# touch /root/test_file_write
次に、電源をオフにしてデスクトップのSDカードを見ると、/dev/mmcblk1p3/root/test_file_write
が期待どおりの/dev/mmcblk1p5/root-fs/root/test_file_write
ではないことがわかります。
これでうまくいくでしょうか?
1つの解決策は、initramfsを使用して、overlayfsでrootfsをマウントすることです。
あなたは一見することができます それがラズベリーパイでどのように行われるか
または、ARMデバイスを使用していない場合、 the overlayroot
Ubuntuパッケージ
この回答は私自身の経験に基づいていますが、組み込みデバイスではありません。多分それはこのセットアップでつまずく他の人にとって有用です-あなたはそれをあなたの特定の状況に適応させるか、少なくともうまくいけばそこから何かを学ぶべきです。
簡単な方法は、ルートファイルシステムがマウントされたときに場所をハイジャックし(initramfsで、それ以外の場合はinit
プロセスをハイジャックして)、そこにオーバーレイをマウントしてから、通常どおり続行します。 initramfsなしでマウントする場合は、通常のinit
に制御を渡す前に、スクリプト内のすべての仮想ファイルシステム(例:/proc
および/sys
)を移動することを忘れないでください。
しない initramfsが必要な場合は、Masieu Maretのリンクされたソリューションをラズベリーで実行する方法が機能するはずです。基本的に、カーネルへのコマンドラインを介してinit
プロセス/スクリプトを独自のものでオーバーライドします。スクリプトを/sbin/init-overlay
のルートファイルシステムに作成し、init=/sbin/init-overlay
をブートローダーの構成のカーネルブートパラメーターに追加する必要があるとします。
init-overlay
スクリプトは、制御をinit
に渡す前に何でもできます。この場合、オーバーレイを別のディレクトリにマウントし、次にchroot
をそれに追加します。
Initramfsでそれを行うための可能な方法は、ルートファイルシステムをマウントした後、initramfs内の/init
スクリプトを単にハイジャックすることです。たとえば、オーバーレイルートだけでなく、/run/rootfs/ro
および/run/rootfs/rw
にある元のマウントポイントにもアクセスしたいとします(前者は読み取り専用ルート、後者は変更を行います)。 、upperdir
)システムが稼働した後。また、システムを起動するドライブに、読み取り専用のルートファイルシステムを含むroot.squashfs
ファイルがあり、それをマウントしたいとします。システムの起動後に、便宜上/media/drive
または同様のドライブにもアクセスしたいとします。
Initramfsスクリプトをハイジャックする理由は、いずれにしてもデフォルトのスクリプトコマンドを実行してしまういくつかの既成のパラメーターを使用するよりも、プロセスの柔軟性が高くなるためです。したがって、ブート構成を編集して、「ルート」ファイルシステムが実際にroot.squashfs
が見つかった場所であるという情報をカーネルに渡す必要があります。後でマウントします。
VFATパーティションでsyslinux.cfg
を使用した一般的なコマンドは次のとおりです(必要に応じてUUIDを変更します)。
label linux
linux vmlinuz
append root=UUID=ABCD-1234 rootfstype=vfat rootflags=ro,umask=022,quiet ro quiet splash
initrd initrd.img
これは、VFATパーティションにroot.squashfs
を配置することを想定していますが、これは理想的ではない可能性があります(root =として指定する必要があるのは、root.squashfs
を含むパーティションまたはファイルシステム、または以下のようなファイルシステムです。圧縮したくない場合は、実際のルートファイルシステム)。ただし、ブートパーティション自体に配置することを前提に説明しています。 実行する組み込みシステムの種類がわからないので、ここでは独自の判断をする必要があります。
最初に、/ tmpのどこかにinitramfsを抽出して、その/init
スクリプトを変更できるようにする必要があります。パックする前に所有権を適切に保持するために、root
(スーパーユーザー)としてそれを行うことを忘れないでください。それがどのように実行できるかを理解した後で、おそらくすべてをスクリプト化できます。たとえば、編集のために/tmp/initramfs
に解凍します。
mkdir /tmp/initramfs 2>/dev/null; (cd /tmp/initramfs && zcat /initrd.img | Sudo cpio -idmv)
次に、デフォルトのスクリプトがルートをマウントする場所を見つける必要があります。 /tmp/initramfs/init
で次のようなものを探します(rootとして編集):
maybe_break mount
log_begin_msg "Mounting root file system"
. /scripts/${BOOT}
parse_numeric ${ROOT}
maybe_break mountroot
mountroot
log_end_msg
これがどのように機能するかを理解する必要はありません。理解する必要があるのは、これがroot.squashfs
を含む通常のファイルシステムを、明らかに${rootmnt}
シェル変数を介して指定されたマウントポイントにマウントすることです。
つまり、この時点で${rootmnt}
にあるのはVFATパーティション(またはroot=
コマンドラインパラメーターで指定したもの)です。このスクリプトは、すべての仮想ファイルシステムを${rootmnt}
マウントポイントに移動するなど、他のことも実行するため、すべてのカスタム処理を必ず実行する必要がありますafter上記のコード。
あなたがしなければならないのは、initramfsの/init
に上記のコードの後に次のようなものを挿入することだけです:
# create some temporary directories under the initramfs's /run
# they will be our mountpoints and such, which will get moved
# by the default script to the actual root filesystem...
mkdir -m 755 /run/rootfs
mount -t tmpfs -o size=90%,mode=755,suid,exec tmpfs /run/rootfs
mkdir -m 755 /run/rootfs/drive /run/rootfs/ro /run/rootfs/rw /run/rootfs/.workdir
# move the original root that was mounted, temporarily
mount -n -o move "${rootmnt}" /run/rootfs/drive
# mount the squashfs and then the overlay to our designated locations
mount -t squashfs -o defaults,ro /run/rootfs/drive/root.squashfs /run/rootfs/ro
mount -t overlay -o lowerdir=/run/rootfs/ro,upperdir=/run/rootfs/rw,workdir=/run/rootfs/.workdir root "${rootmnt}"
# at this point we have our overlay root at ${rootmnt}!
# however, move the drive's filesystem mount to the new root
# this allows it to be accessed afterwards from /media/drive
# NOTE: this assumes you have the /media/drive dir in the root squashfs
mount -n -o move /run/rootfs/drive "${rootmnt}/media/drive"
rm -d /run/rootfs/drive
それでおしまい。スクリプトは通常どおり続行されますが、ルートファイルシステムがオーバーレイになり、そのすべての部分に後で簡単にアクセスできます。これはエラーチェックなしを実行することに注意してください。これは、上記のコマンドに追加するか、overlay
モジュールがロードされていることを確認するための独自の裁量に任されています。
今すぐinitramfsをパックしてください:
Sudo sh -c 'cd /tmp/initramfs && find . -print0 | cpio --null -ov --format=newc' | gzip -9 > /tmp/initrd.img
/tmp/initrd.imgをSDカードまたはどこにでもコピーします。 VFATパーティションのルートディレクトリにroot.squashfs
を配置することを忘れないでください。これは明らかに簡単にカスタマイズでき、この方法で行う必要はありません。これは、syslinux(およびUEFIブート)での「最も簡単な」方法であり、決して最良の方法ではありません。
申し訳ありませんが、組み込みデバイスを要求したことは知っていますが、そこでのブートプロセスのしくみがわかりません。x86の例を使用していますが、その部分はそれほど重要ではありません(syslinux.cfg
部分のみ)。
注意してくださいこれにより、overlayfs
の書き込み可能な部分がtmpfs
として作成されますが、これは意図したものではありません。ただし、それは簡単に変更です。上記を参照すると、書き込み先のどこにでも、tmpfsの代わりに/run/rootfs
をマウントするだけです。