Running Raspbian on x86 docker
Setting up a cross compilation environment is quite tedious and it is much easier to rebuild a software natively on raspberry pi, but what if you don’t have on pi spare next to you or if you want to automate the build process on a generic x86 server.
Hopefully, the binfmt_mis
Linux kernel module allows to register interpreters for various binary formats based on a magic number. In conjonction with the qemu-user-static
user-space emulator for arm, it allows us to create a docker image
of the arm raspbian distribution which can run on a directly x86 desktop or server.
Installing Docker on an Ubuntu x86 host
Fist install binfmt-support and qemu-user-static on the x86 host. On Ubuntu LTS 14.04:
sudo apt-get update && sudo apt-get install -y binfmt-support qemu qemu-user-static
# check your ability to emulate the binary formats by checking for ARM support
sudo update-binfmts --enable qemu-arm
sudo update-binfmts --display | grep arm
Building arm/raspbian docker image for x86 with qemu
Use the following script to download the image from raspberrypi.org and convert if to a docker image.
Get the rpi-build-docker-img script.
#!/bin/bash
#
# Create a docker image raspbian distribution image for raspberry-pi
#
# Change the SRC path if needed:
SRC=https://downloads.raspberrypi.org/raspbian_lite_latest
set -e
sudo echo Info: Need root access to mount the image to extract the content
mkdir raspbian-tmp
cd raspbian-tmp
echo Download image...
wget --trust-server-names $SRC
unzip *.zip && rm *.zip
DISK_IMG=$(ls *.img | sed 's/.img$//')
OFFSET=$(fdisk -lu $DISK_IMG.img | sed -n "s/\(^[^ ]*img2\)\s*\([0-9]*\)\s*\([0-9]*\)\s*\([0-9]*\).*/\2/p")
mkdir root
sudo mount -o loop,offset=$(($OFFSET*512)) $DISK_IMG.img root
# Disable preloaded shared library to get everything including networking to work on x86
sudo mv root/etc/ld.so.preload root/etc/ld.so.preload.bak
# Copy qemu-arm-static in the image be able to interpret arm elf on x86
if /usr/bin/qemu-arm-static -version | grep 2.0.0;
then
# Fix crash with `tcg.c:1693: tcg fatal error` by using a more recent version
wget https://jguiraudet.github.io/assets/bin/qemu-arm-static
chmod 755 ./qemu-arm-static
sudo cp ./qemu-arm-static root/usr/bin
else
sudo cp /usr/bin/qemu-arm-static root/usr/bin
fi
# Create docker images
cd root
sudo tar -c . | sudo docker import - jguiraudet/raspbian-lite-for-x86_64:$DISK_IMG
cd ..
# Clean-up
sudo umount root
rmdir root
rm $DISK_IMG.img
sudo docker images | grep raspbian
echo Test the image with:
echo docker run -ti --rm jguiraudet/raspbian-lite-for-x86_64:$DISK_IMG /bin/bash -c \'uname -a\'
if docker run -ti --rm jguiraudet/raspbian-lite-for-x86_64:$DISK_IMG /bin/bash -c 'uname -a' | grep armv7l; then echo OK; else echo FAIL; fi
Performance
The raw CPU performance on the emulation is slightly slower that when running on the native but has the great advantage to be able to run on any server to automate build or image modification.
I used sysbench as descripbe bellow to benchmark the three configuration.
sudo apt-get update && sudo apt-get install -y sysbench
sysbench --test=cpu --cpu-max-prime=2000 run
grep Revision /proc/cpuinfo
(See table to interpret the /proc/cpuinfo on raspberry-pi)
Results:
system | sysbench Total time |
---|---|
Host native (i7 6 cores) | 1.1145s |
raspeberry-pi native (Model B+ ARMv6/512MB) | 54.3638s |
qemu-arm | 60.7251s |
References
- Using qemu-user-static with root for a raspbian image can be found here and here
- Qemu User Emulation
- How to benchmark your system cpu with sysbench
Issues
Update: I encounter a crash with tcg.c:1693: tcg fatal error
while cloning a git tree with qemu-user-static 2.0.0+dfsg-2ubuntu1.22. This is apparently a known issue. See: https://patches.linaro.org/patch/32473/.
The issue doesn’t occurs with qemu-arm-static of Ubuntu 15.10 (A copy is stored at http://jguiraudet.github.io/assests/bin/qemu-arm-static)