26
28

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

[メモ] Raspberry Piで OverlayFS (組み込み向け設定・スクリプト)

Last updated at Posted at 2016-06-14

概要

  • raspberry pi overlayfs とかで、検索していたら、Domoticz - Open Source Home Automation SystemというプロジェクトのWikiに気になる記事が。

  • Setting up overlayFS on Raspberry Pi

    • /bootrootファイルシステムは通常、読み取り専用(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

手順

  1. 書いてあるとおりに..

  2. いつもの+設定など行う (/home/varしか、書き込みできなくなるので、そのようにする)

  3. こぴぺ

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`を追加
  1. 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を使っているとうまく動かないので、↓のコメントの変更したスクリプトを使用すること!
sysmaint.shというファイル名にしときます.
#!/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

hansrune.net/domo/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

:
26
28
6

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
26
28

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?