Het meest gebruikte besturingssysteem voor de Raspberry Pi is Raspberry Pi OS. Je kunt hier vrij eenvoudig aangepaste images van maken. Dat is handig als je meerdere Raspberry Pi’s met dezelfde configuratie wil installeren.
Koen Vervloesem
Als je voor jezelf een eenmalig project met een Raspberry Pi wilt uitvoeren, is het het gemakkelijkste als je gewoon Raspberry Pi OS installeert en dan de benodigde pakketten installeert en configureert. Maar wat als je meerdere Raspberry Pi’s op dezelfde manier wilt klaarmaken? Of als je een project wilt verspreiden zonder dat gebruikers nog zelf allerlei installatie- en configuratiestappen dienen te doorlopen?
Een van de mogelijkheden is om na de installatie van Raspberry Pi OS de verdere installatie en configuratie door een configuratiebeheertool zoals Ansible te laten uitvoeren. Als het om een intern project gaat, is dat nog wel een goede keuze, maar wil je een project publiceren, dan kun je niet veronderstellen dat alle gebruikers met Ansible overweg kunnen. Bovendien zijn sommige instellingen, zoals de configuratie van een draadloos netwerk, niet met Ansible te doen als je niet al een netwerkverbinding hebt, en misschien wil je zelfs dat je Raspberry Pi’s in een speciale netwerkconfiguratie opstarten zoals een meshnetwerk.
Aangepast image maken
Een andere oplossing is dat je een aangepast image van het besturingssysteem maakt. Je creëert dan een aangepaste versie van Raspberry Pi OS, waarin je alle benodigde software al installeert en ook al je aangepaste instellingen toepast. Het resultaat is een image dat je naar een micro-sd-kaartje kunt schrijven zoals je dat met de standaard Raspberry Pi OS doet.
Als je dan al je Raspberry Pi’s met deze aangepaste configuratie wilt laten opstarten, hoef je alleen maar je eigen image naar meerdere micro-sd-kaartjes te schrijven en deze een voor een in de Raspberry Pi’s te steken. Zo ben je ook zeker dat ze allemaal exact dezelfde softwareversies en exact dezelfde instellingen hebben. Dat voorkomt al heel wat lastig op te lossen problemen.
Pi-gen
De makers van de Raspberry Pi zijn zo vriendelijk om hun eigen tool te publiceren waarmee zij de officiële images van Raspberry Pi OS maken: pi-gen. Pi-gen draait op Debian Buster en Ubuntu Xenial en later, maar op andere Linux-distributies kun je het ook als Docker-container draaien.
Download eerst de laatste versie van pi-gen van GitHub:
git clone https://github.com/RPi-Distro/pi-gen.git cd pi-gen
Installeer dan de afhankelijkheden. Op Ubuntu 20.04 gaat dat als volgt:
sudo apt install coreutils quilt parted qemu-user-static debootstrap zerofree zip \ dosfstools libarchive-tools libcap2-bin grep rsync xz-utils file git curl bc
Eerste image
De configuratie van pi-gen gebeurt in het bestand config, dat je nog zelf dient aan te maken. Daarin geef je een aantal omgevingsvariabelen een waarde. De enige die verplicht is, is IMG_NAME:
IMG_NAME=raspios
Het is ook aan te raden om een apt-proxy te draaien zodat het buildscript niet telkens dezelfde pakketbestanden opnieuw downloadt. Draai je al een apt-proxy zoals apt-cacher-ng, dan verwijs je naar het IP-adres van je apt-proxy in de omgevingsvariabele APT_PROXY:
APT_PROXY=http://192.168.0.128:3142
Wijzig dit naar jouw situatie. Draai je nog geen apt-proxy, dan kun je er eenvoudig een opstarten met het bij pi-gen meegeleverde Docker Compose-bestand, en daarnaar verwijzen in de configuratie:
docker-compose up -d echo 'APT_PROXY=http://172.17.0.1:3142' >> config
Daarna dien je de keuze te maken of je een Lite-systeem wilt, een systeem met desktop of zelfs nog extra pakketten erbij. In dit artikel gaan we ervan uit dat je een Lite-systeem wilt aanpassen. Maak daarom enkele lege bestanden aan om de latere stadia over te slaan:
touch stage3/SKIP stage4/SKIP stage5/SKIP touch stage4/SKIP_IMAGES stage5/SKIP_IMAGES
Waarschijnlijk wil je voor je eigen image ook geen NOOBS-image. Dan moet je nog een bestand verwijderen:
rm stage2/EXPORT_NOOBS
Na deze basisconfiguratie kun je het image bouwen:
sudo ./build.sh
Dit kan nu wel een half uurtje duren. Als alles goed gaat, krijg je op het einde een gezipt image in de map deploy, van rond de 438 MB groot. Omdat we niets essentieels aangepast hebben, is het exact hetzelfde als een Raspberry Pi OS Lite-image dat je van de website van de Raspberry Pi zou downloaden, alleen dan met nieuwere softwareversies.
Aangepaste configuratie
Pi-gen ondersteunt nog enkele basisinstellingen in het bestand config. De belangrijkste zijn de volgende, die de juiste toetsenbordindeling en tijdzone instellen (hier een voorbeeld voor België):
KEYBOARD_KEYMAP=be KEYBOARD_LAYOUT=Belgian TIMEZONE_DEFAULT=Europe/Brussels
Verder kun je ook de hostname instellen:
TARGET_HOSTNAME=raspberrypi
Ga je meerdere Raspberry Pi’s met dit image in je netwerk draaien, dan kun je beter de hostname na het opstarten instellen.
Als je wilt dat je Raspberry Pi bij het opstarten automatisch met je wifi-netwerk verbindt, dan kun je je land, ssid en wpa-wachtwoord invoeren:
WPA_COUNTRY=BE WPA_ESSID=MijnSSID WPA_PASSWORD=MijnWachtwoord
Je kunt ook de standaard gebruikersnaam (pi) en wachtwoord (raspberry) aanpassen:
FIRST_USER_NAME=koen FIRST_USER_PASS=SterkWachtwoord1234
En voor SSH zijn er ook enkele interessante omgevingsvariabelen:
PUBKEY_SSH_FIRST_USER=ssh-rsa AAAAB3NzaC1yc... PUBKEY_ONLY_SSH=1 ENABLE_SSH=1
Aan de eerste variabele ken je de publieke sleutel van je gebruiker toe. Met de tweede variabele stel je in dat je alleen kunt inloggen via SSH via je geheime sleutel die bij de voorgaande publieke sleutel hoort, en met de derde variabele schakel je SSH in.
Je kunt je image met deze aanpassingen nu weer bouwen.
Geïnstalleerde pakketten aanpassen
De installatie van pakketten en bijbehorende configuratie gebeurt in pi-gen in 6 stadia van stage0 tot en met stage5. Een Lite-systeem doorloopt stage0, stage1 en stage2. Zo vind je in de map stage2 alle taken die pi-gen uitvoert om van een minimaal systeem (stage1) een Lite-systeem (stage2) te maken. In elk stadium vind je verschillende mappen met scripts, die alfabetisch uitgevoerd worden. Zo worden eerst de scripts in 00-copies-and-fills uitgevoerd, daarna die in 01-sys-tweaks, daarna die in 02-net-tweaks enzovoort.
In elk van die mappen staan diverse bestanden die elk ook weer alfabetisch worden verwerkt. De volgende bestanden zijn mogelijk:
Wil je niet alle pakketten installeren die een Lite-systeem normaal heeft, kijk dan eens in stage2/01-sys-tweaks/00-packages en verwijder wat je niet nodig hebt. Heb je bijvoorbeeld geen ontwikkeltools nodig, dan kun je gerust pakketten zoals build-essentialen gdb uit de lijst verwijderen.
Door de cijfers in het begin van de bestandsnamen aan te passen, kun je de volgorde wijzigen, maar in de meeste gevallen is die goed. Wil je bijvoorbeeld eerst afhankelijkheden van een te compileren programma installeren en dan het programma compileren, dan zet je de afhankelijkheden in 00-packages en voer je de compilatie uit in 00-run.sh. Maar kun je die afhankelijkheden pas installeren nadat je eerst een repository hebt toegevoegd, doe dat laatste dan in 00-run.sh, installeer de afhankelijkheden in 01-packages en compileer het programma in 01-run.sh.
Node-RED installeren
Een voorbeeld: we gaan een image maken waarin je Node-RED installeert uit de repository van het project (de versie in Raspberry Pi OS is ouder). Maak daarvoor in de map stage2 een map 04-install-nodered aan met als inhoud twee bestanden. In 00-packages zetten we de afhankelijkheden:
git npm
Volgens de instructies heeft Node-RED ook het pakket build-essential nodig, maar dat wordt al geïnstalleerd dankzij stage2/01-sys-tweaks/00-packages.
Daarna komt het installatiescript 00-run.sh:
#!/bin/bash -e # Install Node-RED on_chroot <<EOF su - pi -c "bash <(curl -sL https://raw.githubusercontent.com/node-red/linux-installers/master/deb/update-nodejs-and-nodered) --confirm-install --confirm-pi" EOF
Omdat we de installatie in de chroot van het te bouwen systeem willen uitvoeren, moeten we het script tussen on_chroot <<EOF en EOF zetten. In de installatie-instructies van Node-RED staat dat je het pakket installeert met de volgende opdracht:
bash <(curl -sL https://raw.githubusercontent.com/node-red/linux-installers/master/deb/update-nodejs-and-nodered)
Maar dat is een interactieve installatie, terwijl ons buildscript niet interactief mag zijn. Daarom voegen we de opties –confirm-install en –confirm-pi toe. Bovendien willen we dit als gebruiker pi uitvoeren, dus daarom de su – pi -c om bash als de gebruiker pi uit te voeren.
Dan rest je alleen nog om het script uitvoerbaar te maken:
chmod +x 00-run.sh
Als je nu je image bouwt, heb je Raspberry Pi OS Lite met Node-RED voorgeïnstalleerd.
Python-modules installeren
Op dezelfde manier installeer je andere pakketten. Wil je bijvoorbeeld specifieke Python-modules installeren, installeer dan eerst de afhankelijkheden (zoals python3-pip) in 00-packages, en installeer dan in het script 00-run.sh de modules met pip3, bijvoorbeeld:
#!/bin/bash -e # Install Node-RED on_chroot <<EOF sudo pip3 install bluepy EOF
Systemd-services inschakelen
Een andere veel voorkomende taak is dat je specifieke systemd-services wilt installeren en inschakelen. Stel dat je bijvoorbeeld een script wilt installeren dat een aangesloten sensor uitleest en de gegevens naar een server zoals ThingsBoard stuurt. Creëer dan het systemd-script sensor_upload.service in een map files in de map waarin je 00-run.sh staat.
In je 00-run.sh installeer je dan het bestand naar de juiste locatie op het rootbestandssysteem en schakel je de service in:
install -m 644 files/sensor_upload.service "${ROOTFS_DIR}/lib/systemd/system/" on_chroot << EOF systemctl enable sensor_upload.service EOF
Merk op: de opdracht install hoeft niet in de chroot, want die verwijst naar bestanden op je ontwikkelsysteem. Het inschakelen van de systemd-service dient wel in de chroot te gebeuren.
Conclusie
Al met al is pi-gen een handige tool om je eigen images voor de Raspberry Pi te maken. Omdat met dezelfde tool de officiële images van Raspberry Pi OS worden gemaakt, blijf je altijd dicht bij de standaardinstallatie van een Raspberry Pi. En dankzij het gebruik van shellscripts kun je echt alles automatiseren.