您的位置:首页 > 编程语言 > ASP

使用overlayfs打造一个只读的不怕意外关机的树莓派Raspberry Pi

2017-12-26 20:16 411 查看
树莓派的本领就不多说了。但是在树莓派的应用场合,关机的时候还是显得尴尬,先不说执行 sudo halt 要么需要ssh上去,要么需要有键盘和显示器,更不要说,有的场景可能连网络和显示器都没有,真正的 headless。 但是如果不执行sudo halt直接关电源,那么有很大的概率会损坏SD卡上的文件系统,甚至损坏SD卡。
overlayfs是linux系统下的一种影子文件系统,它可以把真正的存储文件系统作为只读挂载,而把所有文件改动都存放在RAM中,关机或者重启就失效,真正的保护了存储文件系统。  下面就说一下我在树莓派中实施overlayfs的方法,其实很简单。
我参考了这个帖子中介绍的方法: https://www.raspberrypi.org/forums/viewtopic.php?t=173063#p1151405
1. 首先,禁用交换空间,毕竟树莓派里的交换空间也是占用RAM(tempfs)的,所以如果使用了overlayfs后,交换空间就显得没有意义了。
执行如下3条命令:
sudo dphys-swapfile swapoff
sudo dphys-swapfile uninstall
sudo update-rc.d dphys-swapfile remove
2. 更新系统,保证系统为最新状态
sudo apt-get update
sudo apt-get upgrade


3. 保存如下脚本为 overlayRoot.sh
#!/bin/sh
# Read-only Root-FS for Raspian using overlayfs
# Version 1.0
#
# Created 2017 by Pascal Suter @ DALCO AG, Switzerland
# to work on Raspian as custom init script
# (raspbian does not use an initramfs on boot)
#
# Modified 2017-Apr-21 by Tony McBeardsley
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see
# <http://www.gnu.org/licenses/>.
#
#
# Tested with Raspbian mini, 2017-01-11
#
# This script will mount the root filesystem read-only and overlay it with a temporary tempfs
# which is read-write mounted. This is done using the overlayFS which is part of the linux kernel
# since version 3.18.
# when this script is in use, all changes made to anywhere in the root filesystem mount will be lost
# upon reboot of the system. The SD card will only be accessed as read-only drive, which significantly
# helps to prolong its life and prevent filesystem coruption in environments where the system is usually
# not shut down properly
#
# Install:
# copy this script to /sbin/overlayRoot.sh and add "init=/sbin/overlayRoot.sh" to the cmdline.txt
# file in the raspbian image's boot partition.
# I strongly recommend to disable swapping before using this. it will work with swap but that just does
# not make sens as the swap file will be stored in the tempfs which again resides in the ram.
# run these commands on the booted raspberry pi BEFORE you set the init=/sbin/overlayRoot.sh boot option:
# sudo dphys-swapfile swapoff
# sudo dphys-swapfile uninstall
# sudo update-rc.d dphys-swapfile remove
#
# To install software, run upgrades and do other changes to the raspberry setup, simply remove the init=
# entry from the cmdline.txt file and reboot, make the changes, add the init= entry and reboot once more.

fail(){
echo -e "$1"
/bin/bash
}

# Load overlay module
modprobe overlay
if [ $? -ne 0 ]; then
fail "ERROR: missing overlay kernel module"
fi

# Mount /proc
mount -t proc proc /proc
if [ $? -ne 0 ]; then
fail "ERROR: could not mount proc"
fi

# Create a writable fs on /mnt to then create our mountpoints
mount -t tmpfs inittemp /mnt
if [ $? -ne 0 ]; then
fail "ERROR: could not create a temporary filesystem to mount the base filesystems for overlayfs"
fi

# Mount a tmpfs under /mnt/rw
mkdir /mnt/rw
mount -t tmpfs root-rw /mnt/rw
if [ $? -ne 0 ]; then
fail "ERROR: could not create tempfs for upper filesystem"
fi

# Identify root fs device, PARTUUID, mount options and fs type

#rootDev=`blkid -o list | awk '$3 == "/" {print $1}'`
# Changed here(point to / ) in case the cmd above doesn't work # By ChenYang 20171122
rootDev=/dev/mmcblk0p2
rootPARTUUID=`awk '$2 == "/" {print $1}' /etc/fstab`
rootMountOpt=`awk '$2 == "/" {print $4}' /etc/fstab`
rootFsType=`awk '$2 == "/" {print $3}' /etc/fstab`

