Even without Ansible or other config management tool, there's no
reason any of those steps need to be manual: you could drive
everything with a shell script, thus reaping all the benefits of
automation: no more errors, consistent deployments, and faster
configuration. Using Ansible can help make the process more modular
and more structured, but it doesn't fundamentally allow you to do
anything new.
Ignoring the question of what tooling you use to drive the
configuration, I'd like to suggest an option that you may not have
considered: it's possible to perform all the configuration on the image before burning it onto a microsd card. You can mount the raspberry pi os image on a local directory, and then make all your configuration changes there. I use a process like this:
Download and unzip the raspberry pi os image
Make a working copy of the image (this way you can re-use the base
image multiple times to create different configured images):
# cp 2022-01-28-raspios-bullseye-armhf-lite.img work.img
I like to extend the image a bit so there's room for installing
new software:
# truncate -s 2500MB work.img
Attach the work image to a loop device:
# losetup -fnP --show work.img
/dev/loop0
Grow the filesystem to use the additional space:
# parted /dev/loop0 resizepart 2 100%
# e2fsck -f /dev/loop0p2
# resize2fs /dev/loop0p2
Mount the filesystems locally:
# mount /dev/loop0p2 /mnt
# mount /dev/loop0p1 /mnt/boot
Now you're in a position where you can create and modify configuration
files on the image, in order to...
- Configure networking
- Configure the hostname
- Enable ssh
- Configure wifi
- Install ssh keys
- Etc.
But what if you want to do other things, like update or install
packages? If you install the qemu-user-static
package and properly
configure the binfmt_misc
module (modern versions of the
qemu-user-static
package will do this for you automatically), you will be
able to run Raspberry Pi binaries on your host. This allows you to run
commands inside the image, like this:
# systemd-nspawn -D /mnt apt update
# systemd-nspawn -D /mnt apt upgrade -y
# systemd-nspawn -D /mnt apt install -y git
Or inject a shell script:
# systemd-nspawn -D /mnt --bind=$PWD/config.sh:/config.sh sh /config.sh
Here I'm using systemd-nspawn
, which is a little like chroot
(in
this example), except it takes care of mounting special
filesystems like /sys and /proc and has all sorts of interesting
options (like the --bind
option for bind mounting files or
directories into the image).
When you're all done, unmount the filesystem and disconnect the loop
device:
# umount /mnt/boot /mnt
# losetup -d /dev/loop0
And write the customized image to an sd card:
# dd if=work.img of=/dev/sdb bs=4M
You can wrap the entire process described here in a script, and have
it take parameters to configure networking (specify a static address
or use dhcp), etc.