Pioreactor dev blog #11 - creating custom Raspberry Pi images

Pioreactor dev blog #11 - creating custom Raspberry Pi images

We care a lot about onboarding. I've seen enough Raspberry Pi projects that seem to require deep experience in software compilers and package management (don't worry if you don't know what those are...) before you can get started. This is an immediate barrier to your project! From a "funnel" perspective, you may end up losing up a large fraction of your users just at this stage. Can we do better?

Pioreactor onboarding 1.0

From the start of Pioreactor, we've attempted to simplify onboarding for users. We managed to get it down to the following:

  1. Flash the Raspberry Pi OS image to your SD card. Use the crtl-shift-x "trick" to add your WIFI credentials. (Which, by the way, should definitely not be a hidden menu.)
  2. Once SD card is flashed, add to your Raspberry Pi and boot. 
  3. SSH into the Raspberry Pi, and paste a one-line bash script that we provide.
  4. Mid way through the install, you're asked for a new hostname for the Pioreactor - provide it. 
  5. Wait for the installation to finish, about 10 minutes. The Raspberry Pi will reboot, and our onboard LED will flash when ready. 

That's not bad, except for point 3. Asking people to SSH in was always a worry - they need to download some networking software to perform this, know about hostnames and password (that don't show up when you type), and be comfortable executing on the command line. It was all just a bit too much to ask. 

💡 What is a "Raspberry Pi image" anyways? Think of it as an entire operating-system-as-a-file that can be downloaded, and otherwise moved around. To "flash" an image onto an SD card means to move the image onto the SD card so that another computer (like a Raspberry Pi) can read it.

Pioreactor onboarding 2.0

Coming out of the excellent OctoPrint project, the CustoPizer program is a clean and easy way to programatically modify an existing Raspberry Pi image. So, from an official Raspberry Pi OS image, CustoPizer will virtually boot it, execute scripts that install software, create files, etc., and return a new image that can be loaded onto a Raspberry Pi. The Raspberry Pi now has access to that installed software, files, etc.! See Figure 1 below. 

We have forked their project and moved all our installation scripts from the main Pioreactor repository to our custom fork. Under the workspace directory, we have all of our installations scripts organized by topic. 

Since we have three roles (leader, worker, and leader-is-also-a-worker, read more about roles here), not all software is needed for some roles. We pass in environment variables to CustoPizer that will conditionally add software if needed (example of using environment variables here). 

In the end, we have three custom Pioreactor images that users can immediately load into their Raspberry Pis. So what does the new onboarding look like? 

  1. Flash the Pioreactor image to your SD card. Use the crtl-shift-x "trick" to add your WIFI credentials, and desired hostname. 
  2. Once SD card is flashed, add to your Raspberry Pi and boot. 
  3. Our onboard LED will flash when ready.

That's it! No more ssh-ing, no more post-installation, it's all done automagically! This also makes adding new Pioreactors to an existing cluster much easier, too. 

Figure 1. High level overview of the pipeline to transform official RPi images into Pioreactor images. 

A caveat: not everything can be pre-installed!

One catch is that we are distributing identical images, so any sensitive or unique information on the original image we be copied everywhere. This means that some things can't be pre-installed, but has to happen on the Rasbperry Pi's first boot. SSH credentials are a good example of this, or anything that relies on the hostname (which we don't know at image-creation time). We solve this by adding a first-boot script to the image, which runs on the first boot of the Raspberry Pi (here's an example). There is an associated systemd service file that runs the first boot script, and then renames the first-boot script so that the service never successfully runs again. This is a bit hacky, but it works well! 

Conclusion

We've had lots of success in this approach - our "time to first user experiment" is down significantly, and Pioreactor onboarding seems easier than ever. We thank the OctoPrint team for opensourcing the CustoPizer project!