Překrytí systémového disku - overlay filesystem

Z DCEwiki
Skočit na navigaci Skočit na vyhledávání
Koncept transparentního překrytí systémového disku virtuálním diskem vytvořeným v lokální paměti, využíváme u bezdiskového linuxu od r. 2006.

Původně se používal unionfs, jehož vývoj započal r. 2004. Byla to vůbec první linuxová implementace této technologie, která se dala reálně používat. S přechodem na jádro řady 2.6 však začal vývoj unionfs zaostávat, proto byl upřednostěn progresivnější aufs, který podporoval i novější jádra řady 3.x a měl – stejně jako linuxový kernel – zdrojový kód udržovaný v git repozitáři a verzovaný vůči aktuálním verzím jádra.

Bohužel, klíčový problém aufs byl (a je), že není součástí hlavní vývojové větve linuxového jádra, přes to, že se o začlenění jeho vývojář Junjiro R. Okajima řadu let snažil. Vývojářům kernelu se nelíbilo, že aufs sjednocení adresářů neprovádí v rámci VFS (virtuálního souborového systému), ale mimo něj – stejně jako původní unionfs. Proto nakonec upřednostnili overlay, který provádí sjednocení adresářů na úrovni VFS. [1]

aufs
Modul aufs sice nebyl součástí hlavní vývojové větve jádra, ale až k jádru verze 3.16 byl standardní součástí distribučního jádra Debianu[2].
overlay
Původně vyvíjený jaderný modul s názvem overlayfs, se stal součástí hlavní vývojové větve jádra od verze 3.18-rc2 pod názvem overlay[3].
unionfs-fuse
Overlay lze také řešit přesunion-fuse. Ten soubory honí v uživatelském prostoru, což představuje zhruba 20% ztrátu výpočetního výkonu procesoru. Což je pro účely disklessu akceptovatelné.
mcachefs
Umožňuje použít lokální blokové zařízení jako keš nad připojeným NFS adresáře. V podstatě se to chová také jako overlay, ovšem s tím rozdílem, že vytahuje při čtení soubory z podkladové vrstvy nahoru, což overlay nedělá. S výhodou lze toho využít u dynamického ramdisku


Linuxový systém nad NFS

Poznámka Linuxový systém nad NFS lze provozovat pouze za předpokladu, že jeho jádro obsahuje modul aufs. U Debianu byl tento modul donedávna součástí distribučního jádra, ale od jádra verze 3.19 se patchování jádra nevyhnete. Jak vytvořit vlastní jádro s podporou aufs viz výše.

Princip je následující:

  1. Nejprve se spustí linuxové jádro, které si do paměti rozbalí ramdisk
  2. V ramdisku musí být k dispozici modul aufs a utility pro připojení adresáře sdíleného přes NFS
  3. V paměti se vytvoří další tmpfs prostor, připojený na přípojný bod, kterým se pak překryje namountovaný adresář se systémem, sdíleným přes NFS
  4. Další zavádění již probíhá jako obvykle. S tím, že veškeré změny se zapisují do onoho vyhrazeného prostoru v paměti

Součástí ramdisku tak musí být skripty, které tyto operace zrealizují ještě před spuštěním init procesu.

Dynamický ramdisk

S rozšířením disklessu na TurtleBoty jsem od září 2019 implementoval novinku – dynamický ramdisk. Ten umožňuje modifikovat zavádění disklessového systému bez toho, že by bylo nutné v PXE menu psát na příkazové řádce jádra další potřebné parametry.

Dynamický ramdisk je založen na myšlence, že ramdisk obsahuje pouze výchozí skripty, nezbytné pro nahození sítě a stažení konfiguračního souboru podle identifikačních údajů (jména skupiny, IP adresy, hostname či výchozí brány) z DHCP. Ten obsahuje další potřebné informace k sestavení sendviče a spuštění disklessového systému.


Dynamický ramdisk vyžaduje upravený skript nfs a dva klíčové skripty: enable_wireless a nfsroot

nfs
Originální verze tohoto skriptu, která je součástí instalačního balíku initramfs-tools-core, se instaluje do adresáře /usr/share/initramfs-tools/scripts – právě odtud se bere, když se přes update-initramfs sestavuje ramdisk. Počítá s tím, že je na příkazové řádce jádra předán parametr nfsroot ve kterém je IP adresa NFS serveru a cesta ke sdílenému adresáři, kde je uložen kořenový adresář zaváděného systému + další parametry připojení.
Pro dynamický ramdisk ale tato proměnná není nezbytně nutná

U dynamického ramdisku, se ale nepo

