Aus Linux-Magazin 06/2013

Transparente Architektur-Emulation mit Qemu

© Joseasreyes, 123RF.com

Kompakte Systeme wie der Raspberry Pi bieten preisgünstige Hardware für unzählige Verwendungszwecke. Doch wie entwickelt und portiert man Software auf diese Plattformen?

Die Entwicklung für kleine System-on-a-Chip-Geräte wie den Raspberry Pi stellt eine größere Herausforderung dar, als man zunächst annehmen mag. Diese Geräte sind in erster Linie darauf ausgerichtet, fertige Software auszuführen. Daher hat es sich bewährt, Betriebssystem-Images anzubieten, die ein Anwender lediglich auf den Speicherchip oder das Speichermedium des Geräts kopiert. Im Falle des Raspberry Pi genügt es, ein 1-zu-1-Abbild auf eine SD-Speicherkarte zu schreiben (etwa mit »dd« ), von der das Gerät bootet.

Doch wie erstellt man ein solches Image, das die eigenen Dienste oder Frameworks anbieten soll, möglichst effizient? Naheliegend ist, auf dem Gerät selbst die notwendige Software zu installieren und zu kompilieren. Hier ließen sich alle Einstellungen vornehmen, bevor man das Image auf umgekehrtem Wege wieder von der SD-Karte in eine Datei schreibt, um diese weiterzuverteilen. Das Problem: Die beschriebene Prozedur dauert sehr lange, da diese Geräte keine ausreichenden Ressourcen bieten, um darauf ernsthaft zu entwickeln. Auch geduldige Menschen spüren daher schon bald das Verlangen nach einer Lösung, die möglichst reproduzierbar und automatisiert solche Images generiert.

Draufsicht

Der logische erste Schritt besteht also darin, die eigene Perspektive auf den Prozess zu verändern und einen Schritt zurück zu tun. Um beim Raspberry Pi zu bleiben: Mit Hilfe von Skripten lässt sich etwa das von der Raspberry-Pi-Foundation bereitgestellte Raspbian-Image, das auf Debian basiert, direkt an die eigenen Bedürfnisse anpassen und weiterverteilen. Das spart nicht nur eine Menge Zeit, sondern lässt sich später auch automatisieren und mit einer Continuous-Integration-Umgebung kombinieren, etwa Jenkins CI [1].

Doch auf dem Weg dorthin liegen noch ein paar Stolpersteine. Der gewitzte Entwickler denkt natürlich sofort daran, das Image in eine Chroot-Umgebung einzubinden. So lässt sich darin agieren, als hätte man das System regulär gebootet. Allerdings macht die abweichende Prozessorarchitektur hier einen Strich durch die Rechnung, denn die Intel-CPU kann die binären ARM-Programme nicht ausführen. Besteht also die einzige Lösung darin, einen Raspberry Pi als virtuelle Maschine zu betreiben, mit all den Nachteilen in Sachen Automatisierung, die das mit sich bringt? Nicht zwangsläufig!

Schnell mal emulieren

Ein Übersetzer muss her, der direkt zur Laufzeit einspringt. Qemu [2], der Quick Emulator, dürfte in Verbindung mit Linux’ Virtualisierungslösung KVM ein Begriff sein. Doch das Projekt weist noch deutlich mehr Facetten auf. Zusammen mit dem vom Kernel bereitgestellten »binftm_misc« -Mechanismus bietet die Qemu-User-Emulation die Möglichkeit, auch plattformfremden Binärcode auszuführen. Einzige Voraussetzung: Die Maschine selbst darf nicht als VM laufen, sonst wird es kompliziert (Stichwort: Nested Virtualization).

Unter Debian genügt für die Installation eine einzige Zeile:

sudo apt-get install qemu binfmt-support qemu-user-static

Im nächsten Schritt startet der Entwickler den Daemon »binfmt-support« und lässt sich über den Befehl »sudo update-binfmts –display« eine Liste aller unterstützten binären Formate anzeigen. Ruft er dabei ein Programm auf, das für eine andere Plattform kompiliert wurde, erkennt der Daemon das Binärformat automatisch und der passende Qemu-CPU-Emulator führt die Datei aus. Er übersetzt dabei simultan die fremden Prozessorbefehle in für die Intel-Plattform ausführbare Kommandos.

Das Ganze ist allerdings sehr rechenintensiv und zudem nicht auf mehrere CPU-Cores verteilbar, weshalb die Taktung eines einzelnen CPU-Kerns entscheidend für die Performance ist. Ein 2-GHz-Kern liegt nur leicht über der Performance des ARM-Prozessors im Raspberry Pi selbst, die Vorteile dieser Methode liegen also eher in der Flexibilität.

