A raspberry Pi emulator in a Docker image that lets developers easily prepare and flash RPi configurations.
The PI-CI project enables developers to easily:
Example use cases:
Key features:
$ docker pull ptrsr/pi-ci
$ docker run --rm -it ptrsr/pi-ci
> usage: docker run [docker args] ptrsr/pi-ci [command] [optional args]
>
> PI-CI: the reproducible PI emulator.
>
> positional arguments:
> command [init, start, resize, flash, export]
>
> optional arguments:
> -h, --help show this help message and exit
> -v show verbose output
>
> Refer to https://github.com/ptrsr/pi-ci for the full README on how to use this program.
Each command has a help message, for example:
docker run --rm -it ptrsr/pi-ci start -h
.
Simply run a ptrsr/pi-ci
container with the start command:
docker run --rm -it ptrsr/pi-ci start
The emulator will automatically log into root
.
To save the resulting image, use a bind mount to /dist
:
docker run --rm -it -v $PWD/dist:/dist ptrsr/pi-ci start
NOTE: this example will create and mount the dist
folder in the current working directory of the host.
To restart the image, simply use the same bind mount.
To enable ssh access, run the container with port 2222 exposed.
docker run --rm -p 2222:2222 ptrsr/pi-ci start
Then ssh into the virtual Pi:
ssh root@localhost -p 2222
The default image is 2 gigabytes in size. This can be increased (but not decreased!) through the resize
command. Increasing the size can be done in two ways:
by providing a path to the target device (e.g. /dev/mmcblk0
). The resulting image will be the same size as the target device.
By providing a specific size in gigabytes, megabytes or bytes (e.g. 8G
, 8192M
, 8589934592
).
For an image to be flashed to a device, the image has to be the less or equal to the device size.
docker run --rm -it -v $PWD/dist:/dist --device=/dev/mmcblk0 ptrsr/pi-ci resize /dev/mmcblk0
NOTE: although an SD card will say a specific size (such as 16GB), the device is usually if not always smaller (GB vs GiB). Therefore, using a target device is recommended.
NOTE: resizing can potentially be a dangerous operation. Always make backup of the image.qcow2
file in the dist
folder before proceeding.
To flash the prepared image to a storage device (such as an SD card), provide the container with the device and run the flash command:
docker run --rm -it -v $PWD/dist:/dist --device=/dev/mmcblk0 ptrsr/pi-ci flash /dev/mmcblk0
On the first boot of the real RPi, a program will automatically inflate the root partition to fill the rest of the target device.
The export function converts the virtual (.qcow2
) image to a raw (.img
) image. This is particularly handy when it is not possible to directly flash an image (e.g. when using WSL), as the raw image can be flashed using tools like Balena Etcher. The export command takes two optional arguments; the --input
and --output
path;
docker run --rm -it -v $PWD/dist:/dist ptrsr/pi-ci export --input /dist/image.qcow2 --output /dist/image.img
The raw image should pop up alongside the virtual image in the mounted dist
folder in the example above.
Using Ansible, it is possible to automate the whole configuration process. Ansible requires docker-py to be installed. This can be done using pip3 install docker-py
.
Ansible can take care of:
An example configuration can be found in the ./test
folder of this repository. To start the test process, run:
ansible-playbook -i ./test/hosts.yml ./test/main.yml
root
and disable PermitRootLogin
in the /etc/ssh/sshd_config
for security.distro.qcow2
image.PI-CI has automatically been tested on Ubuntu 24.04 using GitHub Actions. Any other distro should work with the following software versions (or higher, perhaps):
Software | Version |
---|---|
Ansible | 2.5.1 |
docker-py | 4.4.4 |
Docker | 19.03.6 |
PI-CI is licensed under GPLv3.