Ubuntu auf einem Rootserver mit ZFS

Es ist mal wieder so weit: der alte Server ist zu klein, ein neuer muss her. Dieser Artikel ist ein Update zu meinem Update meiner alten Anleitung zum Setup des Rootservers.

Ein Serverumzug ist eine gute Gelegenheit, ein paar Dinge anders zu machen als bisher:

  • ZFS: die bisherige Lösung aus Raid + LVM + Dateisystem funktioniert zwar, aber das vergrößern / verkleinern der Partitionen ist doch immer eine recht spannende Angelegenheit und kann nicht immer online durchgeführt werden. Btrfs bietet noch nicht alle Features, die ich haben möchte (quotas auf FS-Ebene) und mit ZFS on Linux steht ZFS auch nativ als Kernelmodul zur Verfügung.
  • LXC statt OpenVZ: der Betrieb mit OpenVZ war nie ganz frei von Sorgen. Es ist super, dass man so viele Parameter hat und Resourcen flexibel zuweisen kann, aber speziell beim Webserver hatten wir das Gefühl, dass nie genug RAM vorhanden ist. Stößt der Server an das RAM-Limit, kommt es zu den seltsamsten Effekten, incl. Stillstand des Webserver. LXC ist im Mainline-Kernel und für unsere Zwecke gut genug, d.h. ich will Resourcen flexibel zuweisen und kann auf die höhere Sicherheit einer echten Virtualisierung verzichten.
  • nginx statt Apache: weil man es mal gemacht haben sollte 😉

Eine Sache, die sich hingegen bewährt hat, ist alle Dienste (PAM, Mail, sonstige Accounts) über LDAP abzuwickeln. Damit ist LDAP der „single point of administration and failure“, der sich besonders gut scripten lässt.

Hier also wieder die Copy & Paste Anleitung für das Setup von

Ubuntu auf einem Rootserver mit ZFS

Ich habe meinen Server bei Hetzner, aber das muss jeder selbst wissen. Als erstes bootet man ins Rescue-system und sichert den Inhalt der Datei /etc/network/interfaces:

### Hetzner Online AG - installimage
# Loopback device:
auto lo
iface lo inet loopback

# device: eth0
auto  eth0
iface eth0 inet static
  address   5.9.62.176
  broadcast 5.9.62.191
  netmask   255.255.255.224
  gateway   5.9.62.161

# default route to access subnet
up route add -net 5.9.62.160 netmask 255.255.255.224 gw 5.9.62.161 eth0

Festplatten einrichten

Dieses Mal soll der Server mit zfs betrieben werden. Es gibt zwar diverse Anleitungen, wie man Ubuntu in ein natives Root-ZFS-Dateisysten installiert, ich wähle aber bewusst einen anderen Weg.

Im Recovery-Fall komme ich nicht an den physikalischen Server. Ich kann nur ein Rescue-System booten, das kein ZFS-Kernelmodul hat, damit würde ich nicht an das root-Dateisystem kommen.
Deswegen installiere ich das Basissystem auf einer ext4-Partition. Hier läuft lediglich der LDAP-Server und ein SSH-Server. Alle anderen Dienste laufen in LX-Containern und diese können auf dem ZFS untergebracht werden.

Der Server ist mit 2×3 TB Festplatten ausgestattet, d.h. mit einem MBR kommt man nicht sehr weit, statt dessen wird eine GUID Partition Table (GPT) eingerichtet. Neben Root, Swap, ZFS wird auch eine „BIOS boot partition“ benötigt (ein EFI-Requirement).

gdisk /dev/sda

Der Rechner hat 32 GB Ram, also sollten 16 GB Swap genügen. Für das Root-System stelle ich 10GB bereit. Auf LVM verzichte ich bewusst um die Komplexität gering zu halten. Ich verliere damit die Möglichkeit das Basissystem über LVM-Snapshots zu sichern, den Kompromiss kann ich eingehen. Root und Swap werden aber in einem Raid-1 betrieben um einen Plattenausfall abzufangen. So sieht das gewünschte Layout aus:

Command (? for help): p
Disk /dev/sda: 5860533168 sectors, 2.7 TiB
Logical sector size: 512 bytes
Disk identifier (GUID): 932661F7-1628-4107-A48F-8FDDC9DB29E4
Partition table holds up to 128 entries
First usable sector is 34, last usable sector is 5860533134
Partitions will be aligned on 2048-sector boundaries
Total free space is 2014 sectors (1007.0 KiB)

Number  Start (sector)    End (sector)  Size       Code  Name
   1            2048            4095   1024.0 KiB  EF02  BIOS boot partition
   2            4096        33558527   16.0 GiB    FD00  Linux RAID
   3        33558528        54530047   10.0 GiB    FD00  Linux RAID
   4        54530048      5860533134   2.7 TiB     BF00  Solaris root

Die Platte /dev/sdb wird analog eingerichtet. Jetzt ist ein guter Zeitpunkt um das System zu rebooten (wir müssen nochmal das Rescue-System auswählen), damit die neue Partitionstabelle verwendet wird.

Dann können swap und / angelegt werden:

mdadm -v --create /dev/md0  --level=mirror  --metadata=0.90 --raid-devices=2 /dev/sda2 /dev/sdb2
mdadm -v --create /dev/md1  --level=mirror  --metadata=0.90 --raid-devices=2 /dev/sda3 /dev/sdb3

Wichtig: --metadata=0.90 sollte unbedingt gesetzt werden, sonst kann man große Probleme mit grub bekommen.

