QVINTVS · SCRIBET

Raspbian richtig installieren

Raspbian bietet nur unzureichende Dokumentation über den korrekten Installationsweg der Distribution auf dem Raspberry Pi. Dieser Artikel soll zeigen, wie man es trotzdem hinbekommt.

Theorie

Das Raspbian-Projekt arbeitet wohl an der populärsten Linux-Distribution für den Raspberry Pi. Alles, was die Raspberry Pi Foundation offiziell zur Verfügung stellt, baut auf Raspbian auf, weshalb es überaus befremdlich erscheint, dass das Raspbian-Projekt keine Installationsanleitung mit sich bringt. Lediglich die Raspberry Pi Foundation betreibt mehr oder weniger geeignete Installer für technisch unerfahrene Nutzer, die aber wenig Kontrolle über das ermöglichen, was man eigentlich tatsächlich installieren möchte. Zudem enthalten die Foundation-Installer einen besonderen, von der Foundation gepatchten Kernel, der nicht demjenigen des Standard-Raspbians entspricht.

Raspbians eigene Dokumentation zur Installation der Distribution beschränkt sich auf einen Installer von 2008, obwohl das Projekt in Wirklichkeit aktiv entwickelt wird. Möglicherweise setzt das Raspbian-Team ein vertieftes Debian-Wissen allgemein voraus, um die Distribution installieren zu können; fehlt dieses, etwa, weil man bisher nicht debianbasierte Linux-Distributionen eingesetzt hat, weiß man nicht so recht, wie man anfangen soll.

Das Debian-Projekt bietet für die Installation von Debian von einem laufenden System aus das unheimlich nützliche Werkzeug debootstrap an, das unter ArchLinux sogar im AUR verfügbar ist, weshalb ich davon ausgehe, dass es auch unter anderen Linux-Distributionen installierbar ist. Insbesondere für die Einrichtung von Chroots ist debootstrap ein hervorragendes Werkzeug.

Aber auch zur Installation eines Debian-Systems auf fremder Prozessorarchitektur ist es geeignet. Das Problem bei dieser Konstellation ist, dass die für das Zielsystem konzipierten Executables auf dem eigenen, dem Hostsystem, nicht lauffähig sind. So können etwa Post-Install-Skripte nicht ausgeführt werden. Gängige heutige Rechner laufen auf einer x86_64-Architektur, die es unmöglich macht, die für den Raspberry Pi erforderlichen armhf-Executables auszuführen. debootstrap bietet jedoch speziell für solche Fälle die Möglichkeit, den Installationsprozess auf zwei Stufen aufzuspalten, die sich dann „First Stage“, d.h. Erste Stufe, und „Second Stage“, d.h. Zweite Stufe, nennen. Die erste Stufe besteht im Herunterladen der minimal erforderlichen Pakete sowie der Installation eines Second-Stage-Hilfsprogramms und wird auf dem Hostsystem ausgeführt. Pakete und Hilfsprogramm werden in das Zielverzeichnis kopiert. Auf dem Zielsystem steht dann unter /debootstrap/debootstrap das Hilfsprogramm in der Architektur des Zielprogramms zur Verfügung, welches dann in der Lage ist, den restlichen Installationsprozess nativ auf dem Zielsystem durchzuführen.

Durchführung

Zunächst einmal sind die grundlegenden Voraussetzungen zu erfüllen, d.h.:

Zunächst einmal gilt es, einen funktionstüchtigen Spiegelserver des Raspbian-Projekts zu finden. Selbiges unterhält zu diesem Zwecke eine umfangreiche Liste, von der jedoch nicht alle Einträge funktionieren. Sollte debootstrap hängen bleiben anstatt herunterzuladen, so kann es hilfreich sein, einen anderen Spiegelserver zu versuchen. Ich habe mich für den Leaseweb-Mirror entschieden (http://mirror.us.leaseweb.net/raspbian/raspbian).

Vorbereitend wird nun die SD-Karte formatiert. Die spätere /boot-Partition, bei der es sich zwangsweise um die erste Partition auf der SD-Karte handeln muss, damit die Firmware des Pi sie findet, muss mit FAT32 formatiert sein, die /-Partition kann in jedem für Linux verständlichen Dateisystem formatiert sein. Für die /boot-Partiton genügen 100 MiB, den Rest der SD-Karte kann man mit der /-Partition befüllen.

Nachdem diese Formatierung mit dem Partitionierungsprogramm der Wahl durchgeführt wurde, kann man die neuen Partitionen nun einhängen (/dev/sdc sei die SD-Karte):

# mount /dev/sdc2 /mnt
# mkdir /mnt/boot
# mount /dev/sdc1 /mnt/boot

Nun geht es an die eigentliche Installation:

# debootstrap  --arch=armhf --foreign wheezy /mnt http://mirror.us.leaseweb.net/raspbian/raspbian

--arch gibt die Zielarchitektur an, bei dem Raspberry Pi ist das armhf. --foreign weist debootstrap(8) wie beschrieben an, den Installationsprozess in zwei Stufen aufzuspalten: eine, die am Hostrechner durchgeführt werden kann (Herunterladen der Pakete), und eine, die auf dem Zielsystem ausgeführt wird (Installation der Pakete). wheezy ist der Codename der zu installierenden Debian-Variante, /mnt der Ort, wo sich die zukünftige /-Partition installiert sein wird. Die URL schließlich ist diejenige des angestrebten Spiegelservers, wie die Wiki-Seite des Raspbian-Projekts sie angibt.

Nach Abschluss dieses Kommandos ist das absolut minimal notwendige Minimalminimum installiert, das erforderlich ist, um dpkg(1) auf dem Zielsystem erfolgreich auszuführen, sowie ein Hilfsprogramm, /mnt/debootstrap/debootstrap, das mithilfe von dpkg(1) die nun heruntergeladenen Pakete installieren kann. Es fehlt nur eine Kleinigkeit: Der Kernel.

debootstrap(8) installiert tatsächlich keinen Linux-Kernel, der gebootet werden könnte, /mnt/boot bleibt leer. Das verhindert natürlich den Boot des Systems und die Ausführung von Installationsstufe 2. Temporär muss man sich also eines Kernels bedienen, der nicht aus den Raspbian-Paketquellen stammt, einfach, um an eine Shell zu kommen, aus der heraus man Stufe 2 zünden kann. Als Kernel in Frage kommt der vorkompilierte Kernel der Raspberry Pi Foundation; der gesamte Inhalt des /boot-Verzeichnisses kann auf GitHub gefunden, heruntergeladen, und in /mnt/boot verfrachtet werden. Auch möglich ist die Verwendung des ArchLinux-ARM-Kernels, der im Root-Tarball enthalten ist; ich habe mich für letztere Variante entschieden, weil ich mit ArchLinux ohnehin gut auskomme.

Nachdem also der Kernel und die ihn umgebenden Hilfsdateien nach /mnt/boot kopiert wurden, muss noch der Startprozess leicht geändert werden. Der Kernel möchte standardmäßig /init oder /sbin/init ausführen, was bei Debian normalerweise auch zum Systemstart führt. Allerdings ist das Initsystem noch nicht installiert; das geschieht erst auf Stufe 2. Außerdem muss dem Kernel noch mitgeteilt werden, wo er die Partition finden kann, die er als / nutzen soll. Beides geschieht durch Anpassen der Datei /mnt/boot/cmdline.txt, die die Kernel-Kommandozeile festlegt, also jene Parameter, die dem Kernel beim Boot mitgegeben werden; das entspricht der linux-Zeile des Bootloaders GRUB. Die Datei ist wie folgt anzupassen:

... root=/dev/mmcblk0p2 rootwait init=/bin/bash ...

Alle anderen Einträge so belassen, wie sie sind. Der root=-Parameter gibt das Device für die /-Partition an. Auf dem Raspberry Pi ist /dev/mmcblk0 immer die vorne eingeschobene SD-Karte, sodass /dev/mmcblk0p1 die FAT32-/boot-Partition und /dev/mmcblk0p2 die eigentliche /-Partition ist. rootwait weist den Kernel an, nicht abzustürzen, wenn dass Rootdevice noch nicht da ist, sondern erst später erkannt wird. init=/bin/bash schließlich ist die Magie, die bewirkt, dass trotz fehlendem Init-System eine Shell mit Root-Rechten (und PID 1 :-)) gestartet wird.

Neben dieser Änderung empfiehlt es sich, minimale Anpassungen am Zielsystem vorzunehmen. So sollte man etwa /mnt/etc/hostname auf den gewünschten Rechnernamen setzen und die /etc/fstab um die angelegten Partitionen erweitern, sodass sie wie folgt aussieht:

# /etc/fstab
/dev/mmcblk0p2    /      ext4    defaults    0 1
/dev/mmcblk0p1    /boot  vfat    defaults    0 2

Leerzeile am Ende der Datei nicht vergessen. Danach alles aushängen:

# umount /mnt/boot
# umount /mnt

Jetzt ist der spannende Moment gekommen. Die SD-Karte vom Hostsystem trennen, in den Pi einlegen und Monitor, Ethernet, USB-Tastatur und Stromkabel an den Rasperry Pi anschließen. Läuft alles gut, so erhält man am Ende einen Shellprompt, der den Hostnamen des Rechners noch mit I have no name! wiedergibt, was aber nicht weiter schädlich ist.

Zu beachten ist, dass in diesem Minimalsystem leider ausschließlich nur die US-Tastaturbelegung verfügbar ist, was einem deutschen Anwender regelmäßig Kopfschmerzen bereitet. Im Internet finden sich allerdings genügend Bilder derartiger Tastaturen, sodass unter Zuhilfenahme eines solchen die Bedienung nicht allzu schwer fallen sollte.

