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.

Linuxové jádro s podporou sjednocení souborového systému

Původně jsme k tomu využívali unionfs, jehož vývoj započal r. 2004. Byla to vůbec první linuxová implementace této technologie, která se začala reálně používat. S přechodem na jádro řady 2.6 však začal jeho vývoj zaostávat, proto jsme dali přednost progresivnějšímu aufs, které podporuje i nejnovější jádra řady 3.x a má zdrojový kód udržován (stejně jako kernel) v gitu.

Bohužel, problém aufs je, že není součástí hlavní vývojové větve linuxového jádra. I když se o to řadu let jeho vývojář Junjiro R. Okajima snažil. Do hlavní vývojové větve nebyl aufs, stejně jako unionfs přijat, jelikož se vývojářům kernelu nelíbilo, že se sjednocení adresářů neprovádí v rámci VFS (virtuálního souborového systému), ale mimo něj. Proto nakonec upřednostnili overlayfs, který provádí sjednocení adresářů pouze na úrovni VFS. Ten se se stal součástí hlavní vývojové větve od jádra verze 3.18-rc2. Jenže overlayfs, tak jak bylo nakonec do jádra implementováno nelze - na rozdíl od jeho původní vývojové verze - používat nad systémovým diskem nasdíleným přes NFS.

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


aufs

Ke kompilaci jádra lze použít

Stažení a patchování zdrojového kódu

Poznámka
root@nfsserver :~/git# git clone git://aufs.git.sourceforge.net/gitroot/aufs/aufs3-standalone.git
root@nfsserver :~/git# cd aufs3-standalone.git
root@nfsserver :~/git# git checkout origin/aufs3.0

Zdrojáky z http://www.kernel.org

Poznámka
root@nfsserver :~/git# cd /usr/src
root@nfsserver :/usr/src# wget https://www.kernel.org/pub/linux/kernel/v3.x/linux-3.8.1.tar.bz2
...
root@nfsserver :/usr/src# tar -xjf linux-3.8.1.tar.bz2


Poznámka
root@nfsserver :/usr/src/linux-3.8.1# cd /root/git/aufs3-standalone/
root@nfsserver :~/git/aufs3-standalone# cp -rvn ./{Documentation,fs,include} /usr/src/linux-3.8.1
	...
root@nfsserver :~/git/aufs3-standalone# cd /usr/src/linux-3.8.1
root@nfsserver :/usr/src/linux-3.8.1#
aufs3-kbuild.patch
aufs3-base.patch
aufs3-proc_map.patch
aufs3-standalone.patch
Poznámka
root@nfsserver :/usr/src/linux-3.8.1# patch -p1 < /root/git/aufs3-standalone/aufs3-kbuild.patch
...
root@nfsserver :/usr/src/linux-3.8.1# patch -p1 < /root/git/aufs3-standalone/aufs3-base.patch
...
root@nfsserver :/usr/src/linux-3.8.1# patch -p1 < /root/git/aufs3-standalone/aufs3-proc_map.patch
...
root@nfsserver :/usr/src/linux-3.8.1# patch -p1 < /root/git/aufs3-standalone/aufs3-standalone.patch
...
root@nfsserver :/usr/src/linux-3.8.1# cd ..
root@nfsserver :/usr/src# tar -cjf linux-3.8.1-aufs.tar.bz2 linux-3.8.1
Poznámka Během aplikace patche se může ve výpisu objevit ve výpisu následující informace..
...
Hunk #2 succeeded at 1432 (offset 7 lines).
...

Netřeba se znepokojovat. Je to pouhé oznámení, že rozdílový soubor našel odpovídající kus kódu o několik řádek posunutý. Většinou se to objeví, pokud byl na kód aplikován ještě jiný patch.

Sestavení jádra

Sestavení jádra lze provést standardním způsobem přímo v prostředí bezdiskového stroje.

Poznámka
root@diskless :/usr/src# ln -s linux-3.8.1 linux
root@diskless :/usr/src# cd linux
root@diskless :/usr/src/linux# gunzip -c /proc/config.gz > .config
root@diskless :/usr/src/linux# make oldconfig
...

Během této operace se u nových modulů konfigurační skript zeptá, jestli mají být součástí jádra, nebo ne. Pokud se již nějaké nastavení modulu ve stávající konfiguraci vyskytuje, tak se automaticky použije tak jak je.

Pokud chcete provést v konfiguraci jádra nějakou změnu dodatečně, tak lze přímo editovat soubor .config a následně znovu spustit výše uvedený příkaz.

Pro rozsáhlejší změny je lepší použít následující příkaz, kterým se vygeneruje ze zdrojáků jádra konfigurační menu, jehož prostřednictvím lze konfiguraci měnit.

Sestavení tohoto konfiguračního menu vyžaduje aby byl do systému doinstalován balík ...

Poznámka
root@diskless :/usr/src/linux# make menuconfig

Nakonfigurované jádro lze po sestavení rovnou zabalit do instalačního balíku

Poznámka
root@diskless :/usr/src/linux# make
...
root@diskless :/usr/src/linux# make deb-pkg
...

overlayfs

Zpočátku se zdálo, že začleněním overlayfs se situace změní k lepšímu, protože nebude nutné 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ž od jader řady 3.18

Název modulu byl z původního overlayfs změněn na overlay, ovšem mnohem závažnější je, že byly provedeny změny, které znemožňují použít jako podkladový souborový systém sdílený přes NFS.

Upozornění 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 na NFS tak není v současné době jiné cesty než patchovat jádro, aby obsahovalo modul aufs.

Linuxový systém nad NFS

Skripty v ramdisku

Součástí ramdisku jsou skripty, které realizují operace, co musí proběhnout ještě před spuštěním init procesu bezdiskového systému.

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
Použití skriptu

Nejjednodušším způsobem jak dostat skript root_overlay 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

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

Jak už bylo demonstrováno v příkladu pro sestavení jádra, v rámci bezdiskového stroje lze provádět veškeré operace jako kdyby šlo o normální blokové zařízení. Překrytí systémového disku však má z hlediska administrátora 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.

Pokud byl při zavádění přemountován z prostředí ramdisku na přípojný bod /overlay/unirw je jeho obsah dostupný v rámci sjednoceného souborového systému. Z něj lze získat vše potřebné k vytvoření a sestavení binárního balíčku pro jakýkoliv software. Ukázkovým příkladem může být kupř. sestavení instalačního balíčku pro VMware player.