Docker lets the embedded developer run Linux on ARM in a very convenient way using QEMU.
Experimental Docker Engine
Configure the Docker engine for experimental work. Engine settings should appear in Docker Desktop as follows. Experimental changes from false to true.
{
"builder": {
"gc": {
"defaultKeepStorage": "20GB",
"enabled": true
}
},
"experimental": true,
"features": {
"buildkit": true
}
}
This enables the buildx
Docker commands for extended build capabilities including cross-platform support. Usage below.
Usage: docker buildx [OPTIONS] COMMAND
Extended build capabilities with BuildKit
Options:
--builder string Override the configured builder instance
Management Commands:
imagetools Commands to work on images in registry
Commands:
bake Build from a file
build Start a build
create Create a new builder instance
du Disk usage
inspect Inspect current builder instance
ls List builder instances
prune Remove build cache
rm Remove a builder instance
stop Stop builder instance
use Set the current builder instance
version Show buildx version information
Run 'docker buildx COMMAND --help' for more information on a command.
Buildx Plugin by Docker Inc.
After switching to experimental mode, Docker’s plugins now include buildx
at version 0.8.2.
Name | Version |
---|---|
buildx | v0.10.4 |
compose | v2.17.2 |
dev | v0.1.0 |
extension | v0.2.19 |
init | v0.1.0-beta.2 |
sbom | 0.6.0 |
scan | v0.25.0 |
scout | v0.9.0 |
Multi-platform capable Docker ready to go.
Alpine 32-Bit ARM
Docker’s platforms also now enable the following, covering 64-bit ARM, 32-bit ARM with Thumb (v6) and with Thumb-2.
- linux/amd64
- linux/arm64
- linux/riscv64
- linux/ppc64le
- linux/s390x
- linux/386
- linux/arm/v7
- linux/arm/v6
Launch an Alpine container for ARM v7. Remove it on exit and connect it to the terminal interactively, options --rm
and -it
respectively.
docker run --platform linux/arm/v7 --rm -it alpine
Asking for the process table from within the container shows QEMU running the BusyBox shell. The ARM emulator runs the shell, /usr/bin/qemu-arm
. References to /bin/sh
become /bin/busybox
by symbolic link on BusyBox-based distributions; one binary to rule them all!—J.R.R. Tolkien, 1954–1955
/ # ps
PID USER TIME COMMAND
1 root 0:00 {sh} /usr/bin/qemu-arm /bin/sh /bin/sh
8 root 0:00 ps
Thumb-2 Disassembly
NO DISASSEMBLE!—Johnny Five, Short Circuit (1986)
Is it really true though? Add build base for the objdump
object file dump utility, inside the Alpine container.
apk add build-base
Object dump on BusyBox binary. The disassembly lists Thumb-2, below.
/ # objdump -d /bin/busybox | head
/bin/busybox: file format elf32-littlearm
Disassembly of section .init:
000055b0 <_init>:
55b0: b501 push {r0, lr}
55b2: e8bd 4001 ldmia.w sp!, {r0, lr}
55b6: 4770 bx lr
Push R0 and link register, load Multiple Increment After, ‘branch and exchange instruction set’ as the initial part of an initialisation function prologue, all in 32-bit little-endian ARM.
One important little point remains to highlight, that /proc/cpuinfo
still reports reality: the host CPU, not the platform emulation. Eight cores of Intel i7 in my case.
model name : 11th Gen Intel(R) Core(TM) i7-1165G7 @ 2.80GHz
Underneath the bonnet, the binfmt_misc
kernel feature is launching a user-land wrapper because the binary format mismatches the expected magic sequence. Hey presto!