enable_wireless
nfsroot

Skript pro překrytí systémového disku

O překrytí systémového disku se stará univerzální skript root_overlay, který musí být - stejně jako modul pro sjednocení souborového systému - součástí ramdisku. Skript tento modul zavede a připojí virtuální disk, umístěný v paměti, který překryje systémový disk připojený přes NFS.

Protože se může spustit až poté, co je systémový disk sdílený přes NFS připojen, je uložen v podadresáři /scripts/nfs-bottom.

Upozornění Aby se skripty skutečně spustily, musí být v ramdisku nastaveny jako spustitelné! Pokud tomu tak není, tak se disk nepřekryje a systém najede jako zapisovatelný!

root_overlay

Poznámka
#!/bin/sh

PREREQ=""
prereqs()
{
     echo "$PREREQ"
}

case $1 in
prereqs)
     prereqs
     exit 0
     ;;
esac

# Kód pro vypnutí překrytí předáním volby overlay=off jádru
[ "${overlay}" == "off" ] && exit 0 || [ -e /off ] && exit 0

# Kód, co se stará o zavedení modulu, který umožní překrytí souborového systému...
insmodule()
{
    if ! grep -q $1 /proc/filesystems ; then
        modprobe $1 >/dev/null 2>/dev/null
        if ! grep -q $1 /proc/filesystems ; then
            if [ -d "${rootmnt}/lib/modules/$(uname -r)/extra/$1" ] ; then
                if [ ! "$(insmod ${rootmnt}/lib/modules/$(uname -r)/extra/$1/$1.ko)" ] ; then
                    echo $1
                fi
            fi
        else
            echo $1
        fi
    else
        echo $1
    fi
}

for i in overlayfs aufs unionfs
do
    OVERLAY=$(insmodule $i)
    [ "$OVERLAY" == "$i" ] && break
done

# Kód, který připraví přípojný bod a namountuje virtuální disk, kterým se překryje systémový  disk
# namountovaný přes NFS...
mkdir /tmp/unirw
mount -n -t tmpfs none /tmp/unirw

case "$OVERLAY" in
    overlayfs) echo "Remounting root as overlayfs ..."
        mount -n -t overlayfs -o upperdir=/tmp/unirw,lowerdir=${rootmnt} overlayfs ${rootmnt}
        ;;
    aufs) echo "Remounting root as aufs ..."
        mount -n -t aufs -o dirs=/tmp/unirw=rw:${rootmnt}=nfsro unionfs ${rootmnt}
        ;;
    unionfs) echo "Remounting root as unionfs ..."
        mount -n -t unionfs -o dirs=/tmp/unirw=rw:${rootmnt}=ro unionfs ${rootmnt}
        ;;
    *) panic "Actual initrd.img has not a module for overlay filesystem"
        ;;
esac

# Mají-li být data co se ukládají na virtuální disk - kterým je systémový disk překrytý - dostupná,
# pak je třeba provést přesun namountovaného virtuálního disku do adresářové struktury sjednoceného
# souborového systému. V opačném případě lze tento kód vynechat.
mkdir -p ${rootmnt}/overlay/unirw
mount -n -o move /tmp/unirw ${rootmnt}/overlay/unirw
chmod 755 ${rootmnt} # Disable rw access for non-root users

# Vytvoření adresářů, na které se mountují další virtuální souborové systémy.
mkdir -p ${rootmnt}/dev
mkdir -p ${rootmnt}/proc
mkdir -p ${rootmnt}/sys
mkdir -p ${rootmnt}/tmp
mkdir -p ${rootmnt}/run
mkdir -p ${rootmnt}/var/lock

Nejjednodušším způsobem jak dostat tento skript do ramdisku je:

  1. Nainstalovat balíček initramfs-tools,
  2. Nakopírovat tento skript do adresáře /etc/initramfs-tools/scripts/nfs-bottom
  3. A následně aktualizovat ramdisk - viz odstavec Práce v prostředí ramdisku#Korektní sestavení ramdisku u Debianu v předchozí kapitole
Upozornění V případě že je systém zaváděný z ramdisku který je mimo virtuální stroj, je třeba nově sestaveným ramdiskem nahradit ten ramdisk který se při zavádění skutečně používá.

Pokud bude všechno v pořádku a linuxovému jádru nebude předána volba overlay=off najede stroj s překrytým souborovým systémem.

Zda-li overlay je či není aplikovaný lze zjistit kupř. z výpisu příkazu mount. Pokud systémový disk není překrytý, tak ho normálně vidíme namountovaný na kořen / souborového systému. V opačném případě se v tomto výpisu neobjeví.

