BlogBlog ÜbersichtjailscriptportsoptFreeBSDLinksThermoskanne

FreeBSD Service Jails mit unionfs erstellen

Mit Hilfe von Service Jails lassen sich gemeinsame Elemente einer Jail mit mehreren Jails teilen. Damit reduziert sich der Administrationsaufwand, da man zum Beispiel Sicherheitspatches des Basissystemes nur noch in der gemeinsamen Basis einspielen muss und nicht mehr in jeder Jail.

Inspiriert durch folgende Seite (http://simon.nitro.dk/service-jails.html) habe ich nun Service Jails mit Hilfe von unionfs erstellt.

Mit unionfs lässt sich ein Dateisystem über ein bestehendes mounten. Wird eine Datei aus dem unterliegenden System nicht durch eine gleichnamige Datei aus dem oberliegenden Dateisystem überdeckt, so ist diese auch im oberliegenden System sichtbar. Änderungen fliessen allerdings nur in das obere System ein.

Da die aktuelle unionfs-Implementation von FreeBSD recht fehlerhaft sein soll, verwenden wir gleich die neue unionfs-Implementation. Damit diese verwendet werden kann, müssen die aktuellen FreeBSD-Quelldateien der verwendeten FreeBSD Version in /usr/src vorhanden sein. Danach kann der Patch heruntergeladen, kompiliert und die neue Implemetation installiert werden:

# cd /usr/src
# fetch http://people.freebsd.org/~daichi/unionfs/unionfs6-p16.diff
# patch -p3 < unionfs6-p16.diff
# cp /usr/src/sys/fs/unionfs/union.h /usr/include/fs/unionfs/
# cd /usr/src/sbin/mount_unionfs/
# make obj depend && make && make install
# make clean
# cd /usr/src
# make buildkernel KERNCONF=<KERNEL-KONFIGURATION>
# make installkernel KERNCONF=<KERNEL-KONFIGURATION>
# shutdown -r now

Dieses Vorgehen läd den Patch 16 für FreeBSD 6 herunter. Man sollte sich vorher allerdings vergewissern, dass man das aktuelle Patchset für die zu verwendende FreeBSD-Version herunterläd.

Danach kann die gemeinsame Basis der Jails erstellt werden. Diese wird in einer 1GB grossen Datei erstellt, welche wiederum als Memory Disk gemountet wird. Der Portbaum wird aus dem Hostsystem in die Jailbasis verschoben und mit einem Symlink dem Hostsystem wieder zur Verfügung gestellt.

# mkdir /usr/jails/
# truncate -s 1G /usr/jails/base
# mdconfig -a -t vnode -f /usr/jails/base -u 0
# bsdlabel -w md0 auto
# newfs md0a
# mkdir -p /mnt/jails
# mkdir -p /mnt/jails/base
# mount /dev/md0a /mnt/jails/base/
# cd /usr/src/ && make installworld DESTDIR=/mnt/jails/base
# cd /usr/src/etc && make distribution DESTDIR=/mnt/jails/base

# mv /usr/ports /mnt/jails/base/usr/ports
# ln -s /mnt/jails/base/usr/ports /usr/ports

# /sbin/mount_unionfs -c transparent -b /usr/ports /mnt/jails/base/usr/ports
# touch /mnt/jails/base/etc/fstab

Nun kann die gemeinsame Basis nach eigenen Wünschen konfiguriert werden.

Danach kann eine Jail folgendermassen erzeugt werden:

# truncate -s <Grösse> /usr/jails/<Name>
# mdconfig -a -t vnode -f /usr/jails/<Name> -u <Nr>
# bsdlabel -w md<Nr> auto
# newfs md<Nr>a
# mkdir -p /mnt/jails/<Name>
# mount /dev/md<Nr>a /mnt/jails/<Name>

# mount_unionfs -c transparent -b /mnt/jails/base /mnt/jails/<Name>

# mount_devfs devfs /mnt/jails/<Name>/dev
# cd /mnt/jails/<Name>
# ln -sf /dev/null kernel

<Grösse> ist durch die Grösse der Datei zu ersetzen, in der man die Jail erzeugen will. Für zum Beispiel 2 GB gibt man hier 2G an. <Name> ist natürlich durch den Jailnamen zu ersetzen. Bei der ersten Jail ersetzt man <Nr> durch 1, bei der zweiten durch 2 usw.

Nun wird die Jail gestartet und kann konfiguriert werden:

# ifconfig <Interface> alias <IP-Adresse>/32
# jail /mnt/jails/<Name> <Name> <IP> /bin/sh

So können nun mehrere Jails erzeugt werden, die das gleiche Basissystem verwenden.

Da diese Variante für die Jails Dateien verwendet, die als RAM-Disk gemountet werden, müssen diese auch bei einem Neustart zuerst geladen werden, damit man nachher die Jails ganz normal über die rc.conf starten kann. Dazu wird unter /etc/rc.d/jails eine Datei mit folgendem Inhalt erstellt:

#!/bin/sh
#
# ----------------------------------------------------------------------------
# "THE BEER-WARE LICENSE" (Revision 42):
# <beat@chruetertee.ch> wrote this file. As long as you retain this notice you
# can do whatever you want with this stuff. If we meet some day, and you think
# this stuff is worth it, you can buy me a beer in return Beat Gätzi
# ----------------------------------------------------------------------------
#

# PROVIDE: jails
# REQUIRE: root mountcritlocal
# BEFORE: jail
# KEYWORD: shutdown

. /etc/rc.subr

name="jails"
rcvar=`set_rcvar`
start_cmd="jails_start"
stop_cmd="jails_stop"

jails_start()
{
echo 'Setting up jails environment'
/sbin/mdconfig -a -t vnode -f /usr/jails/base -u 0
/sbin/fsck -y /dev/md0a
/sbin/mount /dev/md0a /mnt/jails/base/
j=1
for i in ${jails_list}
do
/sbin/mdconfig -a -t vnode -f /usr/jails/${i} -u ${j}
/sbin/fsck -y /dev/md${j}a
/sbin/mount /dev/md${j}a /mnt/jails/${i}
/sbin/mount_unionfs -c transparent -b /mnt/jails/base /mnt/jails/${i}
j=`expr $j + 1`
done
}

jails_stop()
{
j=1
for i in ${jails_list}
do
/sbin/umount /mnt/jails/${i}
/sbin/umount /mnt/jails/${i}
/sbin/mdconfig -d -u ${j}
j=`expr $j + 1`
done
/sbin/umount /mnt/jails/base/
/sbin/mdconfig -d -u 0
}

load_rc_config $name
run_rc_command "$1"

Nun müssen die verschiedenen Jails noch in der jails_list Variable in der /etc/rc.conf eingetragen werden. Wichtig ist, dass die Namen mit den Namen im Pfad der Jails übereinstimmen. Beispiel:

Zwei Jails sind unter /mnt/jails/test1.chruetertee.ch und /mnt/jails/test2.chruetertee.ch installiert, so muss das Startskript aktiviert und die jails_list Variable folgendermassen gesetzt werden:

jails_enable="YES"
jails_list="test1.chruetertee.ch test2.chruetertee.ch"

Die Jails können nun ganz normal in der rc.conf konfiguriert werden und stehen bei einem Neustart automatisch zur Verfügung.

jail_enable="YES"
jail_list="test1 test2"
jail_test1_rootdir="/mnt/jails/test1.chruetertee.ch"
jail_test1_hostname="test1.chruetertee.ch"
jail_test1_ip="<IP>"
jail_test1_exec="/bin/sh /etc/rc"
jail_test1_devfs_enable="YES"
jail_test2_rootdir="/mnt/jails/test2.chruetertee.ch"
jail_test2_hostname="test2.chruetertee.ch"
jail_test2_ip="<IP>"
jail_test2_exec="/bin/sh /etc/rc"
jail_test2_devfs_enable="YES"

Diese Service Jails wurden mit FreeBSD 6.1 getestet und funktionieren bis jetzt hier auch. Allerdings ist diese Variante auf produktiven Systemen mit Vorsicht zu geniessen, da sowohl die neue unionfs-Implementierung als auch diese Variante noch nicht ausgiebig getestet worden sind!

Arbeitet man mit FreeBSD 6.1-RELEASE und mit den Jails sollte man unbedingt folgenden Hinweis beachten, da sich in FreeBSD 6.1-RELEASE ein Fehler in der /etc/rc.d/jail befindet: ftp://ftp.freebsd.org/pub/FreeBSD/ERRATA/notices/FreeBSD-EN-06:01.jail.asc

Related Entries:
Gespeicherte Optionen nach OptionsNG konvertieren
Ports-Subversion-Repository spiegeln
sysinstall-Ersatz für neuere FreeBSD-Versionen
Alte FreeBSD-Port Patchdateien aufsplitten
FreeBSD-Portbaum auf Fehler überprüfen
 Permalink