> [!tip] > Podman Desktop for Windows/WSL2 can replace Docker Desktop. The Podman [Windows guide](https://podman.io/getting-started/installation#windows) walks through installing and exposing the Podman service to WSL2. Building Raspberry Pi images on an x86 server or desktop lets you automate builds without a physical Pi nearby. Podman's `--platform` support and `qemu-user-static` binfmt handlers emulate ARM, so you can target the same architecture that runs on Pi 3/4/5 as well as older Pi Zero/1/2 models. | Raspberry Pi model | Target platform | Notes | | --- | --- | --- | | Pi 3B+, 4, 5, Zero 2 W | `linux/arm64` | Modern 64-bit firmware. Use the same containerfile as on the Pi. | | Pi Zero, Pi 1, Pi 2 | `linux/arm/v7` | 32-bit-only. Requires explicit binfmt registration for `arm/v7`. | ## Requirements - **x86 Linux host:** install `podman` and `qemu-user-static`. On Debian/Ubuntu also install `binfmt-support`; on Fedora/RHEL use the `systemd-binfmt` service (built in). - **macOS host:** Podman Desktop already includes `linux/arm64` binfmt handlers in its VM; `linux/arm/v7` support must be added manually inside the VM. - **WSL2/Windows:** install Podman Desktop for Windows and follow the WSL instructions to expose the Podman instance to WSL2. ## Preparing an X86 Linux Host ### Debian / Ubuntu 1. Install Podman and the QEMU binfmt helpers: ```bash sudo apt-get update sudo apt-get install -y podman qemu-user-static binfmt-support sudo systemctl enable --now systemd-binfmt ``` 2. Register the emulators for all targets (including `linux/arm64` and `linux/arm/v7`). Tonistiigi's helper container works well with Podman: ```bash sudo podman run --rm --privileged docker.io/tonistiigi/binfmt --install all ``` 3. Confirm the interpreters are registered: ```bash ls /proc/sys/fs/binfmt_misc | grep -E "arm" ``` ### Fedora / RHEL `binfmt-support` is a Debian package and does not exist on Fedora. Use `qemu-user-static` with the `systemd-binfmt` service instead: 1. Install `qemu-user-static`: ```bash sudo dnf install -y qemu-user-static ``` 2. Enable and start `systemd-binfmt`: ```bash sudo systemctl enable --now systemd-binfmt ``` 3. Confirm the interpreters are registered: ```bash ls /proc/sys/fs/binfmt_misc | grep -E "arm" ``` ## Preparing a macOS Host (Podman machine) The Podman machine VM runs Fedora CoreOS, which uses an immutable `rpm-ostree` base. `binfmt-support` does not exist here — use `qemu-user-static` with `systemd-binfmt`. > [!warning] > Every `machine-os` image is built using a temporary packit COPR repo that is deleted after the release ships. Running `rpm-ostree install` will fail with a GPG key 404 error until that repo is disabled: > ```bash > sudo sed -i 's/^enabled=1/enabled=0/g' /etc/yum.repos.d/podman-release-copr.repo > ``` > This affects all image versions. The [[podman-machine-setup.yml|setup playbook]] handles this automatically. See the note below. 1. SSH into the machine: ```bash podman machine ssh ``` 2. Install `qemu-user-static` as a layered package and reboot to activate it. `--apply-live` cannot be used because `qemu-user-static` adds new directories: ```bash sudo rpm-ostree install qemu-user-static sudo systemctl reboot ``` 3. Reconnect, enable `systemd-binfmt`, and register all handlers: ```bash podman machine ssh sudo systemctl enable --now systemd-binfmt sudo podman run --rm --privileged docker.io/tonistiigi/binfmt --install all ``` 4. Confirm the interpreters are registered: ```bash ls /proc/sys/fs/binfmt_misc | grep -E "arm" ``` > [!note] > `rpm-ostree` layered packages survive reboots but are lost if you `podman machine rm` and re-init. To make setup reproducible, use the setup playbook to re-apply everything automatically on a fresh machine: > ```bash > podman machine rm --force > podman machine init --playbook ~/podman-machine-setup.yml --now > ``` > See [[podman-machine-setup.yml]] for the full playbook. ## Podman Desktop (macOS/Windows) Notes - macOS Podman Desktop already exposes a Linux VM with `linux/arm64` binfmt handlers. Run `podman build --platform linux/arm64 ...` directly. - To add `linux/arm/v7` support, SSH into the machine (`podman machine ssh`) and follow the macOS host steps above. - Windows users should rely on Podman Desktop instead of Docker Desktop; the service is automatically exposed to WSL2 after following the [Windows installation guide](https://podman.io/getting-started/installation#windows). ## Building a Raspberry Pi Image Use the same containerfile you would on the Pi. Example: ```dockerfile FROM --platform=linux/arm64 debian:bookworm-slim RUN apt-get update && \ apt-get install -y --no-install-recommends build-essential && \ rm -rf /var/lib/apt/lists/* WORKDIR /src COPY hello.c ./ RUN gcc -o hello hello.c CMD ["./hello"] ``` On x86 hosts run: ```bash podman build --platform linux/arm64 -t hello-arm64 . ``` To target the older Pi Zero/1/2, change the `FROM` line to `--platform=linux/arm/v7` and make sure the image includes the appropriate cross-build toolchain (`crossbuild-essential-armhf` or `gcc-arm-linux-gnueabihf`). ## Verify the Architecture inside the Container ```bash podman run --rm hello-arm64 uname -m && dpkg --print-architecture podman run --platform linux/arm/v7 --rm <your-armv7-image> uname -m ``` Expect `aarch64` / `arm64` for new Pis and `armv7l` / `armhf` for the legacy builds. ## Performance Emulated ARM builds are slightly slower than native Pi hardware but fast enough for CI pipelines and automated builders. Favor `linux/arm64` whenever a modern Pi is your target to minimize the emulation gap. ## Legacy Workflow (deprecated) > [!warning] > Pre-2017 guides downloaded the Raspberry Pi OS `.img`, mounted partitions, copied `qemu-arm-static`, and imported the filesystem as a container. That entire workflow is obsolete. Podman's `--platform` builds plus `qemu-user-static` replace it. Keep this old script in mind only for historical reference: https://raw.githubusercontent.com/jguiraudet/jguiraudet.github.io/master/_includes/bin/rpi-build-docker-img ## References - Podman installation: [https://podman.io/getting-started/installation](https://podman.io/getting-started/installation) - tonistiigi/binfmt helper: [https://github.com/tonistiigi/binfmt](https://github.com/tonistiigi/binfmt)