Kam je připojený ale můžeme vidět, když si necháme vypsat obsah souboru /proc/mounts. Z něm by se měl objevit systémový disk připojený na /root.

A v adresáři /overlay/unirw by také měly být vidět veškeré nově vytvořené a změněné soubory.

Chceme-li překrytí vypnout, tak buď můžeme rovnou předat volbu overlay=off

vmlinuz ... overlay=off ...

Druhou variantou je operativní vypnutí překrytí, máme-li zaváděcí proces přerušený parametrem break. V takovém případě stačí v kořeni ramdisku vytvořit soubor s názvem off a příkazem exit pak pokračovat v zavádění.

vmlinuz ... break ...
...
(initramfs) touch off
(initramfs) exit
...
Upozornění Pokud přepínáme mezi překrytím a RW přístupem, je třeba aby byl pro RW přístup vyexportován také adresář virtuálního stroje na vzdáleném NFS serveru!

Skript po nastavení hostname

Tento skript je určen především pro naše bezdiskové stroje v laboratořích.

Na základě přidělené IPv4 adresy nastavuje aktuální hostname bezdiskového stroje a generuje soubor /etc/hosts, ve kterém ukazuje záznam nfsroot na aktuální NFS server.

Upozornění Obsah následujícího skriptu je specifický pro potřeby sítě naší katedry. Pokud jej hodláte využít, musíte upravit část ve které se nastavuje obsah proměnné HOSTNAME na základě IPv4 adresy, kterou přiřazuje DHCP server.

nfsrootsetup

Poznámka
#!/bin/sh
# Setup hostnames according to IP address and create /etc/hosts

PREREQ="root_overlay"
prereqs()
{
     echo "$PREREQ"
}

case $1 in
prereqs)
     prereqs
     exit 0
     ;;
esac

echo "Setting hostname..."
# Bring in the main config
. /conf/initramfs.conf
# source relevant ipconfig output
. /run/net-*.conf

if [ -z "${HOSTNAME}" ]; then # No hostname sent by DHCP
	case "${IPV4ADDR}" in
		147.32.86.*)	HOSTNAME="dcezam-${IPV4ADDR##*.}";;
		147.32.87.*)	HOSTNAME="dcestud-${IPV4ADDR##*.}";;
		192.168.136.*)	HOSTNAME="k09-${IPV4ADDR##*.}";;
		192.168.202.*)	HOSTNAME="k2-${IPV4ADDR##*.}";;
		*)		HOSTNAME="dcelinux-${IPV4ADDR}";;
	esac
fi

[ -z "${DNSDOMAIN}" ] && DNSDOMAIN=local

rm -f ${rootmnt}/etc/hostname
echo ${HOSTNAME} > ${rootmnt}/etc/hostname

# Create /etc/hosts with correct IP for the server
rm -f ${rootmnt}/etc/hosts
cat <<EOF > ${rootmnt}/etc/hosts
127.0.0.1	localhost
${IPV4ADDR}	${HOSTNAME}.${DNSDOMAIN} ${HOSTNAME}
${nfsroot%%:*}	nfsroot
EOF

exit 0

Spouštěcí skripty a operace v systému bezdiskového stroje

Připojení lokálního swapovacího oddílu

Pokud je systémový adresář připojený přes NFS překrytý virtuálním diskem vytvořeným v paměti, je žádoucí aby klientská pracovní stanice (nebo virtuál) měla na lokálním blokovém zařízení k dispozici swapovací oddíl, který umožní - v případě že začne místo v paměti docházet - odsypat data z fyzické paměti na fyzický disk.

Není-li swapovací oddíl k dispozici, tak to sice nevede ke zhroucení systému, ale ten se pak začne chovat stejně jako když dojde místo na disku - podivně. Init skript findswap se při svém spuštění pokusí tento swapovací oddíl vyhledat a připojit.

Poznámka Od jádra ... nabízí NFS server také možnost swapování přes NFS

findswap

Poznámka
#!/bin/sh
### BEGIN INIT INFO
# Provides:          findswap
# Required-Start:    mountall
# Required-Stop: 
# Should-Start:
# Should-Stop:
# Default-Start:     S
# Default-Stop:
# Short-Description: Find all unused swap partitions to enable swapping on them
# Description:
### END INIT INFO

