├── etc └── overlayroot.conf ├── overlayroot ├── module-setup.sh └── mount-overlayroot.sh ├── Makefile ├── LICENSE ├── specs └── dracut-modules-overlayroot.spec ├── README.md └── bin └── overlayroot-chroot /etc/overlayroot.conf: -------------------------------------------------------------------------------- 1 | #overlayrootdevice=/dev/nvme0n1 2 | -------------------------------------------------------------------------------- /overlayroot/module-setup.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # -*- mode: shell-script; indent-tabs-mode: nil; sh-basic-offset: 4; -*- 3 | # ex: ts=8 sw=4 sts=4 et filetype=sh 4 | 5 | check() { 6 | require_binaries /usr/bin/mount 7 | require_binaries /usr/bin/umount 8 | require_binaries /usr/sbin/mkfs.xfs 9 | } 10 | 11 | depends() { 12 | return 0 13 | } 14 | 15 | installkernel() { 16 | instmods overlay 17 | instmods "=fs/overlayfs" 18 | } 19 | 20 | install() { 21 | dracut_install /usr/bin/mount 22 | dracut_install /usr/bin/umount 23 | dracut_install /usr/sbin/mkfs.xfs 24 | inst_hook pre-pivot 10 "$moddir/mount-overlayroot.sh" 25 | } 26 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # 2 | # Makefile 3 | # 4 | 5 | build: 6 | 7 | DRACUT_OVERLAYROOT_D = dracut/modules.d/50overlayroot 8 | 9 | install: 10 | mkdir -p "$(BUILDROOT)/$(DESTDIR)/$(DRACUT_OVERLAYROOT_D)" 11 | for f in mount-overlayroot.sh module-setup.sh; do \ 12 | install "overlayroot/$$f" \ 13 | "$(BUILDROOT)/$(DESTDIR)/$(DRACUT_OVERLAYROOT_D)/" ; \ 14 | done 15 | mkdir -p "$(BUILDROOT)/usr/sbin" 16 | for f in bin/*; do \ 17 | install "$$f" \ 18 | "$(BUILDROOT)/usr/sbin" ; \ 19 | done 20 | mkdir -p "$(BUILDROOT)/etc" 21 | install "etc/overlayroot.conf" "$(BUILDROOT)/etc" 22 | 23 | rpm: 24 | rpmbuild -ba specs/dracut-modules-overlayroot.spec 25 | 26 | publish: 27 | aws s3 cp /usr/src/rpm/RPMS/noarch/dracut-modules-overlayroot-0.1-beta.amzn1.noarch.rpm s3://gfleury --acl public-read 28 | 29 | # vi: ts=4 noexpandtab syntax=make 30 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 George Fleury 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /specs/dracut-modules-overlayroot.spec: -------------------------------------------------------------------------------- 1 | Summary: Dracut module to mount the root partition with a RW fs on top of a RO fs 2 | Name: dracut-modules-overlayroot 3 | Version: 0.2 4 | Release: beta%{?dist} 5 | License: GPLv3 6 | Group: System Environment/Base 7 | Source0: https://github.com/gfleury/overlayroot/archive/v%{version}.zip 8 | 9 | Requires: dracut 10 | Requires: util-linux 11 | 12 | BuildArch: noarch 13 | 14 | %description 15 | This dracut module will re-mount the root fs with overlayfs on top of the real 16 | root filesystem. Keeping the real root filesystem in read-only mode. All the 17 | writes and new data are written another filesystem (root-rw). 18 | 19 | %prep 20 | # extract cloud-utils 21 | %setup -q -n overlayroot-%{version} 22 | 23 | 24 | %build 25 | 26 | 27 | %install 28 | make install BUILDROOT=%{buildroot} DESTDIR=%{_exec_prefix}/lib 29 | 30 | 31 | %files 32 | %doc README.md 33 | %if 0%{?amzn} || 0%{?rhel} || 0%{?centos} 34 | %dir %{_prefix}/lib/dracut/modules.d/50overlayroot 35 | %{_prefix}/lib/dracut/modules.d/50overlayroot/mount-overlayroot.sh 36 | %{_prefix}/lib/dracut/modules.d/50overlayroot/module-setup.sh 37 | /etc/overlayroot.conf 38 | %{_prefix}/sbin/overlayroot-chroot 39 | %endif 40 | 41 | %post 42 | 43 | 44 | %changelog 45 | * Sun Apr 09 2017 George Fleury - 0.1-beta 46 | - First version 47 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Dracut module to permit root fs overlay 2 | 3 | Mount virtual root fs with rw-fs pointing to one filesystem on top or ro-fs from another filesystem. 4 | 5 | Usages examples: 6 | - EC2 ephemeral storage as RW on top of EBS volumus as a RO. (probably same performance from instances storage). 7 | - Get instance storage IOPS performance on EBS root volumes. 8 | - If the root EBS volume fails, should improve the graceful degradation. 9 | - Protect root filesystem from modifications. 10 | - The root device volume for an I3 instance must be an Amazon EBS volume. So this allow you to use all nvme drivers performance on the root file system. Allowing you to use ephemeral volumes as I3 root filesystem. 11 | 12 | ## Latest version: 13 | 14 | - CentOS5/6, Amazon Linux 1 15 | - https://github.com/gfleury/overlayroot/releases/download/v0.1/dracut-modules-overlayroot-0.1-beta.el7.noarch.rpm 16 | - CentOS7, Amazon Linux 2 17 | - https://github.com/gfleury/overlayroot/releases/download/v0.1/dracut-modules-overlayroot-0.2-beta.el7.noarch.rpm 18 | 19 | ## Known problems 20 | 21 | - Only support one filesystem per system (Only rootfs) 22 | 23 | 24 | ## Using 25 | 26 | - Spin up an Amazon Linux instance with root EBS volume and with ephemeral storage 27 | - Update to latest version 28 | - Install the overlayroot package 29 | - Recreate initramfs 30 | - Reboot 31 | 32 | ``` 33 | yum install kernel-4.9.20-10.30.amzn1.x86_64 -y 34 | rpm -ivh https://s3.amazonaws.com/gfleury/dracut-modules-overlayroot-0.1-beta.amzn1.noarch.rpm 35 | echo "overlayrootdevice=/dev/xvdb" >> /etc/overlayroot.conf 36 | dracut -f /boot/initramfs-4.9.20-10.30.amzn1.x86_64.img 4.9.20-10.30.amzn1.x86_64 37 | reboot 38 | ``` 39 | ** this example the ephemeral device is /dev/xvdb 40 | 41 | [1] https://www.kernel.org/doc/Documentation/filesystems/overlayfs.txt 42 | -------------------------------------------------------------------------------- /bin/overlayroot-chroot: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # 3 | # overlay-chroot - chroot wrapper script for overlay 4 | # Copyright (C) 2012 Dustin Kirkland 5 | # 6 | # Authors: Dustin Kirkland 7 | # George Fleury 8 | # 9 | # This program is free software: you can redistribute it and/or modify 10 | # it under the terms of the GNU General Public License as published by 11 | # the Free Software Foundation, version 3 of the License. 12 | # 13 | # This program is distributed in the hope that it will be useful, 14 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | # GNU General Public License for more details. 17 | # 18 | # You should have received a copy of the GNU General Public License 19 | # along with this program. If not, see . 20 | 21 | set -e 22 | set -f # disable path expansion 23 | REMOUNTS="" 24 | 25 | error() { 26 | printf "ERROR: $@\n" 1>&2 27 | } 28 | fail() { [ $# -eq 0 ] || error "$@"; exit 1; } 29 | 30 | info() { 31 | printf "INFO: $@\n" 1>&2 32 | } 33 | 34 | get_lowerdir() { 35 | local overlay="" 36 | overlay=$(awk \ 37 | '$1 == "overlay" && $2 == "/" { print $0 }' /proc/mounts) 38 | if [ -n "${overlay}" ]; then 39 | lowerdir=${overlay##*lowerdir=} 40 | lowerdir=${lowerdir%%,*} 41 | if mountpoint "${lowerdir}" >/dev/null; then 42 | _RET="${lowerdir}" 43 | else 44 | fail "Unable to find the overlay lowerdir" 45 | fi 46 | else 47 | fail "Unable to find an overlay filesystem" 48 | fi 49 | } 50 | 51 | clean_exit() { 52 | local mounts="$1" rc=0 d="" lowerdir="" mp="" 53 | for d in ${mounts}; do 54 | if mountpoint ${d} >/dev/null; then 55 | umount ${d} || rc=1 56 | fi 57 | done 58 | for mp in $REMOUNTS; do 59 | mount -o remount,ro "${mp}" || 60 | error "Note that [${mp}] is still mounted read/write" 61 | done 62 | [ "$2" = "return" ] && return ${rc} || exit ${rc} 63 | } 64 | 65 | # Try to find the overlay filesystem 66 | get_lowerdir 67 | lowerdir=${_RET} 68 | 69 | recurse_mps=$(awk '$1 ~ /^\/dev\// && $2 ~ starts { print $2 }' \ 70 | starts="^$lowerdir/" /proc/mounts) 71 | 72 | mounts= 73 | for d in proc dev run sys; do 74 | if ! mountpoint "${lowerdir}/${d}" >/dev/null; then 75 | mount -o bind "/${d}" "${lowerdir}/${d}" || fail "Unable to bind /${d}" 76 | mounts="$mounts $lowerdir/$d" 77 | trap "clean_exit \"${mounts}\" || true" EXIT HUP INT QUIT TERM 78 | fi 79 | done 80 | 81 | # Remount with read/write 82 | for mp in "$lowerdir" $recurse_mps; do 83 | mount -o remount,rw "${mp}" && 84 | REMOUNTS="$mp $REMOUNTS" || 85 | fail "Unable to remount [$mp] writable" 86 | done 87 | info "Chrooting into [${lowerdir}]" 88 | chroot ${lowerdir} "$@" 89 | 90 | # Clean up mounts on exit 91 | clean_exit "${mounts}" "return" 92 | trap "" EXIT HUP INT QUIT TERM 93 | 94 | # vi: ts=4 noexpandtab 95 | -------------------------------------------------------------------------------- /overlayroot/mount-overlayroot.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # Copyright, 2012 Dustin Kirkland 3 | # Copyright, 2012 Scott Moser 4 | # Copyright, 2012 Axel Heider 5 | # 2016 George Fleury 6 | # 7 | # Based on scripts from 8 | # Sebastian P. 9 | # Nicholas A. Schembri State College PA USA 10 | # Axel Heider 11 | # Dustin Kirkland 12 | # Scott Moser 13 | # 14 | # 15 | # This program is free software: you can redistribute it and/or modify 16 | # it under the terms of the GNU General Public License as published by 17 | # the Free Software Foundation, either version 3 of the License, or 18 | # (at your option) any later version. 19 | # 20 | # This program is distributed in the hope that it will be useful, 21 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 22 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 23 | # GNU General Public License for more details. 24 | # 25 | # You should have received a copy of the GNU General Public License 26 | # along with this program. If not, see 27 | # . 28 | 29 | . /lib/dracut-lib.sh 30 | 31 | 32 | clean_path() { 33 | # remove '//' in a path. 34 | local p="$1" tmp="" 35 | while [ "${p#*//}" != "$p" ]; do 36 | tmp=${p#*//} 37 | p="${p%%//*}/${tmp}" 38 | done 39 | _RET="$p" 40 | } 41 | 42 | overlayrootify_fstab() { 43 | # overlayrootify_fstab(input, root_ro, root_rw, dir_prefix, recurse, swap) 44 | # read input fstab file, write an overlayroot version to stdout 45 | # also returns (_RET) a list of directories that will need to be made 46 | local input="$1" root_ro="${2:-/run/sysroot}" 47 | local root_rw="${3:-/run/root-rw}" dir_prefix="${4:-/root}" 48 | local recurse=${5:-1} swap=${6:-0} fstype=${7:-overlay} 49 | local hash="#" oline="" ospec="" upper="" dirs="" copy_opts="" 50 | local spec file vfstype opts pass freq line ro_line 51 | local workdir="" use_orig="" relfile="" needs_workdir=true 52 | 53 | [ -f "$input" ] || return 1 54 | 55 | while read spec file vfstype opts pass freq; do 56 | line="$spec $file $vfstype $opts $pass $freq" 57 | case ",$opts," in 58 | *,ro,*) ro_opts="$opts";; 59 | *) ro_opts="ro,${opts}";; 60 | esac 61 | ro_line="$spec ${root_ro}$file $vfstype ${ro_opts},nofail $pass 0" 62 | 63 | use_orig="" 64 | if [ "${spec#${hash}}" != "$spec" ]; then 65 | use_orig="comment" 66 | elif [ -z "$freq" ]; then 67 | use_orig="malformed-line" 68 | else 69 | case "$vfstype" in 70 | vfat|fat) use_orig="fs-unsupported";; 71 | proc|sysfs|tmpfs|dev|devpts|udev) use_orig="fs-virtual";; 72 | esac 73 | fi 74 | 75 | rel_file=${file#/} 76 | if [ -n "$use_orig" ]; then 77 | if [ "$use_orig" != "comment" ]; then 78 | echo "$line # $MYTAG:$use_orig" 79 | else 80 | echo "$line" 81 | fi 82 | elif [ "$vfstype" = "swap" ]; then 83 | if [ "$swap" = "0" ]; then 84 | # comment out swap lines 85 | echo "#$MYTAG:swap=${swap}#${line}" 86 | elif [ "${spec#/}" != "${spec}" ] && 87 | [ "${spec#/dev/}" = "${spec}" ]; then 88 | # comment out swap files (spec starts with / and not in /dev) 89 | echo "#$MYTAG:swapfile#${line}" 90 | else 91 | echo "${line}" 92 | fi 93 | elif [ "$file" = "/" ]; then 94 | #ospec="${root_ro}${file}" 95 | ospec="${fstype}" 96 | copy_opts="" 97 | [ "${opts#*nobootwait*}" != "${opts}" ] && 98 | copy_opts=",nobootwait" 99 | clean_path "${root_rw}/${dir_prefix}${file}" 100 | upper="$_RET" 101 | 102 | oline="${ospec} ${file} $fstype " 103 | clean_path "${root_ro}${file}" 104 | oline="${oline}lowerdir=$_RET" 105 | oline="${oline},upperdir=${upper}${copy_opts}" 106 | if [ "$fstype" = "overlayfs" -o "$fstype" = "overlay" ] && 107 | ${needs_workdir}; then 108 | workdir="${root_rw}/workdir" 109 | oline="${oline},workdir=$workdir" 110 | dirs="${dirs} $workdir" 111 | fi 112 | oline="${oline} $pass $freq" 113 | 114 | if [ "$recurse" != "0" ]; then 115 | echo "$ro_line" 116 | echo "$oline" 117 | dirs="${dirs} ${upper}" 118 | else 119 | echo "$line" 120 | [ "$file" = "/" ] && dirs="${dirs} ${upper}" 121 | fi 122 | else 123 | echo "${line}" 124 | fi 125 | done < "$input" 126 | _RET=${dirs# } 127 | } 128 | 129 | 130 | mkdir -p /run/sysroot || echo Fail create ro dir 131 | mkdir -p /run/root-rw || echo Fail create rw dir 132 | 133 | [ -f $NEWROOT/etc/overlayroot.conf ] && . $NEWROOT/etc/overlayroot.conf 134 | 135 | # Silent fallback if no device specified on conf file 136 | [ -n "$overlayrootdevice" ] || return 1 137 | [ ! -b $overlayrootdevice ] && (echo Overlayroot device not found. Falling back to root device. && return 1) 138 | [ $? != 0 ] || return 139 | 140 | # Mount and/or format the ephemeral device 141 | mount $overlayrootdevice /run/root-rw || ((mkfs.xfs -f $overlayrootdevice && mount $overlayrootdevice /run/root-rw) || (echo Fail mount $overlayrootdevice. Falling back to root device. && return 1)) 142 | [ $? = 0 ] || return 143 | 144 | # Create working directories to the RW filesystem 145 | mkdir -p /run/root-rw/root 146 | mkdir -p /run/root-rw/workdir 147 | 148 | mount --make-private $NEWROOT 2>> /run/.overlayroot.log 149 | mount --make-private / 2>> /run/.overlayroot.log 150 | mount --make-private /run 2>> /run/.overlayroot.log 151 | # Move the original root filesystem mount point to the new directory 152 | mount --move $NEWROOT /run/sysroot 2>> /run/.overlayroot.log || (echo Failed to move $NEWROOT to /run/sysroot. && return 1) 153 | [ $? = 0 ] || return 154 | 155 | # Try to mount overlay, if fail fallback to original root filesystem. 156 | mount -t overlay -o lowerdir=/run/sysroot,upperdir=/run/root-rw/root,workdir=/run/root-rw/workdir overlay $NEWROOT || (mount --move /run/sysroot $NEWROOT && echo Failed to mount overlay root filesystem. Falling back to root device. && return 1) 157 | [ $? = 0 ] || return 158 | 159 | mkdir -p /sysroot/run/sysroot 160 | mkdir -p /sysroot/run/root-rw 161 | 162 | mount --move /run/sysroot /sysroot/run/sysroot 163 | mount --move /run/root-rw /sysroot/run/root-rw 164 | 165 | overlayrootify_fstab /sysroot/run/sysroot/etc/fstab > /sysroot/etc/fstab 166 | 167 | --------------------------------------------------------------------------------