缘起
最近总是会有一些需求,就是快速地部署一个临时的网关。有的时候,用于部署网关的电脑可能只是临时拿来用的。因此,给人家重新装个系统就很不靠谱了。我通常的做法是,在我的 U 盘里装个 ubuntu 之类的。然后里边装上 bind、isc-dhcp-server 之类的,然后每次用这个 U 盘启动就好了。后来发现,这个问题并不是那么简单,因为 U 盘插在别人的电脑上,一来容易丢失,二来容易被物理碰撞损坏。于是我就考虑,能不能在启动后,把根文件系统载入到内存中,这样就可以拔掉 U 盘了。一种方案
有一种方案是显然可行的,就是把整个系统搞成一个 initrd,这样自然就在内存中了。这样作的弊端是,initrd 是 bootloader 载入到内存中的。而 Grub 读取硬盘的驱动是走的 BIOS,这样速度就很慢了。同时,尽可能少的改动发行版,也有利于后续继续安装软件和维护。我的思路
我的思路是,在 initrd 执行完毕后,替换掉原系统的 init 程序,换上去我的,然后 mount 上去一个 tmpfs,然后把根文件系统拷贝过去,最后 chroot 进去,起里边原来的 init。虽说思路是很简单的,但是要想实现起来,还是有一些细节要考虑的,主要要点是:
- 合理地把之前挂上去的 / 给 umount 掉
实现方法
写一个脚本,放在/usr/local/sbin/init.sh
下,内容是:1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 | read -p "Input 'y' in 5 seconds to boot normally..." -t 5 yes if [ \( x$yes = xy \) -o \( x$yes = xY \) ]; then exec /sbin/init "$@" echo failed... sleep 10000 fi echo Reading rootfs, it may take several minutes... mkdir -p /run/rootfs mount -t tmpfs -o size=4G shankers-mem-ubuntu /run/rootfs rsync -a / /run/rootfs/ --exclude=/proc --exclude=/dev --exclude=/sys --exclude=/run --exclude=/var/cache --exclude=/var/log --exclude=/usr/include --exclude=/usr/local/include cd /run/rootfs for i in proc dev sys run var/cache var/cache/bind var/log; do mkdir -p $i done mount -t proc mem_proc proc mount -t sysfs mem_sys sys mount -t tmpfs mem_run run mount -t devtmpfs mem_dev dev mount -t devpts mem_devpts dev/pts mount -t tmpfs mem_tmpfs tmp echo > etc/fstab mkdir oldroot #exec /bin/bash pivot_root . oldroot ### # 这里之所以 >dev/console,是因为现在的 init.sh 的 # stdin、stdout 和 stderr 原本指向了 /dev/console # 由于 /dev 是挂载在原来的 root 下的,pivot_root 后 # 跑到了 /oldroot/dev/console 中。如果不加上 >dev/console, # 就会保持 /oldroot/dev/console 打开,导致 /oldroot # umount 不下来。 ### exec chroot . bin/bash -s "$@" >dev/console 2>&1 << 'HERE' cd / umount -R oldroot rmdir oldroot echo Will start mem system in 5 seconds... sleep 5 exec /sbin/init "$@" </dev/console >/dev/console 2>&1 echo failed... sleep 10000 HERE |
chmod +x /usr/local/sbin/init.sh
。之后新建一个
/etc/default/grub.d/memroot.cfg
,里边写上:1
| GRUB_CMDLINE_LINUX_DEFAULT="$GRUB_CMDLINE_LINUX_DEFAULT init=/usr/local/sbin/init.sh"
|
1
| update-grub
|
以上脚本在 Ubuntu 16.04 下测试通过。
from https://innull.com/linux-in-memory-how-to/
No comments:
Post a Comment