Update: Es gibt eine viel bessere und aktuellere Beschreibung wie man eine Raspberry simulieren kann auf diese Seite.
1. Schnellstart
1.1 Installation von QEMU
sudo apt-get install kvm qemu
1.2 Download eines Raspbianimages und des Linux kernels für qemu (wheezy or stretch)
a) wget 2012-12-16-wheezy-raspbian/2012-12-16-wheezy-raspbian.zip
Entsprechendes qemu kernel downloaden von https://github.com/dhruvvyas90/qemu-rpi-kernel. Für Wheezy ist es
curl -L wget https://github.com/dhruvvyas90/qemu-rpi-kernel/blob/master/kernel-qemu-3.10.25-wheezy > kernel-qemu
1.3 Anpassen des Images so dass es mit qemu startet
Von der Ausgabe des Befehls muss der Startsektorwert der zweiten Partition mit 512 multipliziert werden und das ist dann der Offset im folgenden Befehl
b) sudo mount 2012-12-16-wheezy-raspbian.zip -o offset=62914560 /mnt
c) sudo nano /mnt/etc/ld.so.preload
Die eine Zeile in der Datei muss auskommentiert werden mit einem # als erstes Zeichen in der Zeile
d) sudo umount /mnt
1.4 Starten des Images
1.5 Anmelden und Konfigurieren
2. Erweiterung der virtuellen Platte
2.1 Erstellung einer virtuellen Platte im Format qcow
2.2 Vergrößerung der virtuellen Platte
2.3 Erstellen von /dev/mmcblk0px
KERNEL=="sda?", SYMLINK+="mmcblk0p%n"
KERNEL=="sda2", SYMLINK+="root"
3. Script um ein Image für qemu vorzubereiten
Wer häufiger Images konvertieren muss kann auch das folgende von mir geschriebene Script benutzen. Es konvertiert ein img in qcow2, vergrößert das image und nimmt die oben beschriebenen notwendigen Änderungen vor um das Image dann in qemu starten zu können.
4. Netzwerkanbindung des Images
Damit qemu über das Hostsystem ins externe Netzwerk zugreifen kann muss auf dem Hostsystem eine Brücke existieren und ein existierendes Netzwerkinterface eth0 muss an einer Brücke hängen. Dazu habe ich folgende Definitionen in /etc/network/interfaces vorgenommen
auto lo
iface lo inet loopback
auto eth0
iface eth0 inet manual
auto br0
iface br0 inet dhcp
bridge_ports eth0
bridge_stp off
bridge_fd 0
bridge_maxwait 0
5. Start eine Images
Ich möchte, dass mein Image immer dieselbe MAC Adresse erhält, so dass der Homerouter ihm immer dieselbe IP Adresse per DHCP vergibt. Dazu benutze ich folgendes Script mit dem Namen start.sh
#!/bin/bash
DIR=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )
F=$DIR/macdict.txt
found=0
if [ -e $F ]; then
if grep -q "^$1 " $F; then
mac=$(grep "^$1 " $F | cut -d ' ' -f 2)
found=1
echo "Reusing mac $mac for $1"
fi
fi
if (( ! found )); then
# generate a random mac address for the qemu nic
mac=$(printf 'DE:AD:BE:EF:%02X:%02X\n' $((RANDOM%256)) $((RANDOM%256)))
echo "$1 $mac" >> $F
echo "Generated mac $mac for $1"
fi
sudo qemu-system-arm -kernel $DIR/kernel-qemu -cpu arm1176 -m 256 -M versatilepb -no-reboot -append "root=/dev/sda2 panic=1" -hda $DIR/$1 -net nic,macaddr=$mac -net tap
Quellen für diesen Artikel
HOWTO: Virtual Raspbian on Qemu in Ubuntu Linux 12.10
Emulate a Raspberry Pi with Qemu+ KVM
Howto setup Raspberry Pi emulation with QEMU on LInux or Windows
KVM/ARM: The Design and Implementation of the Linux ARM Hypervisor
qemu-rpi-kernel: git repository mit rpi kernels
Raspbian on QEMU with network access
Erfahrungen mit der QEMU Emulation und Raspberry
Die Emulation wird primär dazu eingesetzt das Tool raspiBackup.sh zu testen. Beim Test des Restores des erstellten Backups ist es notwendig direkt auf das neue leere Image vom Host zuzugreifen. Das funktioniert auch gut mit den folgenden Befehlen
sudo losetup -d /dev/loop0
sudo losetup /dev/loop0 raspiBackupRestore.img
kpartx -av /dev/loop0
Danach kann man auf /dev/loop0 vom Host zugreifen und das Backup restoren. Allerdings gabe es beim restore des tar und rsync Backups beim Booten der restoreten VM immer Filesystemfehler. Das dd Backup konnte aber dagegen ohne Probleme gestartet werden. Nach längerem Debuggen fand ich raus warum es das Problem gab: Da ich immer ein ziemlich altes Standard raspbian Image benutze um es zu backuppen dachte das Image beim booten immer es würde momentan Anno 2014 gestartet werden (Jetzt ist es 2015). Da tar bzw rsync restore das Filesystem im Image mit dem aktuellsten Datum versah stellte das Image immer beim Booten fest, das das Filesystem in der Zukunft geändert wurde und verlangte ein fsck. Da beim dd restore das Filesystem nicht geändert wurde trat der Fehler dort nicht auf. Die Lösung des Problems war am Ende des restores noch folgende Aktionen auszuführen
mount /dev/loop0p2 /mnt
echo $(date +"%Y-%m-%d %T") > /mnt/etc/fake-hwclock.data
umount /mnt
Damit wird die fake-hwclock des alten Raspbian Images auf die aktuelle Zeit gesetzt und es startet nicht mehr Anno 2014 sondern in der aktuellen Zeit wo das Backup restored wurde.
Raspberry Emulation in einem Docker Container
Wer eine Raspberry in einem Docker Container starten will kann auf dieses git Respository von Luke Childs - dockerpi - zugreifen. Dort findet sich ein Dockerfile und README in dem beschrieben wird wie man das Dockerimage baut und nutzt. Man kann beliebige Images nutzen. Default ist ein Busterimage 2019-09-26-raspbian-buster-lite. Zugang bekommt man entweder per ssh über den lokalen Port 5022 oder direkt auf der Konsole. Für raspiBackup kann ich es leider nicht nutzen da /dev/mmcblk0p1 incl /boot fehlt und nur /dev/mmcblk0p2 als Root existiert.
Es ist aber ein voll funktionsfähiges Original Buster RaspianOS.

