Build your own raspberry pi image

Eran Goldman-Malka · August 7, 2018

I had to build a private image of raspberry pi and after a talk with my brother, I thought it worth a post

So we are going to create our own Cylon.pi distro based on Raspian and Cylon.js.

This tutorial will use the Installing Cylon.js for the Raspberry Pi guide in cylon.js website.
This tutorial is tested only on Ubuntu because that’s the system I currently use and It’s easier for me.
All the code of this tutorial will be available on a github repo.

The logic of the script is to download the last version of raspbian, extract and mount it, inject our files, unmount and compress

The image is based on 2 scripts:
Build.sh – to build the image – you run this script on your computer
first-boot.sh – to install everything on the pi – the build script injecting this script to the image and the raspbian will run it on the first reboot.

BUILD.SH

The script is split into 4 sections:
Image Constants – parameters of the image file
Installation Constants – where to do all the downloading, extracting and manipulating is happening. I recommend that it’ll be done in /tmp directory so it’ll be deleted next boot
Helpful functions – functions to print time, and manipulate text etc
The script itself – here the magic happen

I’ll focus on the building part because that the only interesting part:
We start with updating and grubbing the dependencies needed.

apt-get update
apt-get --yes install git wget curl unzip kpartx libarchive-zip-perl dos2unix

Then creating the temporary directories

mkdir -p $installation_dir
mkdir -p $installation_dir/boot $installation_dir/root

Downloading and extracting the latest raspbian

wget -nv -O $installation_dir/raspbian.zip "https://downloads.raspberrypi.org/raspbian_lite_latest" > /dev/null

unzip $installation_dir/raspbian.zip -d $installation_dir
mv $installation_dir/raspbian.img $imagefile

Than mounting the image to a temp folders

PARTITIONS=($(kpartx -asv $imagefile | grep -o 'loop[0-9][0-9]*p[0-9]'))
mount -o rw -t vfat /dev/mapper/${PARTITIONS[0]} $installation_dir/boot
mount -o rw -t ext4 /dev/mapper/${PARTITIONS[1]} $installation_dir/root

Injecting the data and files to the image

sed -i "s/127.0.1.1.*/127.0.1.1 $hostname/" $installation_dir/root/etc/hosts
touch $installation_dir/boot/ssh
echo "$hostname" > $installation_dir/root/etc/hostname

cp image_files/rc.local $installation_dir/root/etc/rc.local
cp image_files/first-boot.sh $installation_dir/boot/first-boot.sh
touch $installation_dir/boot/first-boot.log

Closing wrapping and compressing

kpartx -u $imagefile
sleep 2
sync
sleep 2
umount $installation_dir/boot
umount $installation_dir/root
kpartx -dv $imagefile

shorthash=$(git log --pretty=format:'%h' -n 1)
crc32checksum=$(crc32 $imagefile)
destination="$hostname-$timestamp-git$shorthash-crc$crc32checksum.img"

mv -v $imagefile "$destination"
rm -rf $installation_dir

xz --verbose --compress --keep "$destination"
crc32checksum=$(crc32 "$destination.xz")
mv "$destination.xz" "$hostname-$timestamp-git$shorthash-crc$crc32checksum.img.xz"

And that’s all after you finished just write the image to an SD
Any code that you put in the first-boot file will be executed when the raspbian started.
I put inside the script to generate random password because fixed image passwords are bad.
And the script to install Cylon.js

The installation script is mostly copied from the Cylon.js site

Twitter, Facebook