# Mount original root filesystem readonly under /mnt/lower
mkdir /mnt/lower
mount -t ${rootFsType} -o ${rootMountOpt},ro ${rootDev} /mnt/lower
if [ $? -ne 0 ]; then
fail "ERROR: could not ro-mount original root partition"
fi

# Mount the overlay filesystem
mkdir /mnt/rw/upper
mkdir /mnt/rw/work
mkdir /mnt/newroot
mount -t overlay -o lowerdir=/mnt/lower,upperdir=/mnt/rw/upper,workdir=/mnt/rw/work overlayfs-root /mnt/newroot
if [ $? -ne 0 ]; then
fail "ERROR: could not mount overlayFS"
fi

# Create mountpoints inside the new root filesystem-overlay
mkdir /mnt/newroot/ro
mkdir /mnt/newroot/rw

# Remove root mount from fstab (this is already a non-permanent modification)
grep -v "$rootPARTUUID" /mnt/lower/etc/fstab > /mnt/newroot/etc/fstab
echo "#the original root mount has been removed by overlayRoot.sh" >> /mnt/newroot/etc/fstab
echo "#this is only a temporary modification, the original fstab" >> /mnt/newroot/etc/fstab
echo "#stored on the disk can be found in /ro/etc/fstab" >> /mnt/newroot/etc/fstab

# Change to the new overlay root
cd /mnt/newroot
pivot_root . mnt
exec chroot . sh -c "$(cat <<END

# Move ro and rw mounts to the new root
mount --move /mnt/mnt/lower/ /ro
if [ $? -ne 0 ]; then
echo "ERROR: could not move ro-root into newroot"
/bin/bash
fi
mount --move /mnt/mnt/rw /rw
if [ $? -ne 0 ]; then
echo "ERROR: could not move tempfs rw mount into newroot"
/bin/bash
fi

# Unmount unneeded mounts so we can unmout the old readonly root
umount /mnt/mnt
umount /mnt/proc
umount /mnt/dev
umount /mnt

# Continue with regular init
exec /sbin/init
END
)"


注意,我的脚本和帖子里面的有些不同,我把
rootDev=`blkid -o list | awk '$3 == "/" {print $1}'`
改成了
rootDev=/dev/mmcblk0p2
不改的话,我这里overlayRoot.sh会运行失败

4. 将脚本拷贝到 /sbin/overlayRoot.shsudo cp overlayRoot.sh /sbin/overlayRoot.sh
sudo chmod a+x /sbin/overlayRoot.sh
5. 修改 cmdline.txt 文件,在行尾加上 "init=/sbin/overlayRoot.sh",如下是我的 /boot/cmdline.txt 文件的内容
pi@raspberrypi:~ $ cat /boot/cmdline.txt
dwc_otg.lpm_enable=0 console=serial0,115200 console=tty1 root=PARTUUID=0e82c2e4-02 rootfstype=ext4 elevator=deadline fsck.repair=yes rootwait init=/sbin/overlayRoot.sh
6. 为了保证整个SD卡都是只读,将 /boot 分区也修改为只读, 修改 fstab 文件,把/boot 对应的行改为ro,我的/etc/fstab文件内容如下
pi@raspberrypi:~ $ cat /etc/fstab
proc /proc proc defaults 0 0
PARTUUID=0e82c2e4-01 /boot vfat defaults,ro 0 2
PARTUUID=0e82c2e4-02 / ext4 defaults,noatime 0 1

