Wer sich nicht nur einen einzigen, sondern gleich einen ganzen Zoo an Raspberry Pis hält, muss Wege finden, um die Zwerge schnell zu betanken und geschickt zu aktualisieren. Ein Bash-Skript bewirkt hier Wunder: Es lädt die passenden Images herunter und automatisiert die Konfiguration.
Der Raspberry Pi wurde bis Februar 2015 bereits 5 Millionen Mal verkauft [1]. Egal ob in Unternehmen, Schulen oder auch zu Hause, der Kleinstrechner begeistert die Anwender. Nach den anfänglichen Experimenten finden die Pis nicht selten Einzug in den produktiven Betrieb und treiben diverse Gerätschaften an, zum Beispiel ein Dashboard im Büro (Abbildung 1).
Doch beim Dauerbetrieb vieler Raspis zeigt sich, dass die Hardware-Entwickler Kompromisse schlossen, um den günstigen Preis zu ermöglichen: Vor allem die SD-Karten arbeiten nicht unbegrenzt. So gaben beim Autor bereits einige Exemplare den Geist auf, der Raspberry Pi erkannte sie nicht mehr, während sie auf normalen PCs weiterhin funktionierten.
À la carte
Admins erstellen problemlos eine neue SD-Karte mit Raspbian-Betriebssystem [2]: Sie laden die Zip-Datei herunter, entpacken diese und schreiben das darin enthaltene Image mit »dd« auf eine SD-Karte. Leider fehlen bei dieser Art der Neuinstallation persönliche Anpassungen und Konfigurationen. Im nächsten Schritt muss der Admin den Raspberry Pi also von der SD-Karte neu starten, um dann von Hand alles einzurichten.
Das geht besser
Das Bash-Skript »rpi-image-creator« ([3], [4]) automatisiert diesen Prozess vollständig (Abbildung 2), die Listings zeigen Auszüge daraus. Linux-Nutzer müssen zuvor noch einige abhängige Pakete installieren, unter Ubuntu lautet der passende Befehl:
sudo apt-get install kpartx qemu-user-static wget gpg parted
Das Skript lädt das aktuelle Raspbian-Image herunter, entpackt es und hängt es als Loopback-Device ein (Listing 1). Eingezäunt von »chroot« aktualisiert das Skript die Raspbian-Software im Image und führt weitere Anpassungen durch:
Listing 1
_get_image{} und _open_image{}
01 [...]
02 # Raspbian
03 RASPBIAN_URL=http://downloads.raspberrypi.org/raspbian/images/raspbian-2015-02-17/2015-02-16-raspbian-wheezy.zip
04 RASPBIAN_SHA1=b71d7b61f44e9bd582df71c9be494c271c97650f
05 [...]
06
07 function _get_image {
08 echo "Fetching $RASPBIAN_URL "
09 mkdir -p download
10 RASPBIAN_ARCHIVE_FILE=download/${RASPBIAN_URL##*/}
11 wget --no-verbose --continue --directory-prefix download $RASPBIAN_URL || die "Download of $RASPBIAN_URL failed"
12 echo -n "Checksum of "
13 sha1sum --strict --check - <<<"$RASPBIAN_SHA1 *$RASPBIAN_ARCHIVE_FILE" || die "Download checksum validation failed, please check http://www.raspberrypi.org/downloads"
14 unzip -q $RASPBIAN_ARCHIVE_FILE -d temp/ || die "Could not unzip $RASPBIAN_ARCHIVE_FILE"
15 }
16 [...]
17
18 function _open_image {
19 echo "Loop-back mounting" temp/*.img
20 kpartx="$(kpartx -av temp/*.img)" || die "Could not setup loop-back access to $RASPBIAN_ARCHIVE_FILE:$NL$kpartx"
21 read img_boot_dev img_root_dev <<<$(grep -o 'loop.p.' <<<"$kpartx")
22 test "$img_boot_dev" -a "$img_root_dev" || die "Could not extract boot and root loop device from kpartx output:$NL$kpartx"
23 img_boot_dev=/dev/mapper/$img_boot_dev
24 img_root_dev=/dev/mapper/$img_root_dev
25 mkdir -p mnt/img_root
26 mount -t ext4 $img_root_dev mnt/img_root || die "Could not mount $img_root_dev mnt/img_root"
27 mkdir -p mnt/img_root/boot || die "Could not mkdir mnt/img_root/boot"
28 mount -t vfat $img_boot_dev mnt/img_root/boot || die "Could not mount $img_boot_dev mnt/img_root/boot"
29 cp -a "$(type -p qemu-arm-static)" mnt/img_root/usr/bin/ || die "Could not copy qemu-arm-static"
30 echo "Raspbian Image Details:"
31 df -h mnt/img_root/boot mnt/img_root | sed -e "s#$(pwd)/##"
32 }
33 [...]
- Es übernimmt die Konfiguration für DNS, Zeitzone, Tastatur und Konsole vom Buildsystem. Falls vorhanden holt es auch die SSH-Schlüssel des Benutzers und deaktiviert zugleich den Passwortzugriff via SSH.
- Es schaltet die Noobs- [5] und Raspbian-Komponenten aus, die andernfalls beim ersten Start eine manuelle Konfiguration unterstützen.
- Es konfiguriert den DHCP-Client, um den Hostnamen per DHCP zu setzen.
- Es fügt interessante Apt-Repositories mitsamt Schlüssel-IDs hinzu, die es aus dem Buildsystem extrahiert.
- Es deinstalliert überflüssige Pakete und spielt neue ein.
- Es richtet einen Cronjob für vollautomatische Updates ein.
- Es führt per selbst gewähltem Befehl benutzerspezifische Anpassungen aus.
Im nächsten Schritt formatiert das Skript die SD-Karte und kopiert die Dateien aus dem Image darauf. So muss der Admin beim ersten Start nicht mehr die Dateisystemgröße anpassen, Abbildung 3 zeigt einen Durchlauf des Skripts.
Zur Konfiguration des Skripts dient eine optionale Datei namens »rpi-image-creator.conf« , in der die Einstellungen als Bash-Arrays liegen. Das Hauptskript »rpi-image-creator« sucht im aktuellen Arbeitsverzeichnis nach dieser Datei. Mit ihr lassen sich in Projektverzeichnissen verschiedene Konfigurationen verwalten.
Im Alltag
Das Portal Immobilienscout24 nutzt das Skript, um SD-Karten für die Raspberry Pis zu erstellen. In der verwendeten Standardkonfiguration macht es die Kleinstrechner nur mit dem firmeninternen Debian-Repository bekannt und besorgt die GPG-Schlüssel. Dann installiert es zwei Pakete. Alle weiteren Anpassungen erfolgen in den Debian-Paketen. So lassen sich die Systeme auch nach der Installation einfach aktualisieren.
In die Konfigdatei trägt der Admin bei Bedarf nur einen Shellbefehl (Listing 3) ein, der das System konfiguriert, »rpi-image-creator« führt dann das »CUSTOM_COMMAND« in der Chroot-Umgebung aus. Beim Aufruf benötigt das Hauptskript dabei einen Parameter, der das Ziel angibt. Das kann »–chroot« sein, um nach den Anpassungen eine interaktive Shell im Chroot zu erhalten, oder das Blockdevice für die SD-Karte, meist »/dev/mmcblk0« oder »/dev/sdb« . Der »–chroot« -Modus benötigt keine SD-Karte und eignet sich sehr gut zum Testen oder auch, um ein Raspbian auf dem Desktop zu starten.
Listing 3
Angepasste Konfigurationsdatei
01 [...] 02 INSTALL_PACKAGES=() 03 ADD_REPOS=() 04 ADD_REPO_KEYS=() 05 CUSTOM_COMMAND='curl http://example.com/script.sh | bash -i' 06 [...]
Trickkiste
An zentraler Stelle im Skript dient Qemu mit dem User Space Emulator [6] dazu, auf einem x86_64- oder i386-System den Binärcode des ARM-basierten Raspbian-Linux auszuführen. Dazu kopiert das Skript den Emulator »qemu-arm-static« in der »_open_image{}« -Funktion (Listing 1) in die Chroot-Umgebung und deaktiviert die »libcofi_rpi.so« -Bibliothek [7], die auf dem Pi massiv beschleunigte Speicheroperationen ermöglicht, aber unter Qemu zum Absturz führt.
Ab diesem Zeitpunkt kann der Administrator die Chroot-Umgebung trotz der ARM-Binaries wie gewohnt benutzen. Alle Programme lassen sich ganz normal ausführen, mit dem Vorteil, dass sie viel schneller als auf einem echten Raspberry Pi laufen.
Einige weitere Kniffe dienen der Performance-Optimierung. Die »_get_image{}« -Funktion (Listing 1) legt das Raspbian-Image im Downloadverzeichnis ab und erspart bei weiteren Durchläufen das erneute Herunterladen. Das Skript hängt die SD-Karte in der »_create_sdcard{}« -Funktion (Listing 2) zudem mit aktiviertem Schreibcache ein, sodass der eigentliche Kopiervorgang die Daten schnell in den Cache schreibt.
Listing 2
_create_sdcard{}
01 [...]
02 function _create_sdcard {
03 # putting it all onto SD card
04 DEST_DEVICE="$1"
05 test -b "$DEST_DEVICE" || die "Must give block device with SD Card as first parameter"
06
07 _umount mnt/img_root/{proc,sys,run,dev/pts}
08
09 echo "Preparing SD card in $DEST_DEVICE"
10 umount -f ${DEST_DEVICE}* &>/dev/null || :
11 dd if=/dev/zero of=$DEST_DEVICE bs=1M count=100 status=none || die "Could not wipe SD card in $DEST_DEVICE"
12 parted -a minimal -s $DEST_DEVICE mklabel msdos mkpart primary fat32 0mb 64mb mkpart primary ext2 64mb 100% set 1 boot on || die "Could not parted $DEST_DEVICE"
13 if [ -e ${DEST_DEVICE}p1 ] ; then sd_boot_dev=${DEST_DEVICE}p1 ; elif [ -e ${DEST_DEVICE}1 ] ; then sd_boot_dev=${DEST_DEVICE}1 ; else die "Could not find sd-card partition 1" ; fi
14 if [ -e ${DEST_DEVICE}p2 ] ; then sd_root_dev=${DEST_DEVICE}p2 ; elif [ -e ${DEST_DEVICE}2 ] ; then sd_root_dev=${DEST_DEVICE}2 ; else die "Could not find sd-card partition 2" ; fi
15 mkdir -p mnt/sd_boot mnt/sd_root
16 mkfs.vfat >/dev/null -n RASPBIAN_BOOT -F 32 $sd_boot_dev -m - <<<"This is the boot partition of a Raspbian image intended for a Raspberry Pi" || die "Could not create boot partition"
17 mkfs.ext4 -q -L raspbian_root -E discard $sd_root_dev || die "Could not create root partition"
18 tune2fs >/dev/null $sd_root_dev -o journal_data,discard || die "Could not tune2fs $sd_root_dev"
19 mount -o data=writeback,nobarrier -t ext4 $sd_root_dev mnt/sd_root || die "Could not mount $sd_boot_dev mnt/sd_boot"
20 mkdir -p mnt/sd_root/boot || die "Could not mkdir boot"
21 mount -t vfat $sd_boot_dev mnt/sd_root/boot || die "Could not mount $sd_boot_dev mnt/sd_root/boot"
22
23 echo "Copying files to SD card."
24 cp -a mnt/img_root/* mnt/sd_root/ || die "Could not copy root fs"
25
26 echo "SD Card Details:"
27 _op parted -s $DEST_DEVICE print
28 df -h mnt/sd_root/boot mnt/sd_root | sed -e "s#$(pwd)/##"
29
30 sed -i -e 's/#//' mnt/sd_root/etc/ld.so.preload || die "Could not enable ld.so.preload"
31 echo
32 echo "SD Card Creation finished, please wait for script to complete."
33 }
34 [...]
Hängt das Skript die Dateisysteme nach getaner Arbeit wieder aus, schreibt der Kernel die Blöcke mit der maximalen sequenziellen Schreibgeschwindigkeit auf die SD-Karte.
Fazit
Dank der automatischen Betankung lässt sich eine ganze Herde von Raspbis mit wenig Aufwand auf die Weide treiben. Der Komfort gleicht dem einer vollautomatischen Serverbetankung im Rechenzentrum. Wer zugleich alle Anpassungen in Pakete verpackt, den belohnen stets aktuelle Systeme. Die SD-Karten sind zwar Verschleißmaterial, lassen sich aber auch leicht ersetzen – für den Fall der Fälle liegt immer eine Ersatzkarte in der Schublade.
Infos
- Fünf Millionen Raspberry Pi verkauft (Februar 2015): http://www.raspberrypi.org/five-million-sold/
- Raspbian, das Debian für den Raspberry Pi: http://raspbian.org
- »rpi-image-creator« auf Github: https://github.com/ImmobilienScout24/rpi-image-creator
- Komplettes Listing zum Artikel: https://www.linux-magazin.de/static/listings/magazin/2015/05/rpi-image-creator/
- Noobs (New Out of Box Software): https://github.com/raspberrypi/noobs
- Qemu User Space Emulator: http://wiki.qemu.org/download/qemu-doc.html#QEMU-User-space-emulator
- Optimierte »memcpy« – und »memset« -Bibliothek für den Raspberry Pi: https://github.com/simonjhall









