概要
-
raspberry pi overlayfs
とかで、検索していたら、Domoticz - Open Source Home Automation SystemというプロジェクトのWikiに気になる記事が。 -
Setting up overlayFS on Raspberry Pi
-
/boot
とroot
ファイルシステムは通常、読み取り専用(ro)ーに変更. -
/var
と/home
は読み書きできる(rw)オーバーレイファイルシステムに変更. -
/etc/init.d/saveoverlays
のinitスクリプトで、システムのシャットダウンと再起動時にSDに同期させる。
-
-
これを使用すると、ほぼ完全にSDカードの書き込みを排除することができます。 読み書きの部分は、RAMベース(=Ramdisk)なので、(Domoticzを)スピードアップします。
#1 Google翻訳+ちょいと改
#2 Domoticz: Open Source Home Automation System というのが気になる。。がまたの機会に..
#3 再起動前にsudo service saveoverlays sync
をするのがよいかも。(RAMDisk上のファイルをSD側へ、rsync(なければコピー)してくれる)
#4 rootfsをro
にすると、apt-get
やら、できなくなる。設定の済んだ、組み込み以外は、あつかいが大変カモ?
環境
- Raspberry Pi 2/3 (1でもZeroでもいけるかと)
2016-05-27-raspbian-jessie-lite.img
手順
-
書いてあるとおりに..
-
いつもの+設定など行う (
/home
と/var
しか、書き込みできなくなるので、そのようにする) -
こぴぺ
cd /tmp
wget http://hansrune.net/domo/mount_overlay
wget http://hansrune.net/domo/saveoverlays
chmod a+rx saveoverlays mount_overlay
sudo cp mount_overlay /usr/local/bin
sudo cp saveoverlays /etc/init.d/
Swapをとめる.
sudo dphys-swapfile swapoff
sudo dphys-swapfile uninstall
sudo update-rc.d dphys-swapfile disable
fake-hwclockサービスは、/etc/fake-hwclock.data
ファイルを読み書きするので、実態を/var以下に移して、リンクをはる.
ここでサービスをdisableするが、saveoverlaysサービスで、呼ばれる
sudo service fake-hwclock stop
sudo mv /etc/fake-hwclock.data /var/log/fake-hwclock.data
sudo ln -s /var/log/fake-hwclock.data /etc/fake-hwclock.data
sudo service fake-hwclock start
sudo update-rc.d fake-hwclock disable
インストール fuse lsof rsync
lsof: ファイルシステムをリードオンリーに再マウントできないとき、オープンしてるファイルをみつけるのに役立つよ.
sudo apt-get install -y fuse lsof rsync
roを開始するとめんどうになるので、いろんな設定をしといたほうがいいかと。
#サービス開始
sudo systemctl enable saveoverlays.service
3. `sudo vi /boot/cmdline.txt`
```txt:/boot/cmdline.txt
dwc_otg.lpm_enable=0 console=serial0,115200 console=tty1 root=/dev/mmcblk0p2 rootfstype=ext4 elevator=deadline fsck.repair=yes rootwait noswap fastboot ro
- `noswap fastboot ro`を追加
-
sudo vi /etc/fstab
/etc/fstab
proc /proc proc defaults 0 0
/dev/mmcblk0p1 /boot vfat ro 0 2
/dev/mmcblk0p2 / ext4 ro,noatime 0 1
mount_overlay /var fuse nofail,defaults 0 0
mount_overlay /home fuse nofail,defaults 0 0
none /tmp tmpfs defaults 0 0
- `/dev/mmcblk0p1`と`/dev/mmcblk0p2` が `ro`になってるよ
5. Overlay関連
```txt:こぴぺ
#
#Overlayに使うのディレクトリ
sudo mv /home /home_org
sudo mkdir /home /home_rw
sudo mv /var /var_org
sudo mkdir /var /var_rw
#
#マウントしてみて、確認.
sudo mount /home
sudo mount /var
#
mount | grep home ; mount | grep var
ls -la /home/pi
```shell-session:こんなかんじ
pi@raspberrypi:~ $ mount | grep home ; mount | grep var
ramdisk on /home_rw type tmpfs (rw,relatime)
overlay on /home type overlay (rw,relatime,lowerdir=/home_org,upperdir=/home_rw/upper,workdir=/home_rw/work)
ramdisk on /var_rw type tmpfs (rw,relatime)
overlay on /var type overlay (rw,relatime,lowerdir=/var_org,upperdir=/var_rw/upper,workdir=/var_rw/work)
pi@raspberrypi:~ $ ls -la /home/pi
total 20
drwxr-xr-x 2 pi pi 4096 Jun 14 23:03 .
drwxr-xr-x 1 root root 40 Jun 14 23:28 ..
-rw-r--r-- 1 pi pi 220 May 27 11:09 .bash_logout
-rw-r--r-- 1 pi pi 3512 May 27 11:09 .bashrc
-rw-r--r-- 1 pi pi 675 May 27 11:09 .profile
-rw------- 1 pi pi 57 Jun 14 23:03 .Xauthority
6. `sudo reboot`
7. マウントできてるか確認
```shell-session:mount
pi@raspberrypi:~ $ mount
/dev/mmcblk0p2 on / type ext4 (ro,noatime,data=ordered)
.
.
.
fusectl on /sys/fs/fuse/connections type fusectl (rw,relatime)
none on /tmp type tmpfs (rw,relatime)
ramdisk on /home_rw type tmpfs (rw,relatime)
ramdisk on /var_rw type tmpfs (rw,relatime)
/dev/mmcblk0p1 on /boot type vfat (ro,relatime,fmask=0022,dmask=0022,codepage=437,iocharset=ascii,shortname=mixed,errors=remount-ro)
overlay on /var type overlay (rw,relatime,lowerdir=/var_org,upperdir=/var_rw/upper,workdir=/var_rw/work)
overlay on /home type overlay (rw,relatime,lowerdir=/home_org,upperdir=/home_rw/upper,workdir=/home_rw/work)
pi@raspberrypi:~ $
- 見所
/dev/mmcblk0p2 ... (ro, ...)
: リードオンリー
/dev/mmcblk0p1 ... (ro, ...)
: リードオンリー
/home_rw
と/var_rw
: RAMディスク
/home
と/var
: lowerdirをベースにupperdirを重ねる(lowerdir=/XXX_org,upperdir=/XXX_rw/upper,workdir=/XXX_rw/work
で、overlay)
システムメンテナンスのためのスクリプト
-
systemd
を使っているとうまく動かないので、↓のコメントの変更したスクリプトを使用すること!
#!/bin/bash
# remount root rw
mount -o remount,rw /
# prapare target paths
mkdir -p /chroot
mkdir -p /chroot/{bin,boot,dev,etc,home,lib,opt,proc,root,run,sbin,sys,tmp,usr,var}
# mount special filesystems
mount -t proc proc /chroot/proc
mount --rbind /sys /chroot/sys
mount --rbind /dev /chroot/dev
# bind rw directories
for f in {home,var}; do mount --rbind /${f}_org /chroot/$f; done
# bind remaining directories
for f in {bin,boot,etc,lib,opt,root,run,sbin,tmp,usr}; do mount --rbind /$f /chroot/$f; done
# chroot
echo "Note: /boot is still mounted read-only, remount to read-write if needed."
echo -e "\e[33mYou are now in read-write chroot. Use CTRL+D when done to exit chroot and mount read-only again.\e[39m"
chroot /chroot /usr/bin/env PS1="(rw) \u@\h:\w\$ " /bin/bash --noprofile -l
# unmount mounts
for f in /chroot/{bin,boot,dev,etc,home,lib,opt,proc,root,run,sbin,sys,tmp,usr,var}; do
umount -l $f
done
sleep 1
# remount read-only again
echo -e "\e[32mChroot left, re-mounting read-only again.\e[39m"
mount -o remount,ro /
-
sudo ./sysmaint.sh
-
=> 実行すると
chroot
つかって、ファイルの読み書きができるようになる(#/etc/fstab
で、rwにして再起動とか..)例
pi@raspberrypi:~$ sudo ./sysmaint.sh
Note: /boot is still mounted read-only, remount to read-write if needed.
You are now in read-write chroot. Use CTRL+D when done to exit chroot and mount read-only again.
(rw) root@raspberrypi:/$ vi /etc/fstab
...
(rw) root@raspberrypi:/$ logout
Chroot left, re-mounting read-only again.
pi@raspberrypi:~$
### もし、読み取り専用に再マウントできなかったら
sudo service saveoverlays sync
sudo reboot
### SDカードにシンクできてるかな?
`/var/log/saveoverlays.log` にログってる。
### その他
### `mount_overlay`
```bash:hansrune.net/domo/mount_overlay
#!/bin/sh
DIR="$1"
[ -z "${DIR}" ] && exit 1
#if ! grep -q overlay /proc/filesystems
#then
# echo "Filesystem overlay is not available. You need a kernel update: apt-get update && apt-get upgrade" >&2
# exit 2
#fi
if [ ! -d "${DIR}_org" ]
then
echo "${DIR}_org does not exist" >&2
exit 1
fi
if [ ! -d "${DIR}_rw" ]
then
echo "${DIR}_rw does not exist" >&2
exit 1
fi
#
# ro must be the first mount option for root .....
#
ROOT_MOUNT=$( grep -v "^#" /etc/fstab | awk '$2=="/" { print substr($4,1,2) }' )
if [ "$ROOT_MOUNT" != "ro" ]; then
/bin/mount --bind ${DIR}_org ${DIR}
else
/bin/mount -t tmpfs ramdisk ${DIR}_rw
/bin/mkdir ${DIR}_rw/upper
/bin/mkdir ${DIR}_rw/work
OPTS="-o lowerdir=${DIR}_org,upperdir=${DIR}_rw/upper,workdir=${DIR}_rw/work"
/bin/mount -t overlay ${OPTS} overlay ${DIR}
fi
saveoverlays
#! /bin/sh
### BEGIN INIT INFO
# Provides: saveoverlays
# Required-Start: $local_fs $time
# Required-Stop: $local_fs $syslog $time
# Default-Start: S
# Default-Stop: 0 6
# Short-Description: Save logs and files from overlay mounts
# Description: Save logs and files from overlay mounts
### END INIT INFO
# Do NOT "set -e"
#
# Testing hints:
# sudo mount -o remount,ro /
# sudo env INIT_VERBOSE=yes /etc/init.d/saveoverlays stop
# cat /var/log/saveoverlays.log
PATH=/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/bin
DESC="overlay filesystem sync"
NAME=saveoverlays
if [ -f "/etc/default/$NAME" ]; then
. "/etc/default/$NAME"
fi
TMPLOG=/tmp/$NAME.log
LOGFILE=/var_org/log/$NAME.log
SYNCDIRS=${SYNCDIRS:-$( mount | awk '/^overlay/ { print $3 ":" $3 "_org" }' )}
SYNCEXCLUDES=${SYNCEXCLUDES:-'--exclude .unionfs* --exclude .fuse_hidden* --exclude *.leases --exclude stats'}
SYNCFLAGS=${SYNCFLAGS:-"-avH --inplace --delete"}
# Check if we are running with read-only root
ROROOT=$( mount | egrep '^/dev/.*on / .*ro,' )
DOSYNC=${FORCESYNC:-"$ROROOT"}
# Load the VERBOSE setting and other rcS variables
. /lib/init/vars.sh
# Define LSB log_* functions.
# Depend on lsb-base (>= 3.2-14) to ensure that this file is present
# and status_of_proc is working.
. /lib/lsb/init-functions
#
# Function that starts the daemon/service
#
do_start()
{
if [ -n "${ROROOT}" ]
then
log_action_msg "Read-only root active"
else
log_action_msg "Read-only root inactive"
fi
if date '+%Y' | grep -q 1970
then
log_action_msg "Clock is not set. Trying fake-hwclock"
fake-hwclock load
fi
}
#
# Function that syncs the files
#
do_sync()
{
RETVAL=0
#
# If we run with overlayfs, try to sync the dirs
#
if [ -z "${ROROOT}" ] || mount -o remount,rw / >> ${TMPLOG} 2>&1
then
echo "----------------------------" >> ${TMPLOG}
echo "$NAME sync started at `date`" >> ${TMPLOG}
for DIR in ${SYNCDIRS}
do
SOURCE="${DIR%%:*}"
DEST="${DIR##*:}"
log_action_msg "Syncing ${SOURCE} to ${DEST} ..."
echo "----" >> ${TMPLOG}
echo "$NAME sync ${SOURCE} to ${DEST} with options ${SYNCFLAGS} ${SYNCEXCLUDES} at `date`" >> ${TMPLOG}
if [ -d "${SOURCE}" -a -d "${DEST}" ]
then
rsync ${SYNCFLAGS} ${SYNCEXCLUDES} ${SOURCE}/ ${DEST}/ >> ${TMPLOG} 2>&1
elif [ -f "${SOURCE}" ]
then
cp -vp ${SOURCE} ${DEST} >> ${TMPLOG} 2>&1
else
log_action_msg "Skipping this step: ${SOURCE} or ${DEST} not available"
fi
done
cat ${TMPLOG} >> ${LOGFILE}
if [ -w /etc/fake-hwclock.data ]
then
log_action_msg "Saving fake-hwclock"
fake-hwclock save
fi
log_action_msg "Sync changes to disk"
sync; sync; sync
#
# return to read-only only if that is where we started
#
if [ -n "${ROROOT}" ]
then
log_action_msg "Remount read-only"
mount -o remount,ro /
fi
else
log_action_msg "Remounting root as writeable failed!"
RETVAL=2
fi
return "$RETVAL"
}
#
# Function that stops the daemon/service
#
do_stop()
{
#
# If we run with overlayfs, try to sync the dirs
#
if [ -n "${DOSYNC}" ]
then
do_sync;
return $?
else
log_action_msg "Root is not read-only. No action"
return 0
fi
}
case "$1" in
start)
log_daemon_msg "Starting $DESC" "$NAME"
do_start
case "$?" in
0|1) log_end_msg 0 ;;
2) log_end_msg 1 ;;
esac
;;
stop)
log_daemon_msg "Stopping $DESC" "$NAME"
do_stop
case "$?" in
0|1) log_end_msg 0 ;;
2) log_end_msg 1 ;;
esac
;;
sync)
log_daemon_msg "Syncing $DESC" "$NAME"
do_sync
case "$?" in
0|1) log_end_msg 0 ;;
2) log_end_msg 1 ;;
esac
;;
status)
;;
restart)
;;
*)
echo "Usage: $SCRIPTNAME {start|stop|status|restart}" >&2
exit 3
;;
esac
: