Serverkonsolidierung mit Jails

Aus UUGRN

Dieser Artikel beschreibt Möglichkeiten, gewachsene Strukturen mit FreeBSD-Servern auf weniger Hardware zusammenzufassen. Doch oftmals lassen sich individuell konfigurierte Systeme nicht auf einen gemeinsamen Nenner bringen. Der perfekte Anwendungsfall für Virtualisierung, in diesem Fall mit FreeBSD-Jails.


Theorie[Bearbeiten]

FreeBSD Jail stellen im eigentlichen Sinn keine Virtualisierung dar sondern mehr eine Methode zum Trennen von Prozessumgebungen. Alle Prozesse, die innerhalb eines Jail-Kontextes gestartet werden, können selbst mit root-Rechten nur auf andere Prozesse und Ressourcen aus dem gleichen Jail zugreifen. Auf einem Host können viele Jails nebeneinander existieren. Prozesse, die keinem Jail angehören, sehen alle Ressourcen in allen Jails.

Ressourcen[Bearbeiten]

Ein Jail verfügt typischerweise über

  • Eigenes Verzeichnis, welches innerhalb des Jails als "/" erscheint
  • Eigene IP-Adresse als Alias auf einem Netzwerkinterface
  • Eigene Benutzerrechte (root!), mit Einschränkungen

Alle Jails und alle Prozesse ohne Jail-Kontext teilen sich:

  • Arbeitsspeicher, wobei hier kein "Übergriff" stattfinden kann zwischen den Jails.
  • CPU
  • Kernel
  • Prozesstabelle, PIDs sind systemweit eindeutig.

Aus Sicht des Kernels haben zwar alle root-User die uid=0, da Prozesse im Jail nicht aus ihrem Jail heraus zugreifen können, ist dies zu verschmerzen. Innerhalb des Jails sind daher einige Zugriffsrechte auch für root beschränkt wie etwa das anlegen von device-nodes, setzen von Filesystem-Flags, mounten von Dateisystemen, Low-Level Zugriff auf das Netzwerk (raw-sockets etc), Hardware (ACPI, ... ), shutdown der Maschine etc.

Problematisch ist in diesem Zusammenhang derzeit Shared Memory zu nennen, da es bisher nur eine maschinenweite gemeinsame Verwaltung hierfür gibt. Aus diesem Grund ist es ratsam, Shared Memory in Jails nicht zu erlauben.

Umfang eines Jails[Bearbeiten]

Ein Jail kann aus n (n>=1) Prozessen bestehen. Als Bug ist anzusehen, wenn ein Jail-Kontext nach Beenden des letzten Prozesses nicht beendet wird. Grund dafür sind allozierte Ressourcen, die nicht freigegeben wurden, z.B. halboffene Netzwerkverbindungen oder geöffnete Dateien.

Statt eines Prozesses kann man natürlich auch ein komplettes Userland innerhalb eines Jails starten. Typischerweise wird der Startvorgang eines Systems vom Script /etc/rc durchgeführt:

# jail /data/jail/192.168.11.100 testhostname 192.168.11.100  /bin/sh /etc/rc


Praxis[Bearbeiten]

Ausganssituation[Bearbeiten]

In einer nicht näher benannten Umgebung existieren noch einige FreeBSD-Installationen, die aufgrund von Nachlässigkeit oder niedriger Priorität nie upgedatet wurden, zum einen weil es möglicherweise zu komplex gewesen wäre, zum anderen weil Sicherheit hier keine primäre Rolle spielt. Never touch a running system also.

Moderne Hardware wird immer leistungsfähiger, bestehende Systeme haben jedoch gleichbleibenden oder verminderten Ressourcenbedarf. Alte Systeme 1:1 auf moderne Hardware umzuziehen ist eine Kostenfrage, falls so alte Systeme überhaupt auf moderner Hardware laufen.

Beispiel[Bearbeiten]

Im Beispiel geht es um 3 Server:

ServerA
FreeBSD 4.10, Webserver mit SSL-Support und eigenem Zertifikat, Apache 1.3 und PHP 4.x, Verfügbarkeitsanforderung, aber niedrige Hitrate.
ServerB
FreeBSD 4.9, Webserver mit SSL-Support mit SnakeOil-Zertifikat, Apache 1.3 und PHP5.0.x, Hohe Verfügbarkeitsanforderung, viele Hits, wenig Ressourcenbedarf (statischer Content). Außerdem Fremdsoftware, die für dieses System maßgeschneidert wurde mit bekannten Problemen bei Updates (PHP Inkompatiblitäten), sehr unflexibel.
ServerC
FreeBSD 4.7, Samba-Server mit Apache und PHP-Uralt. Für Legacy-Applikationen mit teilweise noch urzeitlichem PHP-Code, register_globals=on, schwer wartbare Software, wirr gewachsene Verzeichnisstrukturen und festverdrahtete Abhängigkeiten auf Pfade.

