October 23, 2022
Create a Docker image from scratch using an OS as base
For the purposes of this example, we’ll be using Raspberry Pi OS 64-bit as the base filesystem for our new Docker image. Since this operating system lacks an official one on Docker Hub, it feels like a good fit. However, the principles described here should work well enough for any OS.
Choose an image to download here and save it locally. With unxz
, uncompress the file.
unxz 2022-04-04-raspios-bullseye-arm64-lite.img.xz
Since Raspberry Pi OS is distributed as a disk image and not a partition image, we need to mount it with an offset to avoid getting data from the boot partition. Keep in mind that our goal here is to create a Docker image and, for that, we don’t need boot files.
Find the desired partition offset using fdisk
.
fdisk -l 2022-04-04-raspios-bullseye-arm64-lite.img
You’re likely to see an output similar to the following:
Disk 2022-04-04-raspios-bullseye-arm64-lite.img: 1,86 GiB, 2000683008 bytes, 3907584 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: dos
Disk identifier: 0x0ee3e8a8
Device Boot Start End Sectors Size Id Type
2022-04-04-raspios-bullseye-arm64-lite.img1 8192 532479 524288 256M c W95 FAT32 (LBA)
2022-04-04-raspios-bullseye-arm64-lite.img2 532480 3907583 3375104 1,6G 83 Linux
From this, we can see that the block size used is 512 and the start block for the root partition is 532480. Therefore, our offset will be 532480 * 512 = 272629760
.
Now, let’s mount the relevant partition, gather its contents as a tar
file, generate the image and push it to a registry.
mkdir rootfs
mount -o loop,offset=272629760 2022-04-04-raspios-bullseye-arm64-lite.img rootfs
# Keep in mind that a container image is, under the hood, a tar file of tar files
tar -C rootfs -c . | docker import --platform=linux/arm64 - laury/raspberry-pi-os:bullseye-20220404
docker push laury/raspberry-pi-os:bullseye-20220404
umount rootfs
Note: as the time of writing, the --platform
flag is ignored by docker import
(tested on version 20.10). So, the host architecture is used to determine the platform supported by the generated image. This bug will be resolved on the 22.06 release (see this PR for more information).