Swap aktivieren:

mkswap /dev/md0
swapon /dev/md0

Root-Dateisystem anlegen und mounten:

mkfs.ext4 /dev/md1
mkdir /mnt/install
mount /dev/md1 /mnt/install/

Jetzt können wir

Ubuntu installieren

Wir benötigen erstmal ein neueres debootstrap und installieren damit dann Ubuntu 12.04 LTS:

wget http://archive.ubuntu.com/ubuntu/pool/main/d/debootstrap/debootstrap_1.0.42_all.deb
dpkg -i debootstrap_1.0.42_all.deb 
debootstrap --arch amd64 precise /mnt/install http://archive.ubuntu.com/ubuntu

Die fstab muss angepasst werden:

vim /mnt/install/etc/fstab
proc                    /proc   proc    defaults 0 0
/dev/md0                none    swap    defaults,pri=1 0 0
/dev/md1                /       ext4    defaults 0 1

ausserdem muss die Netzwerk-Config, die wir vorhin gesichert haben wieder gesetzt werden:

vim /mnt/install/etc/network/interfaces
### Hetzner Online AG - installimage
# Loopback device:
auto lo
iface lo inet loopback

# device: eth0
auto  eth0
iface eth0 inet static
  address   5.9.62.176
  broadcast 5.9.62.191
  netmask   255.255.255.224
  gateway   5.9.62.161

# default route to access subnet
up route add -net 5.9.62.160 netmask 255.255.255.224 gw 5.9.62.161 eth0

Die Spezialmounts werden noch gemountet:

mount -t proc none /mnt/install/proc
mount --bind /sys /mnt/install/sys
mount --bind /dev /mnt/install/dev
mount -t devpts none /mnt/install/dev/pts

Dann können wir ins System chrooten…

chroot /mnt/install/ /bin/bash

… und ein paar Einstellungen vornehmen. Zuerst ein neues root-Passwort:

shadowconfig on
passwd

Wir brauchen das Universe-Repository

vim /etc/apt/sources.list
deb http://archive.ubuntu.com/ubuntu precise main universe

Dann werden ein paar grundsätzliche Tools installiert:

apt-get update
apt-get install aptitude
aptitude install man-db vim ssh

Ausserdem wird mdadm zur Raidverwaltung benötigt. Da in Ubuntu eine Abhängigkeit zu einem MTA existiert und der default Postfix ist, installieren wir das sehr schlanke Tool SSMTP mit:

aptitude install ssmtp mdadm

Dann brauchen wir noch einen Bootloader. Dieser wird als Abhängigkeit des Kernels installiert:

aptitude install linux-image-generic

Damit die Boot-Partitionen durch die initrd auch einwandfrei gemountet werden, sollte Änderung der Datei mdadm.conf noch die initrd neu angelegt werden, z.B. durch Ausführen von

dpkg-reconfigure mdadm

Sofern die entsprechenden Module, md bzw. raid0, raid1, noch nicht in der /etc/initramfs-tools/modules aktiviert wurden, muss dies noch erfolgen:

echo "raid0" >>/etc/initramfs-tools/modules
echo "raid1" >>/etc/initramfs-tools/modules
echo "md" >>/etc/initramfs-tools/modules

und anschließend das initramfs mit

update-initramfs -u -k all

aktualisiert werden.

Zum Schluss solle die Option „quiet splash“ aus /etc/default/grub entfernt werden. Die Remote-Konsole LARA bei Hetzner kommt sonst mit dem Bildschirmmodus nicht klar und man würde bei bootproblemen nichts sehen.

vim default/grub

Dann noch grub updaten, aus dem Chroot aussteigen und rebooten.

update-grub
exit
reboot

Wenn kein Fehler aufgetreten und der Server wieder hoch gekommen ist, können wir

ZFS installieren

Für Ubuntu ist die Installation sehr einfach. Wir brauchen erstmal das Paket python-software-properties, da sonst add-apt nicht funktioniert:

aptitude install python-software-properties

Dann kann nach der Installationsanleitung verfahren werden:

add-apt-repository ppa:zfs-native/stable
aptitude update
aptitude install ubuntu-zfs

Das Kernelmodul zfs.ko sollte jetzt gebaut und geladen sein. Jetzt können wir einen zpool auf dem verbleibenden Festplattenplatz anlegen.

zpool create -o ashift=12 tank mirror /dev/disk/by-id/ata-ST3000DM001-9YN166_W1F0W2EW-part4 /dev/disk/by-id/ata-ST3000DM001-9YN166_W1F0WNK2-part4

Die Option ashift=12 sort für ein passendes Alignment. Die Namen der Festplatten müssen natürlich angepasst werden.

Der Pool ist angelegt…

zfs list
NAME   USED  AVAIL  REFER  MOUNTPOINT
tank   472K  2.66T   136K  /tank

…und kann jetzt mit Filesystemen bestückt werden:

zfs create -o mountpoint=/home tank/home  
zfs create -o mountpoint=/var/vm tank/vm 
zfs list
NAME        USED  AVAIL  REFER  MOUNTPOINT
tank        864K  2.66T   136K  /tank
tank/home   136K  2.66T   136K  /home
tank/vm     136K  2.66T   136K  /var/vm

Ich habe zunächst nur ein Filesystem für /home und für die Linuxcontainer angelegt. Ab hier weiss sicherlich jeder selbst am besten, wie das System organisiert wird.

Credits: Das Setup des Basissystems mit GPT hätte ich ohne die Anleitung von Mattias nicht so schnell hinbekommen.