do_start() {
  SWAPCANDIDATES="$(cat /proc/partitions | sed -n -e 's/^.* \([hs]d[a-z][0-9]\)$/\1/p' -e 's/^.* \(xvd[a-z][0-9]\)$/\1/p')"
  for i in $SWAPCANDIDATES ; do
    if [ "$( blkid -s TYPE /dev/$i -o value )" = "swap" ] ; then
      grep -q "/dev/$i" /proc/swaps
      if [ $? -ne 0 ] ; then
        echo "Adding swap device /dev/$i."
        swapon "/dev/$i"
      fi
    fi
  done
}

case "$1" in
  start|"")
	do_start
	;;
  restart|reload|force-reload)
	echo "Error: argument '$1' not supported" >&2
	exit 3
	;;
  stop)
	# No-op
	;;
  *)
	echo "Usage: $0 [start|stop]" >&2
	exit 3
	;;
esac

Init skript pro spouštění dalších operací

Protože v našem prostředí bezdiskového linuxu využíváme i software, který není součástí distribuce a vyžaduje určitá specifická nastavení, je v adresáři /etc/init.d umístěn skript,k335linux, který v okamžiku kdy je namountováno NFS spustí obsah skriptu v /etc/default/k335linux.

Upozornění Obsah následujícího skriptu je specifický pro naši konfiguraci. Pokud jej hodláte využít, musíte jeho obsah upravit.

k335linux

Poznámka
#! /bin/sh
### BEGIN INIT INFO
# Provides:          k335linux
# Required-Start:    $remote_fs
# Required-Stop: 
# Should-Start:
# Should-Stop:
# Default-Start:     S
# Default-Stop:
# Short-Description: Creates symlink in /opt
# Description:
### END INIT INFO

#
# k335linux	K335 diskless linux setup helpers.
#
#		Base on skeleton by Miquel van Smoorenburg <miquels@cistron.nl>.
#		Modified for Debian 
#		by Ian Murdock <imurdock@gnu.ai.mit.edu>.
#
# Version:	@(#)k335linux 1.0  12-Jan-2011  pisa@cmp.felk.cvut.cz
#

PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
NAME=k335linux
DESC="station configuration"

# Include k335linux defaults if available
if [ -f /etc/default/k335linux ] ; then
	. /etc/default/k335linux
fi

set -e

case "$1" in
  start)
	echo -n "Starting $DESC: "
        #echo -n "xconf"
        #/usr/local/bin/xconf > /dev/null
	echo "."
	;;
  stop)
# 	echo -n "Stopping $DESC: "
# 	echo "."
	;;
  force-reload)
	$0 restart \
	|| exit 0
	;;
  restart)
    echo -n "Restarting $DESC: "
	start-stop-daemon --stop --quiet --pidfile \
		/var/run/$NAME.pid --exec $DAEMON
	sleep 1
	start-stop-daemon --start --quiet --pidfile \
		/var/run/$NAME.pid --exec $DAEMON -- $DAEMON_OPTS
	;;
  *)
	N=/etc/init.d/$NAME
	echo "Usage: $N {start|stop|restart|force-reload}" >&2
	exit 1
	;;
esac

exit 0

Připojení uživatelských adresářů

Záznam v souboru /etc/fstab, který využívá pro připojení vzdálených adresářů souboru /etc/hosts, vygenerovaného skriptem v ramdisku

ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no nfshomecreator@nfsserver testuser 1234 100 /nfs/diskless-home

Autorizace uživatelů

Toto téma řeší samostatný manuál - Autorizace uživatelů v linuxu

Použití

V rámci linuxového bezdiskového stroje nad NFS lze provádět veškeré operace jako kdyby šlo o stroj s normálním blokový, zařízení. Překrytí systémového disku však má z hlediska použití v laboratořích a učebnách jednu obrovskou výhodu - veškeré změny jsou uloženy pouze v rámci virtuálního disku, kterým je překrytý výchozí systém a po restartu se zahodí - s výjimkou souborů uložených v uživatelských adresářích.

Pokud je při zavádění přemountován přípojný bod /overlay/unirw z prostředí ramdisku do systému, je jeho obsah dostupný v rámci sjednoceného souborového systému. Z něj pak lze vytáhnout změny a soubory vytvořené v rámci disklessového systému.

Využití překrytí systémového disku při přípravě binárních distribučních balíků

Chceme-li využívat překrytí při testovacích instalacích a tvorbě binárních balíčků, nemusíme patchovat a kompilovat vlastní linuxový kernel, ale můžeme použít rovnou modul overlay který je dnes již standardní součástí distribučního jádra.

mount -t overlay overlay -o lowerdir=/nejnizsi_vrstva,upperdir=/vrstva_kam_se_zapisuje,workdir=/work /sloucene_vrstvy
lowerdir
Adresář, který se má překrýt transparentní vrstvou.
upperdir
Adresář, do kterého se zapisuje obsah transparentní vrstvy která je zcela nahoře. Proto musí být do něj možné zapisovat.
workdir
Prázdný adresář, který se však musí vyskytovat v rámci stejného souborového systému, jako upperdir