Problem[Bearbeiten]

Es ist nahezu ausgeschlossen, diese Systeme mit vertretbarem Aufwand auf ein System zusammenzufassen, auch wenn dies in der Theorie kein Problem darstellen würde.

Umsetzung[Bearbeiten]

Vorbereiten[Bearbeiten]

Ein vorhandener Jailserver, hier mit FreeBSD 6.2, wird für 3 weitere Jails vorbereitet. Der Konvention folgend werden die Verzeichnisse /data/jails/ServerA/, /data/jails/ServerB/, /data/jails/ServerC/ leer angelegt. Weiterhin müssen jailhost-spezifische Einstellungen vorgenommen werden, etwa in /etc/rc.conf, /etc/fstab.ServerX, ...

Live-Transfer[Bearbeiten]

Mittels ssh "dump" | restore werden die einzelnen Filesysteme der Urserver transferiert, alternativ auch durch transfer von einzelnen dump-Files (nicht empfehlenswert).

jailhost# mkdir /data/jails/ServerA
jailhost# cd /data/jails/ServerA/
jailhost# ssh root@ServerA "dump -0ua -f - / | buffer " | buffer | restore -v -rf -
jailhost# cd /data/jails/ServerA/usr/
jailhost# ssh root@ServerA "dump -0ua -f - /usr | buffer " | buffer | restore -v -rf -
jailhost# cd /data/jails/ServerA/var/
jailhost# ssh root@ServerA "dump -0ua -f - /var | buffer " | buffer | restore -v -rf -

Entsprechend für alle Partitionen durchführen. Ist auf dem Zielsystem FreeBSD 5.x oder neuer, dann braucht dump noch die Option "-L", um auf einem Filesystem-Snapshot zu arbeiten.

Anpassungen[Bearbeiten]

  • Backup von ServerA/etc durchführen
  • nicht benötigte Dateien und Verzeichnisse löschen, sofern vorhanden
jailhost# cd /data/jails/ServerA/
jailhost# rm -Rf usr/src usr/ports usr/obj/usr/src; mkdir usr/ports
jailhost# rm -Rf boot/ kernel*
jailhost# rm -Rf dev/ ; mkdir dev
  • vorhandenes rc.conf sichern und bis auf die eigentlichen Dienste (apache_enable="YES", ... ) alles auskommentieren oder besser noch löschen, in Jails benötigt man kein Hardware- und Netzwerksetup, das leistet der Jailhost.
  • vorhandene /etc/fstab löschen oder alles auskommentieren

Basissystem im Jail updaten[Bearbeiten]

Das heikelste folgt nun, das Update des Basis-Systems. Im aktuellen Beispiel wird von 4.10 auf 6.2 upgedatet, jedoch "offline", d.h. aus dem unter 6.2 laufenden Jailhost heraus.

Auf dem jailhost liegt unter /usr/src das aktuell laufende Release, hier z.B. die Sourcen von 6.2-RELEASE-p6 Falls diese noch nicht kompiliert wurden, diese zunächst frisch kompilieren.

jailhost# cd /usr/src
jailhost# make -j2 buildworld

Einen frischen Kernel benötigen wir nicht, daher ohne "buildkernel". Die gebaute Welt kann nun in das Jail installiert werden:

jailhost# make installworld DESTDIR=/data/jails/ServerA/

Wenn das durchgelaufen ist, dann dringend mit mergemaster updaten:

jailhost# mergemaster(8) -D/data/jails/ServerA/

Das ist der zweifelsohne aufwendigste Schritt, da so ziemlich alles, aber eben nicht alles, upgedatet wird. Besonders Augenmerk sollte hier auf /etc/master.passwd, /etc/motd, /etc/mail/* und alle anderen händischen Konfigurationen gelegt werden, unproblematisch ist /etc/rc.d/, da dieses komplett ersetzt werden sollte, d.h. alte Dateien löschen, neue Dateien 1:1 installieren.

Erster Startversuch[Bearbeiten]

Wenn das Jail gemäß der lokalen Konventionen formal korrekt eingerichtet ist, kann es nun gestartet werden:

jailhost# /etc/rc.d/jail start servera 

Inspektion[Bearbeiten]

Per jls(8) und jexec(8) können wir in das Jail einsteigen.

jailhost# jls
  JID  IP Address      Hostname           Path
   1   10.11.12.13     ServerA            /data/jails/ServerA

jailhost# jexec 1 bash
ServerA# (im Jail!)

ServerA konnte erfolgreich gestartet werden, Apache läuft soweit und antwortet auf Requests.


siehe auch[Bearbeiten]