LoginSignup
26
27

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
    
  4. sudo vi /boot/cmdline.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を追加
  5. 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/mmcblk0p2roになってるよ
  6. Overlay関連

    こぴぺ
    #
    #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
    
    こんなかんじ
    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
    
  7. sudo reboot

  8. マウントできてるか確認

    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

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
27
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
27