GästebuchIhr Eintrag in unser Gästebuch KontaktNehmen Sie Kontakt mit den Autoren auf ArchivAlle Unixwerk- Artikel seit 2003
22. September 2007

Linux im chroot-Container

Teil I: Installation und erste Schritte

Dieser Artikel ist ein Update des im März erschienenen Artikels »Linux im chroot-Container installieren«. Ihm folgt ein zweiter Teil , der weitere Konfigurationen, wie ssh-Zugang zu Containern und einen Vorschlag zur Organisation und Verwaltung von chroot-Containern enthält.

Inhalt

  1. Einleitung
  2. Beispiele
    1. Installation von Debian Sarge
    2. Installation von Suse-Linux
    3. Installation von Slackware
    4. Installation einer Live-CD
  3. Container-Startskript
  4. X im Container starten
  5. Weiterführende Informationen

1. Einleitung

Die Auswahl an Linux-Distributionen ist nicht eben klein. Distrowatch zählt zur Zeit so an die 350 Linux-Distributionen. Die ein oder andere würde man sich schon gerne mal anschauen. Doch wer möchte deshalb schon seine Lieblingsdistribution von der Platte fegen?

In diesem Artikel geht es darum, wie man eine andere Distribution mit ein paar Tricks in einem eigenen Container innerhalb eines bestehenden Linux (im folgenden Host oder Wirt genannt) installieren kann. Als Beispiele werden Debian, Suse, Slackware und eine Live-CD in einem Container auf einem bestehenden Slackware-System installiert. Das Verfahren lässt sich leicht auf andere Distributionen übertragen.

2a. Beispiel: Installation von Debian Sarge

Debian stellt einen Sonderfall dar, da Debian selbst für die Installation weiterer Debian-Instanzen in chroot-Umgebungen bereits vorbereitet ist. Die Installation wird mit «debootstrap» durchgeführt.

Wenn Sie Zugang zu einem Debian-System haben oder der Host selbst gar ein Debian basiertes System ist, können Sie «debootstrap» mit «apt» installieren. Im folgenden Beispiel erzeugen wir auf dem Debian-System «debootstrap» als Slackware-Paket:

debian# apt-get install debootstrap
debian# cd /var/cache/apt/archives
debian# alien -t debootstrap_0.2.45-0.2_i386.deb 
debian# mv debootstrap-0.2.45.tgz debootstrap-0.2.45-i486-1.tgz

Steht Ihnen kein Debian-System zur Verfügung, besorgen Sie sich «debootstrap_0.2.45-0.2_i386.deb» z.B. von rpmseek und entpacken es mit Linux-Bordmitteln:

host# mv debootstrap_0.2.45-0.2_i386.deb /tmp
host# cd /tmp
host# ar x debootstrap_0.2.45-0.2_i386.deb
host# mv data.tar.gz debootstrap-0.2.45-i486-1.tgz
host# installpkg debootstrap-0.2.45-i486-1.tgz¹
¹Das Beispiel bezieht sich auf Slackware. Unter anderen Distributionen benutzen Sie statt «installpkg» einfach «tar»: tar xzf data.tar.gz -C /

Unser Debian Container soll unter /home/debian liegen:

host# debootstrap sarge /home/debian
             .
             . 
             .
I: Base system installed successfully.

Damit es mit dem Internet klappt, benötigen wir ein paar Dateien unter /etc vom Wirt:

host# cp /etc/resolv.conf /home/debian/etc
host# cp /etc/hosts /home/debian/etc
host# cp /etc/X11/xorg.conf /home/debian/etc/X11/xfree86.conf

Nun können wir den Container starten - den Start werden wir noch in ein Skript verpacken. Doch für den ersten Test und die nötigen Anpassungen im Container reicht erstmal ein

host# chroot /home/debian su -

Nun finden wir uns im Debian-Container wieder. Ein paar Dinge wollen wir hier anpassen:

chroot-debian# vi /etc/debian_chroot

SARGE

chroot-debian# vi /root/.bashrc

# set variable identifying the chroot you work in (used in the prompt below)
if [ -z "$debian_chroot" -a -r /etc/debian_chroot ]; then
debian_chroot=$(cat /etc/debian_chroot)
fi

# set a fancy prompt (non-color)
PS1='${debian_chroot:+($debian_chroot)}\u@\h:\w\$ '

Um die apt-Quellen zu erstellen starten wir

chroot-debian# apt-setup

Gegebenfalls wollen wir die apt-Quellen noch auf den richtigen Zweig, z.B. «sarge», zeigen lassen. Dazu passen wir /etc/apt/sources.list an:

chroot-debian# vi /etc/apt/sources.list
deb http://ftp2.de.debian.org/debian/ sarge main
deb-src http://ftp2.de.debian.org/debian/ sarge main

deb http://security.debian.org/ sarge/updates main

und aktualisieren die apt-Datenbank:

chroot-debian# apt-get update

Damit wir im Container Kommandos wie «df» und «mount» sinnvoll verwenden können, erstellen wir die Datei /etc/mtab mit folgendem Inhalt:

chroot-debian# vi /etc/mtab
/dev/root / tmpfs rw 0 0
proc /proc proc rw 0 0
sysfs /sys sysfs rw 0 0

Da beim Starten des Containers alle die Initialisierungen, die normalerweise durch den Bootprozess durchgeführt werden, übergangen werden, verankern wir im Container ein Startskript. Dieses Startskript wird beim Containerstart chroot übergeben (anstelle von su -):

chroot-debian# vi /root/cstart
#!/bin/bash

startuser=${1:-root}

# mount /dev/pts
df | grep -w devpts > /dev/null 2>&1
if [ "$?" = "0" ]; then
  mount -n devpts
else
  mount | grep -w devpts > /dev/null 2>&1
  [ "$?" = "0" ] || mount devpts
fi

# start shell
exec su - $startuser

chroot-debian# chmod +x /root/cstart

Das wär's. Nach dem nächsten Containerstart können wir wie auf einem nativen Debian-System schalten und walten.

2b. Beispiel: Installation von Suse-Linux

Lesen Sie hier, wie sich eine rpm-basierte Distribution im Container installieren lässt. Voraussetzung dafür ist, dass ihr Wirtssystem über die rpm-Bibliotheken verfügt. Benutzen Sie RedHat-basierte Distributionen oder Suse-Linux, ist diese selbstredend der Fall. Auch Slackware -obwohl selbst tgz-basiert- liefert rpm mit. Ist Ihr Wirtssystem Debian-basiert, besorgen Sie sich rpm z.B. rpmseek.

Als rpm-basierte Distribution stand mir Suse 9.3 zur Verfügung.

Zunächst legen wir ein Verzeichnis an, in das wir Suse 9.3 installieren wollen:

host# mkdir /home/suse

Die Suse 9.3-CD hängen wir unter /media/cdrom in unser Dateisystem. Im Verzeichnis /media/cdrom/suse/setup/descr finden wir eine Reihe von Dateien mit Paketvorauswahlen. Das Suse-Minimalsystem wird durch die Datei Min-9.3-83.noarch.sel beschrieben. Dies installieren wir - weitere Software lässt sich jederzeit vom laufenden Container aus nachinstallieren.

Ein Blick mit dem vi in die Datei zeigt, dass der erste Paketname in Zeile 18 und der letzte in Zeile 317 steht. ALso schneiden wir diesen Bereich aus und weisen ihn auf eine Variable zu:

host# PKGLIST=$(head -317 /media/cdrom/suse/setup/descr/Min-9.3-83.noarch.sel | tail -n +18)

Die rpm-Pakete befinden sich in den Verzeichnissen /media/cdrom/suse/i586 und /media/cdrom/suse/noarch. Von dort installieren wir die Pakete:

host# cd /media/cdrom/suse
host# for i in $PKGLIST; do ls -d {i586,noarch}/$i-[0-9]* ; done 2>/dev/null >/tmp/rpms-suse
host# rpm --root /home/suse -ihv `cat /tmp/rpms-suse` 2> /tmp/inst.err

Auch in diesem Container benötigen wir ein paar Dateien vom Wirt:

host# cp /etc/resolv.conf /home/suse/etc
host# cp /etc/hosts /home/suse/etc
host# cp /etc/X11/xorg.conf /home/suse/etc/X11

Nun können wir den Container starten - den Start werden wir noch in ein Skript verpacken. Doch für den ersten Test und die nötigen Anpassungen im Container reicht erstmal ein

host# chroot /home/suse su -

Nun finden wir uns im Suse-Container wieder. Ein paar Dinge wollen wir hier anpassen:

chroot-suse# vi /etc/mtab
/dev/root / ext3 rw,acl,user_xattr 0 0
proc /proc proc rw 0 0
udev /dev tmpfs rw 0 0
chroot-suse# vi /etc/fstab
/dev/root / ext3 rw 0 0

Da beim Starten des Containers alle die Initialisierungen, die normalerweise durch den Bootprozess durchgeführt werden, übergangen werden, verankern wir im Container ein Startskript. Dieses Startskript wird beim Containerstart chroot übergeben (anstelle von su -):

chroot-suse# vi /root/cstart
#!/bin/bash

startuser=${1:-root}

# mount /dev/pts
df | grep -w devpts > /dev/null 2>&1
if [ "$?" = "0" ]; then
  mount -n devpts
else
  mount | grep -w devpts > /dev/null 2>&1
  [ "$?" = "0" ] || mount devpts
fi

# start shell
exec su - $startuser

chroot-suse# chmod +x /root/cstart

Das wär's. Suse-Linux steht bereit.

2c. Beispiel: Installation von Slackware

Eine weitere Instanz derselben Disktribution kann zum Testen vieler Dinge nützlich sein, deshalb habe ich in einem Container noch ein weiters Mal Slackware installiert.

Zunächst legen wir ein Verzeichnis, in dem unser Container liegen soll:

host# mkdir /home/slack
Nehmen wir an, die Slackware-DVD ist unter /media/cdrom eingehängt, dann können wir von einem Slackware-basierten System, Slackware ganz einfach im neuen Container installieren:
host# installpkg -root /home/slack /media/cdrom/slackware/a/*.tgz
Damit ist das Basissystem bereits da, doch ein bisschen mehr wollen wir noch installieren, mindestens die als REQUIRED und RECOMMENDED klassifizierten Pakete der Serien ap,l und n. Dazu gehen wir wie folgt vor:
host# cd /media/cdrom/slackware/ap
host# INSTPKG=$(grep -v ^# tagfile | egrep '(ADD|REC)' | awk -F: '{print $1"-*.tgz" }')
host# installpkg² -root /home/slack $INSTPKG
Das ganze Spiel wiederholen wir für die Serie l:
host# cd /media/cdrom/slackware/l
host# INSTPKG=$(grep -v ^# tagfile | egrep '(ADD|REC)' | awk -F: '{print $1"-*.tgz" }')
host# installpkg² -root /home/slack $INSTPKG
²Die Beispiele beziehen sich auf Slackware. Unter anderen Distributionen wird es komplizierter. Zwar können Sie statt «installpkg» auch «tar» benutzen, jedoch werden dann die Installationsskripts nicht ausgeführt - dies müssen Sie manuell tun, alles zusammen geht das dann etwa so:
  for pkg in $INSTPKG; do
  tar xzpf $pkg -C /home/slack
  ( cd /home/slack ; sh install/doinst.sh )
  done

Auf Wunsch werden auf die gleiche Weise weitere Serien installiert, z.B. n (Netzwerk), d (Softwareentwicklung), x (X-Server) und xap (X Applikationen). Allerdings lassen sich diese Serien, gerade wenn das Wirtssystem kein Slackware-System ist, bequemer installieren, wenn der Container schon eingerichtet ist.

Für diese Einrichtung benötigen wir ein paar Dateien vom Wirt:

host# cp /etc/resolv.conf /home/slack/etc
host# cp /etc/hosts /home/slack/etc
host# cp /etc/X11/xorg.conf /home/slack/etc/X11

Nun können wir den Container starten - den Start werden wir noch in ein Skript verpacken. Doch für den ersten Test und die nötigen Anpassungen im Container reicht erstmal ein

host# chroot /home/slack su -
Nun finden wir uns im Slackware-Container wieder. Ein paar Dinge wollen wir hier anpassen:
chroot-slack# vi /etc/mtab
/dev/root / tmpfs rw 0 0
proc /proc proc rw 0 0
sysfs /sys sysfs rw 0 0
chroot-slack# vi /etc/fstab
/dev/root / tmpfs rw 0 0

Da beim Starten des Containers alle die Initialisierungen, die normalerweise durch den Bootprozess durchgeführt werden, übergangen werden, verankern wir im Container ein Startskript. Dieses Startskript wird beim Containerstart chroot übergeben (anstelle von su -):

chroot-slack# vi /root/cstart
#!/bin/bash

startuser=${1:-root}

# mount /dev/pts
df | grep -w devpts > /dev/null 2>&1
if [ "$?" = "0" ]; then
  mount -n devpts
else
  mount | grep -w devpts > /dev/null 2>&1
  [ "$?" = "0" ] || mount devpts
fi

# start shell
exec su - $startuser

chroot-slack# chmod +x /root/cstart

Das wär's. Der Slackware-Container ist startklar....

2d. Beispiel: Installation einer Live-CD

Als Live-CD stand mir back|track zur Verfügung. back|track baut auf SLAX auf.

Aufgrund des speziellen Dateisystems, das Live-CDs im Allgemeinen verwenden, gestaltet sich die Installation etwas ungewöhnlich. So können wir die CD nicht einfach ins Dateisystem hängen und die Daten mit «tar» in ein Verzeichnis kopieren, stattdessen müssen wir tatsächlich zunächst von der CD booten. Doch bevor wir dies tun, finden wir zunächst die Partition heraus, auf der unser Zielverzeichnis /home liegt, z.B.:

host# df /home
Filesystem           1K-blocks      Used Available Use% Mounted on
/dev/hda6               224576     44692    179884  20% /home²
²Sehen Sie hier einen /, liegt /home nicht in einer eigenen Partition. Das müssen Sie beim Kopieren später beachten

Nun booten wir die Live-CD....

Nach der Anmeldung im Livesystem müssen wir unser Zielverzeichnis /home zunächst unter den eingehängten Verzeichnissen identifizieren. Gegebenfalls müssen wir die /home-Partition selbst einhängen.

back|track hängt alle Festplattenpartitionen unter /mnt ein, so dass unser /home nun /mnt/hda6³ heißt.

Zunächst legen wir den Container an

live-cd# mkdir /mnt/hda6/slax 

Wir kopieren die Daten und legen einige wichtige Verzeichnisse im Container an:

live-cd# cp --preserve -R /{bin,dev,etc,home,lib,root,sbin,usr,var,opt,pentest} /mnt/hda6/slax
live-cd# mkdir /mnt/hda6/slax/{boot,mnt,proc,sys,tmp}
live-cd# cp /boot/boot/vmlinuz /mnt/hda6/slax/boot
³Liegt Ihr /home nicht in einer eigenen Partition (s.o.), müssen Sie in den obigen Beispielen statt /mnt/hda6 immer/mnt/hda6/home setzen!

Haben wir dies geschafft, booten wir wieder von Platte in unser Host-System und kopieren die nötigen Dateien aus /etc in den neu geschaffenen Container:

host# cp /etc/resolv.conf /home/slax/etc
host# cp /etc/hosts /home/slax/etc

Nun sind wir soweit, dass wir den Container starten können. Zunächst einmal ohne Skript einfach mit

host# chroot /home/slax su -
Schon finden wir uns im Container wieder. Dort passen wir in der Datei .bashrc den Prompt so an, dass wir immer gleich erkennen, dass wir uns im Container bewegen:

chroot-slax# vi /root/.bashrc
PS1='(SLAX)\[\033[01;31m\]\h\[\033[00m\]:\[\033[01;34m\]\w\$ \[\033[00m\]'

Damit wir im Container Kommandos wie «df» und «mount» sinnvoll verwenden können, erstellen wir die Datei /etc/mtab mit folgendem Inhalt:

chroot-slax# vi /etc/mtab
/dev/root / tmpfs rw 0 0
proc /proc proc rw 0 0
sysfs /sys sysfs rw 0 0

Da beim Starten des Containers alle die Initialisierungen, die normalerweise durch den Bootprozess durchgeführt werden, übergangen werden, verankern wir im Container ein Startskript. Dieses Startskript wird beim Containerstart chroot übergeben (anstelle von su -):

chroot-slax# vi /root/cstart
#!/bin/bash

startuser=${1:-root}

# mount /dev/pts
df | grep -w devpts > /dev/null 2>&1
if [ "$?" = "0" ]; then
  mount -n devpts
else
  mount | grep -w devpts > /dev/null 2>&1
  [ "$?" = "0" ] || mount devpts
fi

# start shell
exec su - $startuser

chroot-slax# chmod +x /root/cstart

Das wär's.

3. Container Startskripts

Wir erstellen das Startskript für die Container auf dem Host:

host# vi /usr/local/sbin/start_container
#!/bin/bash

cntroot=/home
cntuser=${2:-root}
container=${1:-debian}

mount | grep ${cntroot}/${container}/proc > /dev/null 2>&1
[ "$?" = "0" ]  || mount -t proc proc\($container\) ${cntroot}/${container}/proc

grep -w sysfs ${cntroot}/${container}/etc/mtab > /dev/null 2>&1
if [ "$?" = "0" ]
then
  mount | grep ${cntroot}/${container}/sys > /dev/null 2>&1
  [ "$?" = "0" ]  || mount -t sysfs sysfs\($container\) ${cntroot}/${container}/sys
fi

exec chroot ${cntroot}/${container} /root/cstart ${cntuser}

Container lassen sich jetzt mit dem Kommando

start_container [ <Container> [<Benutzer>] ]
starten. Durch das Skript wird auf dem Host automatisch zwei Mounts durchgeführt, die dem Container ermöglichen auf auf die Prozesstabelle zuzugreifen. Wenn beide Container gestartet wurden, sehen wir auf dem Host-System die folgenden vier neuen Mounts:

proc(debian) on /home/debian/proc type proc (rw)
sysfs(debian) /mnt/debian/sys sysfs rw 0 0
proc(slax) on /home/slax/proc type proc (rw)
sysfs(slax) on /mnt/slax/sys type sysfs (rw)

4. X im Container starten

Bislang haben wir nichts weiter als eine Shell im Container. Doch will man sich eine neue Distribution einmal wirklich anschauen, will man natürlich auch die neuesten Desktop-Features sehen - wir wollen also X im Container starten. Das ist viel einfacher als man zunächst glauben mag...

Zunächst einmal brauchen wir eine gültige Konfigurationsdatei - diese können wir mit den distributionseigenen Werkzeugen erstellen oder aber einfach von unserem Host, auf dem X ja schon wunderbar konfiguriert ist, kopieren - wie dies im Beispiel Debian bereits gemacht wurde (2. Beispiel: Installation von Debian Sarge).

host# cp /etc/X11/xorg.conf /home/container/etc/X11
Der Start gestaltet sich dann sehr einfach. Im Debian- aber auch im openSUSE-Container starten Sie einfach

container# kdm

und schon können Sie sich auf vt8 ganz normal anmelden.

Unter back|track starten Sie X mit dem Befehl

chroot-slax# gui

wie von der Live-CD aus auch. Damit es klappt, musste ich allerdings in der Datei /usr/X11R6/lib/X11/xinit/xinitrc in der letzen Zeile den vollen Pfad zu startkde angeben:

chroot-slax# vi /usr/X11R6/lib/X11/xinit/xinitrc
             .
             . 
             .
# Start the window manager:
/opt/kde/bin/startkde

5. Weiterführende Informationen

zu Teil II: Erweiterte Konfiguration

Im zweiten Teil geht es um Netzwerkzugang zu den Containern und um eine Standardisierung der Containerkonfiguration. Dazu werden wir auf Techniken zurückgreifen, wie sie in diesem Artikel entwickelt wurden.