Es ist nunmehr an der Zeit, Stufe 2 des Installationsprozesses zu zünden:

# /debootstrap/debootstrap --second-stage

Sollte debootstrap(8) direkt am Anfang mit einer Fehlermeldung abbrechen, lohnt es sich, zu schauen, ob das Verzeichnis /var/run leer ist. Aus einem früheren Versuch mit Debians normalem Initsystem war bei mir dort noch eine Datei /var/run/utmp vorhanden, die erst gelöscht werden musste, bevor debootstrap(8) zur Arbeit schritt.

Nach Abschluss des Kommandos ist ein Minimalsystem installiert, aber noch nicht gestartet. Bevor man dies tut, ist es tunlichst anzuraten, das root-Passwort zu setzen, da ansonsten ein Login am späteren System unmöglich ist:

# passwd

Schließlich kann man das System jetzt starten. Da dank des kleinen Tricks mit der Kernel-Kommandozeile die aktuelle Shell als PID 1 läuft, kann man hier leicht die Systemaktualisierung manuell an init(8) abgeben:

# exec /sbin/init

Das startet Debian ganz gewöhnlich. Am Schluss des Systemstarts kann man sich jetzt als Nutzer root mit dem oben vergebenen Passwort anmelden.

Post-Install-Schritte

Damit hat man es fast geschafft, ein Grundsystem zu installieren, von dem aus man weitermachen kann. Es gilt zunächst, das System angenehm nutzbar zu machen, wozu die Paketverwaltung unerlässlich ist. Allerdings ist die /etc/apt/sources.list noch leer, sodass apt-get(1) und Verwandte die Arbeit verweigern. In diese Datei muss nun ein Raspbian-Spiegelserver eingetragen werden; es empfiehlt sich, denselben zu verwenden, den man auch zur Installation genutzt hat. Als Editoren stehen auf dem System zurzeit nur vi(1) und nano(1) zur Verfügung, wobei mir ersterer mit US-amerikanischer Tastaturbelegung derartig viele Bedienungsprobleme bereitet hat, dass ich auf nano(1) umgestiegen bin. Die in die /etc/apt/sources.list einzutragende Zeile sieht so aus (URL mit der des gewählten Spiegelservers ersetzen):

deb http://mirror.us.leaseweb.net/raspbian/raspbian wheezy main

Leerzeile am Ende nicht vergessen. Danach die Internetverbindung herstellen (Ethernetkabel eingesteckt?) und dann die Paketverwaltung auf den aktuellen Stand bringen:

# dhclient eth0
# apt-get update
# apt-get upgrade

Damit ist die Paketverwaltung einsatzbereit. Weiter geht’s mit der Anpassung an den deutschen Sprachraum:

# apt-get install locales console-data keyboard-configuration ntp
# dpkg-reconfigure locales
# dpkg-reconfigure console-data
# dpkg-reconfigure keyboard-configuration
# service keyboard-setup restart
# loadkeys de-latin1

Damit ist endlich ein deutsches Tastaturlayout verfügbar. Nach der Installation des bevorzugten Editors geht es nun daran, den hilfsweise installierten Kernel durch den korrekten aus den Paketquellen zu ersetzen. Das geschieht wie folgt:

# cd /boot
# mkdir oldboot
# mv kernel.img oldboot
# apt-get install linux-image-rpi
# cp vmlinuz-* kernel.img

Die letzte Zeile, das cp-Kommando, dient dazu, den Kernel so umzubenenen, dass die Firmware des Raspberry Pis ihn findet. Ein solches oder ähnliches Kommando ist nach jedem Kernel-Update erforderlich, damit der neu installierte Kernel auch geladen wird! Es sollte möglich sein, das durch ein Skript in /etc/kernel/postinst.d zu automatisieren.

Nun muss nun noch die Init-Modifikation aus der /boot/cmdline.txt entfernt werden, indem der Parameter init=/bin/bash ersatzlos gestrichen wird, sodass für zukünftige Starts direkt das Debian-Init übernehmen kann.

Zuletzt muss der Firmware noch beigebracht werden, dass der Debian-Kernel nur mithilfe eines Initramfs bootet. Darüber habe ich bereits geschrieben, sodass ich mich hier auf die bloßen Kommandos beschränke. /boot/config.txt editieren und folgende Zeile hinzufügen:

initramfs initrd 0x00f00000

Das Initramfs auf den passenden Dateinamen kopieren:

# cp initrd-* initrd

Auch dieses Kommando ist nach jedem Kernel-Update so oder ähnlich auszuführen. Schließlich noch die Datei /boot/cmdline.txt anpassen und den Kernel instruieren, das initramfs von der angegebenen Speicheradresse zu laden und zu booten:

... initrd=0x00f00000 ...

Das war’s.

# reboot

Valete.