Beeren pflücken

Um das Raspberry-Pi-Image an die eigenen Bedürfnisse anzupassen, mountet der Entwickler es am besten mit einem kleinen Skript [3], das hier im Beispiel aus der Portierung der quelloffenen Telefonanlage Gemeinschaft 5 [4] stammt:

mnt-pi-img.sh 2013-02-09-wheezy-raspbian. img /mnt

Es berücksichtigt die zwei Partitionen, die das Image enthält: Eine FAT-Partition für den Bootbereich und eine Ext-4-Systempartition. Zudem setzt es Loop Mounts für »/dev/pts« , »/sys« und »/proc« und kopiert die Qemu-Emulatordatei an die richtige Stelle im Dateisystem, damit sie innerhalb der Chroot-Umgebung zur Verfügung steht. Man sollte das Skript auch beim finalen Aushängen der Gerätedateien verwenden. Der Befehl

sudo chroot /mnt

wechselt direkt in die Chroot-Umgebung. Hier nimmt der Entwickler alle notwendigen Änderungen vor, zu denen unter anderem das Installieren und Deinstallieren von Paketen über »apt-get« , das Kompilieren von Software und das Anpassen der Konfiguration gehören. Es ist in der Tat fast so, als würde man tatsächlich auf einem Raspberry Pi arbeiten. Nur Dienste, die der Entwickler starten muss, um sie zu konfigurieren (etwa MySQL), sind schwieriger zu handhaben. Läuft ein ähnlicher Netzwerkdienst mit gleichem Port bereits auf dem Hostsystem, lässt er sich nicht ein zweites Mal starten.

Abbildung 1: In mehreren Schritten erstellt man aus einem Community-betreuten Debian-Image für ARM ein angepasstes Image für den Raspberry Pi.

Abbildung 1: In mehreren Schritten erstellt man aus einem Community-betreuten Debian-Image für ARM ein angepasstes Image für den Raspberry Pi.

Das tatsächliche Laufzeitverhalten unterscheidet sich also, abhängig vom Anwendungsfall, von dem auf einem echten Gerät. Im Zweifel behilft sich der Image-Bastler damit, die gewünschten Kommandos in einem Initskript zusammenzufassen, welches das System beim ersten Booten des Image abarbeitet und das sich dann selbst löscht.

Theorie und Praxis

Bereitstellung und Pflege eines Image sind relativ aufwändig, und gewöhnlich will der Entwickler ja in erster Linie, dass die eigene Software läuft. Wer ein von der Community betreutes Image für das Gerät verwendet, muss dieses nicht ständig an neue Entwicklungen auf dem Raspberry Pi selbst anpassen. Gemeinschaft 5 verwendet aus diesem Grund das originale Debian-Image.

Das Erstellen der ISO-Dateien auf dem Gerät übernehmen eigens entwickelte Hook-Skripte, die in Debian Live laufen, aber unabhängig von der CPU-Architektur funktionieren. Damit diese Hook-Skripte auch auf dem Raspberry Pi laufen, erzeugen wieder andere Skripte eine Systemumgebung, die der von Debian Live entspricht. Später aktualisiert eine dritte Variante von Skripten die Software über Apt-get- oder Git-Repositories.

Lediglich das Bauen eines Image mit neu angepassten Skripten dauert nun noch fünf bis sechs Stunden, was über Nacht passieren kann. Steht das Grundgerüst aber erst mal, sind Anpassungen und Erweiterungen schnell erledigt. Gekoppelt mit einem Git-Repository und Jenkins CI entsteht sogar eine kontinuierliche Integrations- und Buildumgebung.

Der Autor

Julian Pawlowski lebt in München und arbeitet als freiberuflicher IT-Projektmanager im internationalen Umfeld. Er ist seit 2012 im Core-Team der Telefonanlagen-Software Gemeinschaft und dort für den Release-Prozess verantwortlich.

DIESEN ARTIKEL ALS PDF KAUFEN
EXPRESS-KAUF ALS PDFUmfang: 2 HeftseitenPreis €0,99
(inkl. 19% MwSt.)
LINUX-MAGAZIN KAUFEN
EINZELNE AUSGABE Print-Ausgaben Digitale Ausgaben
ABONNEMENTS Print-Abos Digitales Abo
TABLET & SMARTPHONE APPS Readly Logo
E-Mail Benachrichtigung
Benachrichtige mich zu:
0 Kommentare
Älteste
Neuste Beste Bewertung
Inline Feedbacks
Alle Kommentare anzeigen
Nach oben