Posledním parametrem příkazu je přípojný bod do kterého se sloučené vrstvy připojí.

  • Součástí podkladové vrstvy lowerdir může být i několik transparentních vrstev nad sebou. Adresáře jsou od sebe odděleny dvojtečkou a postupně se na sebe vrství zleva doprava. Tj. adresář první v pořadí je nejníž položený.
  • Adresáře upperdir a workdir lze vynechat, ovšem v takovém případě se sloučené vrstvy připojí na přípojný bod pouze v režimu pro čtení

Praktický příklad použití

Dejme tomu, že chcete vyzkoušet jaké změny v systému nastanou, pokud budete chtít nainstalovat aplikaci kompilovanou ze zdrojových kódů.

Příprava a kompilace

Kompilace si může vynutit instalaci nových balíčků, které ovšem jinak vůbec nepotřebujete. Proto si nejprve připravíte adresář /root/pivot pro chroot, ve kterém budete moci provést konfiguraci a instalaci dalších potřebných balíčků, aniž by tím došlo k nabourání stávajícího systému.

Poznámka
root@stroj:~# mount -t overlay overlay -o lowerdir=/,upperdir=/root/prepare,workdir=/root/work /root/pivot
root@stroj:~# mount /dev /root/pivot/dev -o bind
root@stroj:~# mount /proc /root/pivot/proc -o bind
root@stroj:~# mount /sys /root/pivot/sys -o bind
root@stroj:~# chroot /root/pivot

Posledním příkazem chroot jste se přepnuli do systému, kde lze provádět konfiguraci zdrojového kódu a instalaci potřebných balíčků. Ve stejném prostředí můžete (ale nemusíte) zdrojové kódy také zkompilovat.

Jelikož nevíte co se kam bude instalovat, je lepší před vlastní instalaci vyskočit ven z chrootu (příkazem exit) a sestavit overlay znovu. Ovšem tentokrát již s využitím obsahu adresáře /root/prepare, ve kterém se nalézá vše co bylo nainstalováno v předchozím kroku.

Poznámka
root@stroj:~# exit
root@stroj:~# umount /root/pivot/sys
root@stroj:~# umount /root/pivot/dev
root@stroj:~# umount /root/pivot/proc
root@stroj:~# umount /root/pivot

Instalace

Do parametru lowerdir přidáme nad systémový adresář (/) jako transparentní vrstvu adresář /root/prepare do kterého se ukládaly změny v průběhu přechozího kroku. A pro uložení změn při instalaci vyžijeme nový prázdný adresář /root/binary:

Poznámka
root@stroj:~# mount -t overlay overlay -o lowerdir=/:/root/prepare,upperdir=/root/binary,workdir=/root/work /root/pivot
root@stroj:~# mount /dev /root/pivot/dev -o bind
root@stroj:~# mount /proc /root/pivot/proc -o bind
root@stroj:~# mount /sys /root/pivot/sys -o bind
root@stroj:~# chroot /root/pivot

A můžeme bez obav spustit instalaci. Z obsahu adresáře /root/binary můžeme sestavit binární .deb balíček, a obsah adresáře /root/prepare nám zase pro změnu pomůže při detekci závislostí.

Poznámka Jak sestavit binární .deb balíček je popsáno v manuálu k Pacemakeru
  1. Podrobnější informace o problematice sjednocujících souborových systémů nabízí minisérie přeložených článků na http://www.abclinuxu.cz
  2. Od chvíle, kdy se stal overlayfs součástí hlavní vývojové větve jádra, přestali správci distribučního jádra Debianu aufs integrovat. U bezdiskového linuxu postaveného nad aufs, který běží nad NFS tak nezbývá než patchovat jádro, aby obsahovalo modul aufs.
  3. Dlouho se zdálo, že se po začlenění overlayfs situace změní k lepšímu, protože nebude nutné pro jiné distribuce, než Debian patchovat jádro. Jenže začlenění se neustále odsouvalo. Původně bylo ohlášeno již pro jádra řady 3.10, ale nakonec k tomu došlo až u jader řady 3.18 Po začlenění byl název jaderného modulu byl z původního overlayfs změněn na overlay, ovšem mnohem závažnější problém nastal v tom, že změny v jeho kódu znemožnily použít jako podkladový souborový systém adresář sdílený přes NFS. Tento nedostatek byl odstraněn až od verze …