snippets > create-docker-image-from-scratch-using-os-filesystem

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).