<p>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.</p>
<hr />
<p>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 <em>before</em> 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:</p>
<ol>
<li><p>Download and unzip the raspberry pi os image</p>
</li>
<li><p>Make a working copy of the image (this way you can re-use the base
image multiple times to create different configured images):</p>
<pre><code># cp 2022-01-28-raspios-bullseye-armhf-lite.img work.img
</code></pre>
<p>I like to extend the image a bit so there's room for installing
new software:</p>
<pre><code># truncate -s 2500MB work.img
</code></pre>
</li>
<li><p>Attach the work image to a loop device:</p>
<pre><code># losetup -fnP --show work.img
/dev/loop0
</code></pre>
</li>
<li><p>Grow the filesystem to use the additional space:</p>
<pre><code># parted /dev/loop0 resizepart 2 100%
# e2fsck -f /dev/loop0p2
# resize2fs /dev/loop0p2
</code></pre>
</li>
<li><p>Mount the filesystems locally:</p>
<pre><code># mount /dev/loop0p2 /mnt
# mount /dev/loop0p1 /mnt/boot
</code></pre>
</li>
</ol>
<hr />
<p>Now you're in a position where you can create and modify configuration
files on the image, in order to...</p>
<ul>
<li>Configure networking</li>
<li>Configure the hostname</li>
<li>Enable ssh</li>
<li>Configure wifi</li>
<li>Install ssh keys</li>
<li>Etc.</li>
</ul>
<p>But what if you want to do other things, like update or install
packages? If you install the <code>qemu-user-static</code> package and properly
configure the <code>binfmt_misc</code> module (modern versions of the
<code>qemu-user-static</code> 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:</p>
<pre><code># systemd-nspawn -D /mnt apt update
# systemd-nspawn -D /mnt apt upgrade -y
# systemd-nspawn -D /mnt apt install -y git
</code></pre>
<p>Or inject a shell script:</p>
<pre><code># systemd-nspawn -D /mnt --bind=$PWD/config.sh:/config.sh sh /config.sh
</code></pre>
<p>Here I'm using <code>systemd-nspawn</code>, which is a little like <code>chroot</code> (in
this example), except it takes care of mounting special
filesystems like /sys and /proc and has all sorts of interesting
options (like the <code>--bind</code> option for bind mounting files or
directories into the image).</p>
<hr />
<p>When you're all done, unmount the filesystem and disconnect the loop
device:</p>
<pre><code># umount /mnt/boot /mnt
# losetup -d /dev/loop0
</code></pre>
<p>And write the customized image to an sd card:</p>
<pre><code># dd if=work.img of=/dev/sdb bs=4M
</code></pre>
<hr />
<p>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.</p>

CC BY-SA 4.0
2022-05-09T11:29:17.683Z
Thank you very much for your answer, this is very useful.
Postie
CC BY-SA 4.0
2022-05-06T02:54:04.473Z
2022-05-06T02:54:04.473Z
larsks
<p>For multiple projects we are setting up 2 to 6 RPi's per project. Each project runs on a different network and for some of these networks we can use DHCP, for others the RPi's have to connect using a static IP address.</p>
<p>Also every RPi needs a different hostname in sequential order. For instance for a project with three RPi's, the hostnames need to be PROCCESS1, PROCESS2, PROCESS3.</p>
<p>All RPi's run the exact same software and every RPi has a single monitor connected.</p>
<p>The current workflow is:</p>
<ol>
<li>Burn a prepared OS image for every RPi on a microSD</li>
<li>Boot up the RPi using the microSD and manually set the hostname</li>
<li>If needed, set the IP address to a static one</li>
<li>Turn on the overlay file system so the system is read-only</li>
<li>Repeat for the amount of RPi's needed</li>
</ol>
<p>This is a tedious task where errors are made and takes a lot of time. Step 1 can not be automated, since we don't have the hardware (altough the EtcherPro would eventually save a lot of time). Automating step 3 and 4 would be great if that can be realized. I've read a bit about Ansible and also encountered Chef and Puppet but I haven't dived into any of them yet.</p>
<p>Is using Ansible with playbooks a good direction to develop further? Would it be possible to automate the setup using this tool? Is there a better/easier solution or would it not be possible at all? If someone has some tips or can guide in the right direction that would be great.</p>

<ansible><deployment><chef><raspberry-pi-os>
Setup multiple Raspberry Pi different network configurations
Postie
# Setup multiple Raspberry Pi different network configurations

(Asked by: username_0 on 2022-05-05)

For multiple projects we are setting up 2 to 6 RPi's per project. Each project runs on a different network and for some of these networks we can use DHCP, for others the RPi's have to connect using a static IP address.

Also every RPi needs a different hostname in sequential order. For instance for a project with three RPi's, the hostnames need to be PROCCESS1, PROCESS2, PROCESS3.

All RPi's run the exact same software and every RPi has a single monitor connected.

The current workflow is:

1. Burn a prepared OS image for every RPi on a microSD
2. Boot up the RPi using the microSD and manually set the hostname
3. If needed, set the IP address to a static one
4. Turn on the overlay file system so the system is read-only
5. Repeat for the amount of RPi's needed

This is a tedious task where errors are made and takes a lot of time. Step 1 can not be automated, since we don't have the hardware (altough the EtcherPro would eventually save a lot of time). Automating step 3 and 4 would be great if that can be realized. I've read a bit about Ansible and also encountered Chef and Puppet but I haven't dived into any of them yet.

Is using Ansible with playbooks a good direction to develop further? Would it be possible to automate the setup using this tool? Is there a better/easier solution or would it not be possible at all? If someone has some tips or can guide in the right direction that would be great.

**Tags:** ansible, deployment, chef, raspberry-pi-os


---

## 1 answers

### Answer by username_1 on 2022-05-06. Score: 2 | Accepted answer

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.

> **Comments:**
> **username_0**: Thank you very much for your answer, this is very useful.  

---

