I create my device OS images on Mac and Linux systems but all of this can obviously be done from other OS as well. The Raspbian install documentation has all the basic information for creating images on all 3 major OS.
I recommend Raspbian Stretch Lite. This is way more than enough OS to accomplish our goals. In the future, it will be interesting to explore RancherOS or Alpine linux as the base image. For now:
- Download the Raspbian Stretch Lite image
- Copy the image to the sdhc card according to rapbian docs and don’t insert it into the Pi yet.
Mount the image
There is plenty of documentation on how to mount an image. On my computer, I mount it to
/mnt/boot so I’ll use that path in the documentation below to refer to the location that the SD card is mounted to.
Keep it small
More recent versions of Raspbian are configured to automatically expand the file system to the full size of the underlying disk capacity. Eventually, we are going to stamp multiple SD cards with the same bits and for this, we want the smallest possible image. Let’s open up the
cmdline.txt file and disable the auto expand file system capability. Remove the
init=/usr/lib/raspi-config/init_resize.sh argument. The file content will look like this after removal.
dwc_otg.lpm_enable=0 console=serial0,115200 console=tty1 root=PARTUUID=7ee80803-02 rootfstype=ext4 elevator=deadline fsck.repair=yes rootwait quiet
Since the cmdline.txt file is already open, it’s a good time to add
dwc_otg.lpm_enable=0 console=serial0,115200 console=tty1 root=PARTUUID=7ee80803-02 rootfstype=ext4 elevator=deadline fsck.repair=yes rootwait cgroup_memory=1 cgroup_enable=memory quiet
While the SD card is still mounted on the file system, let’s add a few items so we can access the Raspberry Pi with ssh over a wireless connection.
Let’s create a configuration file for wpa_supplicant. This requires a network SSID and passphrase.
If the host OS has the
wpa_passphrase command we can encrypt the psk now but if not, put in the plain text for now and I’ll share the command to encrypt it at the end of the 1st boot cycle.
wpa_supplicant.conf file directly to the root of the
/mnt/boot volume on the SD card.
Also on the
boot volume, add a plain text file called ssh.
When the operating system first boots up, this empty
ssh file is the instruction to the OS to also start the ssh daemon. This only needs to be done once.
Now that we have wifi access and ssh prepped and ready to go, unmount the device
sudo umount /mnt/boot . Remove the card from the computer and insert it into the Raspberry Pi. Start the Pi.
From a terminal
ssh email@example.com password
.local domain only works with systems that support mDNS. You may need to find the IP address of your device and use that instead.
Setup hostname configuration
In order to make this image useful as a node in a cluster of Raspberry Pis, we will want each device to have a unique hostname. The following service description allows us to drop a
hostname file in the boot directory and restart the device with the new hostname.
sudo vi /lib/systemd/system/raspberrypi-hostname.service
Description=Copy user (/etc/)hostname
ExecStart=/bin/mv /boot/hostname /etc/hostname
ExecStartPost=/bin/chmod 644 /etc/hostname
ExecStartPost=/bin/hostname --file /etc/hostname
Create a soft link to the hostname service as a dependency in the multi-user target for systemd
ln -s /lib/systemd/system/raspberrypi-hostname.service /etc/systemd/system/multi-user.target.wants/raspberrypi-hostname.service
Create a file
hostname with the hostname of the base image.
On reboot, we can now access the device using the hostname which was set in that file e.g.:
Is it really necessary to setup hostname modification in this way? The option to ssh into the device and modify the hostname directly via the
hostname command is still a possibility. I’m doing it this way because a) I can change the hostname immediately after imaging an SD card by adding the file to the boot dir (think automation) and b) I envision a scenario in which the master is capable of easily communicating to another device everything it needs to reboot as an agent.
Add the k3s runtime binaries
k3s right to the device. For my image, I went ahead and downloaded both the
arm64 versions. This way I can use it in a variety of devices.
curl -L -O https://github.com/ibuildthecloud/k3s/releases/download/v0.1.0-rc3/k3s-arm64
curl -L -O https://github.com/ibuildthecloud/k3s/releases/download/v0.1.0-rc3/k3s-armhf
chmod 755 k3s-arm*
Let’s add a security measure to the wireless configuration file. Previously we set a plain text passphrase in the configuration which is obviously less secure. The Raspbian image ships with wpa supplicant tools which can assist in setting up a secure config file.
sudo bash -c \
'wpa_passphrase MYSSID passphrase > /boot/wpa_supplicant.conf'
sudo vi /boot/wpa_supplicant.conf and delete the line with the plain text password.
#psk="passphrase" <--- DELETE THIS LINE