OverlayfsによるRaspberry PiのSDカードROM化

SDカード(システムディスク)をリードオンリーで運用したい場合のお手軽な方法を紹介。

/etc/fstab に対するSystemdの処理なので、Raspberry Pi 以外でも使えます!

尚、 このサイトのサーバー 及び ルーター は、ここで紹介する方法でシャットダウンフリー化したRaspberry Pi 2 Model B(2018年2月~ Raspbian Stretch,2019年7月~ Raspbian Buster,2021年12月~ Raspbian Bullseye)上で動作しています。

○.概要

・システムSDカードを読み取り専用とした上で、書き込み処理が必要なディレクトリーを選択してOverlayfsによりtmpfs上で運用する。
・Filesystem in Userspace (FUSE)を活用し、fstabにて上記Overlayfsをマウント指示。
・fstabのルートパーティションのマウントオプションが読み取り専用"ro"で無い場合は通常起動。

swapの無効化、/fsprotectの作成等は済んでいる事が前提です。
また、/proc/filesystemsにoverlayが無い場合は、モジュールのロード(modprobe overlay)が必要です。

1.パッケージの追加

FUSEマウントのためにfuseを追加。

sudo apt-get install fuse

/sbin/mount.fuse をoverlayマウント時に使用します。

2./usr/local/bin/mount_overlay の配置

fstabでのfuseマウントで使用するスクリプトを以下の様な内容で配置。
----------------------

#!/bin/sh

DIR="$1"
ROOT_MOUNT=$( awk '$2=="/" { print substr($4,1,2) }' /proc/mounts )

if [ "$ROOT_MOUNT" = "ro" ]; then
  if [ -e "${DIR}" ]; then

# tmpfsを/fsprotect にマウント(注1)
    /bin/mount -t tmpfs -o size=320m tmpfs ${DIR}

    for d in usr lib etc home root var
    do
    /bin/mkdir ${DIR}/${d}
    /bin/mkdir ${DIR}/${d}_rw
    OPTS="-o lowerdir=/${d},upperdir=${DIR}/${d},
    workdir=${DIR}/${d}_rw"
    /bin/mount -t overlay ${OPTS} overlay /${d}
    done
  fi
fi
# /var/logを独立してtmpfsに配置したい場合はここでマウント(注2)
/usr/local/bin/make_log_files
exit 0

----------------------

注1).tmpfsの容量を指定しない場合は合計RAM容量の半分に設定されますが、確保されないのか、サーバープログラムの動作に影響が出る場合がありましたので容量を指定しています。(但し確保されないという確証はありませんのでご自身で調査してください)

注2). tmpfsを/var/log にマウントすると共に、必要に応じて /var/log 配下の必要なディレクトリーやファイルを続けて作成。

/usr/local/bin/make_log_files を以下の様な内容にて配置しておき、fstabにて/usr/local/bin/mount_overlay から呼び出す。
2.のスクリプト例では通常起動した場合でもtmpfsを/var/log にマウントし、/var/logにゴミが溜まることを防ぎます。

#!/bin/sh

/bin/mount -t tmpfs tmpfs /var/log

/bin/mkdir -p /var/log/apache2
/bin/chown root.adm /var/log/apache2

/bin/mkdir -p /var/log/samba
/bin/chown root.adm /var/log/samba

/bin/mkdir -p /var/log/sysstat

#/bin/mkdir -p /var/log/apt
#/bin/mkdir -p /var/log/private
#/bin/touch /var/log/lastlog
#/bin/chown root.utmp /var/log/lastlog

3./etc/fstab

・SDカードのパーティションをリードオンリー(ro)でマウント。
・/tmp には予めtmpfsをマウント。
・fuseマウントにより、mount_overlayスクリプトにて選択したディレクトリーを /fsprotect 以下にoverlayで展開。

proc /proc proc defaults 0 0
/dev/mmcblk0p1 /boot vfat ro,defaults 0 2
/dev/mmcblk0p2 / ext4 ro,defaults,noatime 0 1
mount_overlay /fsprotect fuse nofail,defaults 0 0
tmpfs /tmp tmpfs defaults 0 0

・上記手順でマウントした場合のdf結果

ファイルシス 1K-ブロック 使用 使用可 使用% マウント位置
/dev/root 7460628 1456788 5667940 21% /
devtmpfs 469544 0 469544 0% /dev
tmpfs 474152 0 474152 0% /dev/shm
tmpfs 474152 35964 438188 8% /run
tmpfs 5120 0 5120 0% /run/lock
tmpfs 474152 0 474152 0% /sys/fs/cgroup
tmpfs 474152 0 474152 0% /tmp
tmpfs 327680 7992 319688 3% /fsprotect
overlay 327680 7992 319688 3% /usr
overlay 327680 7992 319688 3% /lib
overlay 327680 7992 319688 3% /etc
overlay 327680 7992 319688 3% /home
overlay 327680 7992 319688 3% /root
overlay 327680 7992 319688 3% /var
tmpfs 474152 3000 471152 1% /var/log
/dev/mmcblk0p1 258096 39973 218123 16% /boot
tmpfs 94828 0 94828 0% /run/user/1000

●起動モード切替用スクリプトを用意しておくと便利

・プロテクトモードで起動した状態で、次回ブート時通常モード

/usr/local/bin/noprotect

#!/bin/sh
sudo mount -o rw,remount /
sudo umount -l /etc
sudo sed -i ’s/ro,defaults/rw,defaults/g’ /etc/fstab
cat /etc/fstab

・通常モードで起動した状態で、次回ブート時プロテクトモード

/usr/local/bin/protect

#!/bin/sh
sudo sed -i ’s/rw,defaults/ro,defaults/g’ /etc/fstab
cat /etc/fstab