OF Overlayfs ROM 化
Raspberry Pi / Linux / overlayfs

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

システム SD カード(ルート)を読み取り専用で運用しつつ、書き込みが必要なディレクトリは overlayfstmpfs で吸収するミニマルな構成。Systemd による /etc/fstab の処理を利用するため、Raspberry Pi 以外でも使えます。

※ このサイトのサーバーおよびルーターは、ここで紹介する方法でシャットダウンフリー化した Raspberry Pi 2 Model B 上で動作しています。

○ 概要

  • システム SD カードを 読み取り専用 でマウントし、書き込みが必要なディレクトリのみを選んで overlayfstmpfs 上に展開。
  • FUSE を活用し、/etc/fstab から上記 overlayfs をマウント。
  • /(ルート)のマウントオプションが ro でない場合は 通常起動(書き込み可能)。

前提:swap の無効化、/fsprotect の作成済み。/proc/filesystemsoverlay が無い場合は modprobe overlay が必要です。

Raspberry Pi 専用ではなく、他の Linux でも同様の考え方で利用可能です。

1.パッケージの追加

FUSE マウントのために fuse を追加します。
/sbin/mount.fuse を overlay マウント時に使用。

sudo apt-get install -y fuse

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 の 半分 が上限となる挙動です。サーバープログラムに影響する場合があったため明示容量(例:320m)を指定しています。※挙動は環境により異なる可能性があります。

注2)ログの tmpfs 化

/var/log を独立して tmpfs にマウントし、必要なディレクトリ/ファイルを作成します(下記 make_log_files 参照)。

2-補./usr/local/bin/make_log_files

以下の様なスクリプトを配置し、mount_overlay から呼び出します。
通常起動時でも /var/logtmpfs にすることで、SDカードにゴミが溜まることを防ぎます。

#!/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 に展開。
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

● 起動モード切替スクリプト

プロテクト(読み取り専用)で運用しつつ、次回ブートで通常モードに戻したい/その逆を切り替えたいときに便利です。

1) プロテクト状態 → 次回ブートは通常モード

パス:/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

2) 通常状態 → 次回ブートはプロテクトモード

パス:/usr/local/bin/protect

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

Tips / 安全のために

  • 導入前に 必ずバックアップ を取得しましょう(SD 複製推奨)。
  • overlay の対象に含めないディレクトリは、読み取り専用のままとなる点に注意。
  • tmpfs は RAM を消費します。メモリの空き容量とプロセスの動作要件を考慮してサイズを決めてください。
  • トラブル時は noprotect で通常モードに戻し、ログ(必要なら一時的に /var/log をディスク配置)を確認。