7. 到这里 sudo reboot 重启,重启后,文件系统就处于影子系统的保护之下了,所有对于文件系统的改动,在重启后都将恢复原状。 用mount命令可以确认overlayfs的正常工作。
root-rw on /rw type tmpfs (rw,relatime)
/dev/mmcblk0p2 on /ro type ext4 (ro,noatime,data=ordered)
overlayfs-root on / type overlay (rw,relatime,lowerdir=/mnt/lower,upperdir=/mnt/
4000
rw/upper,workdir=/mnt/rw/work)
sysfs on /sys type sysfs (rw,nosuid,nodev,noexec,relatime)
proc on /proc type proc (rw,relatime)
devtmpfs on /dev type devtmpfs (rw,nosuid,size=470160k,nr_inodes=117540,mode=755)
tmpfs on /dev/shm type tmpfs (rw,nosuid,nodev)
devpts on /dev/pts type devpts (rw,nosuid,noexec,relatime,gid=5,mode=620,ptmxmode=000)
tmpfs on /run type tmpfs (rw,nosuid,nodev,mode=755)
tmpfs on /run/lock type tmpfs (rw,nosuid,nodev,noexec,relatime,size=5120k)
tmpfs on /sys/fs/cgroup type tmpfs (ro,nosuid,nodev,noexec,mode=755)
cgroup on /sys/fs/cgroup/systemd type cgroup (rw,nosuid,nodev,noexec,relatime,xattr,release_agent=/lib/systemd/systemd-cgroups-agent,name=systemd)
cgroup on /sys/fs/cgroup/cpu,cpuacct type cgroup (rw,nosuid,nodev,noexec,relatime,cpu,cpuacct)
cgroup on /sys/fs/cgroup/blkio type cgroup (rw,nosuid,nodev,noexec,relatime,blkio)
cgroup on /sys/fs/cgroup/devices type cgroup (rw,nosuid,nodev,noexec,relatime,devices)
cgroup on /sys/fs/cgroup/cpuset type cgroup (rw,nosuid,nodev,noexec,relatime,cpuset)
cgroup on /sys/fs/cgroup/memory type cgroup (rw,nosuid,nodev,noexec,relatime,memory)
cgroup on /sys/fs/cgroup/freezer type cgroup (rw,nosuid,nodev,noexec,relatime,freezer)
cgroup on /sys/fs/cgroup/net_cls type cgroup (rw,nosuid,nodev,noexec,relatime,net_cls)
systemd-1 on /proc/sys/fs/binfmt_misc type autofs (rw,relatime,fd=25,pgrp=1,timeout=0,minproto=5,maxproto=5,direct)
debugfs on /sys/kernel/debug type debugfs (rw,relatime)
sunrpc on /run/rpc_pipefs type rpc_pipefs (rw,relatime)
mqueue on /dev/mqueue type mqueue (rw,relatime)
configfs on /sys/kernel/config type configfs (rw,relatime)
/dev/mmcblk0p1 on /boot type vfat (ro,relatime,fmask=0022,dmask=0022,codepage=437,iocharset=ascii,shortname=mixed,errors=remount-ro)
tmpfs on /run/user/1000 type tmpfs (rw,nosuid,nodev,relatime,size=94952k,mode=700,uid=1000,gid=1000)

原来的根文件系统 /dev/mmcblk0p2 改为挂载在 /ro ,并且是只读;/boot 也挂载为只读;而 / 的 type 变成了overlay。

好了,直接拔电试试看吧。事实上你可以反复尝试不正常关机,都不会有问题。

8. 以后如果想禁用overlayfs,可以修改 cmdline.txt 把 "init=/sbin/overlayRoot.sh" 删掉,重启即可。 当然修改前要先把 /boot remount 成可写状态。
更新系统等操作都需要先禁用overlayfs后再执行。

9. 如果临时想修改原 /boot 以及根文件系统的内容可以如下命令remount

要remount /boot为可写
pi@raspberrypi:~ $ sudo mount -o remount,rw /boot
原来的根文件系统在overlayfs下是挂载在 /ro 的,要remount的话
pi@raspberrypi:~ $ sudo mount -o remount,rw /ro

注意,remount文件系统为可写后,要重启和关机需要使用sudo reboot或者sudo halt,不可以强行非正常关机,以免损坏文件系统。

PS. 网上有人报告,如果在不接显示器的情况下(即 headless),如上脚本会运行失败,但是我不接显示器时并没有遇到此问题 。

PS2. 网上有另外一个脚本,链接如下 https://gist.githubusercontent.com/niun/34c945d70753fc9e2cc7/raw/3d60338cd8d8daf740692f426a5a1ec17839d613/root-ro
使用了  update-initramfs 的方式,我在官方系统中可以使用,但是在修改了内核的系统中,运行失败。

欢迎交流

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: