※2024/12/27 bookworm版の作成について追記。また、Apple silicon Mac上でRaspberry Pi OS(64-bit)を動かす場合、ネイティブ動作になることを追記。
※2026/6/19 macOS上のApple containerでRaspberry Pi OS Lite 64-bit/32-bit (trixie) を動かす手順を追記。
はじめに
Raspberry Piを深く触っていると、実機上の作業では時間がかかりすぎて耐えられないことはないでしょうか。(ただし、最近は一時的にRaspberry Pi 5上で動かせば良いことも多いです)
例えば…
- Qt等、巨大なライブラリの最新版がどうしても必要となり、実機上でコンパイルしたら終わりそうにない or エラーのモグラ叩き(しかもスペックが貧弱なので、エラーが数時間おきで発生し収束しない)に陥ることが多々あります
- パワフルなマシン上で、実機と同じ仮想環境を構築してコンパイルしたい
- クロスコンパイルだと設定が複雑なので、時間は少しかかってもいいから単純にやりたい
- 実機と同じアーキテクチャ上の仮想環境で、実機より効率よく開発したい
ということで、お手持ちのPCをビルド環境や開発環境にするため、ARMアーキテクチャで動くRaspberry Pi OSイメージをDockerまたはApple containerで動かす手順をまとめました。
注意点として、GPIO/I2C/SPI、Raspberry Pi firmware、boot loader、Raspberry Pi kernelまで再現するものではなく、Raspberry Pi OSの通常の実行環境をコンテナ上で動かすための手順です。
本頁は、以下のサイトの手順を簡易にしたものから始まり、その後Apple silicon Mac向けの手順を追加したものになります。
http://blog.guiraudet.com/raspberrypi/2016/03/03/raspbian-image-for-docker.html
また、DockerやApple containerの基本的な操作は割愛します。コンテナの起動/ログイン/終了といった手順は別途お調べください。
ざっくりとした手順
Apple silicon搭載 Mac
- Apple containerをインストール
- Raspberry Pi OS Lite 64-bitの
.img.xzを取得 - Apple container上のDebianで
.img.xzを展開し、rootfsパーティションをmount - rootfsからApple container用のOCIイメージを作成
- コンテナを起動
- 作業内容を残したい場合は、名前付きコンテナ、volume mount、またはContainer Machineを使う
- Raspberry Pi OS Lite 32-bitを動かす場合は、qemu/binfmtを使うrunnerイメージを作成する
Intel Mac
- Dockerをインストール
- Linux環境を用意
- Linux環境でRaspberry Pi OSイメージを取得し、rootfsパーティションをmount
- tarで固め、Dockerのホスト環境へ移動
- Dockerイメージを作成
- Dockerを起動
なお、筆者が確認した環境は以下になります。
- 2019年記載時: Host環境はmacOS Mojave(x86_64)、Linux環境はDocker上のDebian(x86_64)、Raspberry Pi OSは32bit版(armhf)です。
- 2024年記載時: Host環境はmacOS Sequoia(arm64)、Linux環境はDocker上のDebian(arm64)、Raspberry Pi OSは64bit版(aarch64=arm64)と32bit版(armhf)です。
- 2026年記載時: Host環境はmacOS 27.0(arm64)、Apple container 1.0.0、Raspberry Pi OS Lite 64-bit/32-bit 2026-04-21 trixieです。
Apple silicon搭載 Macの手順
前提
Apple silicon搭載Macはarm64アーキテクチャなので、Raspberry Pi OS 64-bit環境はネイティブに近い形で動きます。Raspberry Pi OS 32-bit(armhf)はネイティブでは動かないため、後述のqemu/binfmtを使います。
ここではApple containerを使います。Homebrewが入っていれば、以下でインストールできます。
$ brew install container
インストール後、Apple containerのsystem serviceを起動して、バージョンを確認します。
$ container system start
$ container system version
筆者の確認環境では以下でした。
COMPONENT VERSION
container 1.0.0
container-apiserver 1.0.0
作業ディレクトリを用意
一時作業なので/tmpを使います。
$ WORK=/tmp/raspios-container
$ mkdir -p "$WORK"
$ cd "$WORK"
Raspberry Pi OS Lite 64-bitイメージを取得
URLはRaspberry Pi OSのダウンロードページまたはRaspberry Pi ImagerのOSリストを参照してください。
2026-04-21版のRaspberry Pi OS Lite 64-bitの場合は以下です。
$ curl -L -C - -o 2026-04-21-raspios-trixie-arm64-lite.img.xz \
https://downloads.raspberrypi.com/raspios_lite_arm64/images/raspios_lite_arm64-2026-04-21/2026-04-21-raspios-trixie-arm64-lite.img.xz
$ shasum -a 256 2026-04-21-raspios-trixie-arm64-lite.img.xz
4cd31df026fd82243805a326dc0cafd7383f7e3d30c9413e7044d507aae281e2 2026-04-21-raspios-trixie-arm64-lite.img.xz
rootfsを抽出するDebianコンテナを起動
Apple container上でDebian arm64を起動し、その中で.img.xzの展開とmountを行います。
mount -o loop,offset=...を使うので、--cap-add ALLを付けます。
$ container run --arch arm64 -it --rm \
--cap-add ALL \
--volume "$PWD:/work" \
docker.io/debian:trixie /bin/bash
以降、この節ではDebianコンテナ内で作業します。
# apt-get update
# apt-get install -y xz-utils util-linux fdisk mount tar openssl passwd ca-certificates
# cd /work
# xz -dk 2026-04-21-raspios-trixie-arm64-lite.img.xz
# sha256sum 2026-04-21-raspios-trixie-arm64-lite.img
7a49cd99423f561e681e9d32071ec05d06beca5a9224972a4a4c99d684deec04 2026-04-21-raspios-trixie-arm64-lite.img
rootfsパーティションをmount
.imgはディスク全体のイメージなので、そのままrootfsとしてmountするのではなく、第2パーティションの開始セクタを確認してoffset指定でmountします。
# fdisk -l 2026-04-21-raspios-trixie-arm64-lite.img
2026-04-21版のRaspberry Pi OS Lite 64-bitでは以下のようになりました。
Disk 2026-04-21-raspios-trixie-arm64-lite.img: 3.01 GiB, 3229614080 bytes, 6307840 sectors
Units: sectors of 1 * 512 = 512 bytes
Device Start End Sectors Size Id Type
2026-04-21-raspios-trixie-arm64-lite.img1 16384 1064959 1048576 512M c W95 FAT32 (LBA)
2026-04-21-raspios-trixie-arm64-lite.img2 1064960 6307839 5242880 2.5G 83 Linux
第2パーティションのStartを使います。この例では1064960です。
# START=1064960
# mkdir -p /mnt/raspios
# mount -o loop,offset=$((512*START)) \
2026-04-21-raspios-trixie-arm64-lite.img /mnt/raspios
# findmnt /mnt/raspios
TARGET SOURCE FSTYPE OPTIONS
/mnt/raspios /dev/loop0 ext4 rw,relatime
Apple container 1.0.0では、--cap-add ALLを付けたDebian arm64コンテナ内でmount -o loop,offset=...がそのまま使えました。したがって、rootfs抽出のためにDocker Desktopや別Linux環境へ逃がす必要はありませんでした。
ユーザーを作成
現在のRaspberry Pi OSには、昔のような固定のpiユーザーはありません。Raspberry Pi Imagerは初期ユーザー設定を行いますが、ここではrootfs作成時にユーザー作成だけを先に適用します。
Imagerと同じく、Raspberry Pi OS側に入っている/usr/lib/userconf-pi/userconfを使います。
以下は例としてpi/raspberryを作成する場合です。
これはかつてのRaspberry Pi OSのデフォルトに合わせた例で、そのまま実運用することは推奨しません。実際に使う場合は、各自で別のユーザー名と十分に強いパスワードを設定してください。
# USERNAME=pi
# PASSWORD=raspberry
# HASH=$(printf '%s' "$PASSWORD" | openssl passwd -6 -stdin)
# mountpoint -q /mnt/raspios/proc || mount -t proc proc /mnt/raspios/proc
# mountpoint -q /mnt/raspios/sys || mount -t sysfs sysfs /mnt/raspios/sys
# mountpoint -q /mnt/raspios/dev || mount --bind /dev /mnt/raspios/dev
# chroot /mnt/raspios /usr/lib/userconf-pi/userconf "$USERNAME" "$HASH"
# umount /mnt/raspios/dev
# umount /mnt/raspios/sys
# umount /mnt/raspios/proc
任意のユーザー名・パスワードを入力したい場合は、先頭のUSERNAME、PASSWORD、HASHの部分を以下のように置き換えます。以降のmountとuserconfの実行は同じです。
# read -p "Username: " USERNAME
# read -s -p "Password: " PASSWORD
# echo
# HASH=$(printf '%s' "$PASSWORD" | openssl passwd -6 -stdin)
Apple container用イメージを作成
rootfsをtar化します。
# tar --numeric-owner --xattrs --acls \
-C /mnt/raspios \
-cpf /work/raspios-trixie-arm64-rootfs.tar .
# umount /mnt/raspios
# exit
ここからはmacOS側で作業します。
# Dockerfile.arm64
FROM scratch
ADD raspios-trixie-arm64-rootfs.tar /
CMD ["/bin/bash"]
$ container build --arch arm64 \
--file Dockerfile.arm64 \
--tag raspios-trixie-arm64:20260421 .
筆者の環境では、以下のように登録されました。
$ container image list | grep raspios-trixie-arm64
raspios-trixie-arm64 20260421 e25858843ab0
実行方法
コンテナを起動
単発で確認するだけなら以下です。--rm付きで起動しているため、コンテナ終了時に書き込み内容は削除されます。作ったファイルやapt installした内容は残りません。
$ container run --arch arm64 -it --rm \
raspios-trixie-arm64:20260421 /bin/bash
CPUやメモリを多めに割り当てたい場合は以下のようにします。Apple containerのデフォルトは、筆者の環境では4 CPU / 1GBでした。通常のコンテナでは、CPUやメモリの指定は作成時の設定になります。--rmを外してコンテナを残す場合でも、container start時に--cpusや--memoryを指定し直すことはできません。
$ container run --arch arm64 -it --rm \
--cpus 8 \
--memory 8g \
raspios-trixie-arm64:20260421 /bin/bash
確認例です。
# uname -m
aarch64
# dpkg --print-architecture
arm64
# getent passwd pi
pi:x:1000:1000::/home/pi:/bin/bash
# su - pi
作業内容を残したい場合
成果物だけ残したい場合は、Mac側のディレクトリをmountします。
$ container run --arch arm64 -it --rm \
--volume "$PWD:/work" \
raspios-trixie-arm64:20260421 /bin/bash
コンテナ内での変更も残したい場合は、--rmを外して名前を付けます。この場合、コンテナの書き込みレイヤが残るため、apt installした内容なども同じコンテナを再開すれば残ります。
$ container run --arch arm64 -it \
--name raspios-work \
raspios-trixie-arm64:20260421 /bin/bash
再開例です。
$ container start raspios-work
$ container exec -it raspios-work /bin/bash
前述の通り、通常のコンテナでは作成後に同じコンテナのCPU/メモリ設定を変更することはできません。変更したい場合は、必要なファイルをvolumeなどに退避したうえで、別名のコンテナを作り直します。後からCPU/メモリを変更したい場合は、次のContainer Machineの方が扱いやすいです。
$ container run --arch arm64 -it \
--name raspios-work-8cpu \
--cpus 8 \
--memory 16G \
raspios-trixie-arm64:20260421 /bin/bash
Container Machineを使う場合
Apple containerには永続的なLinux環境として使えるContainer Machineがあります。Macユーザーの自動作成と、Macのホームディレクトリ共有が行われます。
$ container machine create raspios-trixie-arm64:20260421 \
--name raspios-dev
CPUやメモリを指定したい場合は、作成時に--cpusと--memoryを付けます。以下の6 CPU / 16GBは例なので、使っているMacの余力に合わせて変更してください。
$ container machine create raspios-trixie-arm64:20260421 \
--name raspios-dev \
--cpus 6 \
--memory 16G
作成時に指定した値はContainer Machineの設定として保存され、次回以降のcontainer machine runでも引き継がれます。あとから変更する場合はcontainer machine setを使います。変更は再起動後に反映されます。
$ container machine set -n raspios-dev cpus=4 memory=8G
$ container machine stop raspios-dev
起動・ログインは以下です。
$ container machine run -n raspios-dev
Macのログインユーザー名と同名のユーザーが自動作成され、そのユーザーのホームディレクトリがvirtiofsで共有されます。Raspberry Pi OS側のユーザーも使えます。
$ container machine run -n raspios-dev --user pi
ただし、Raspberry Pi OSのsystemd起動時に/boot/firmware、growfs、zram、nftablesなどRaspberry Pi実機向けのunitが失敗することがあります。開発用途では使えますが、記事の本線としては通常のcontainer runを先に紹介する方が分かりやすいと思います。
不要になったContainer Machineは以下で削除します。
$ container machine stop raspios-dev
$ container machine delete raspios-dev
初回起動後にkernel/initramfs関連を削除
Raspberry Pi OSをコンテナ上で動かす場合、Raspberry Pi kernelやinitramfsは使いません。むしろapt upgrade時にkernel packageのpostinstがupdate-initramfsを実行し、コンテナ上の/のデバイスを解決できずに失敗することがあります。
そのため、継続利用するコンテナまたはContainer Machineを作ったら、apt upgradeする前に削除しておきます。--rm付きの単発コンテナで実行しても、終了時に変更は残りません。
# apt-get update
# apt-get purge -y 'linux-image*' 'linux-headers*' 'initramfs-tools*'
# apt-get autoremove --purge -y
# apt-get upgrade
2026-04-21版では、Lite 64-bitにもlinux-image-rpi-v8、linux-image-rpi-2712、initramfs-toolsなどが入っていました。Lite 32-bit(armhf)にはlinux-image-rpi-v6、linux-image-rpi-v7、linux-image-rpi-v8:arm64、initramfs-toolsなどが入っていました。したがって、64-bit/32-bitのどちらでも、コンテナ用途では先に削除しておく方が安全です。
なお、linux-libc-devは通常のアプリケーション向けのLinux APIヘッダなので、このpurge対象には含めません。Raspberry Pi kernel本体や外部kernel moduleをビルドする場合は、コンテナに最初から入っているkernel packageへ依存するのではなく、対象kernelに合わせたsourceまたはheadersを別途用意する方が安全です。
Raspberry Pi OS Lite 32-bitを動かす場合
Raspberry Pi OS Lite 32-bitはarmhfです。Apple silicon Macはarm64なので、64-bit版のようにはネイティブ実行できません。
実際に以下を試すと、imageの取得までは進みますが、32-bit ARMバイナリの実行でExec format errorになります。
$ container run --platform linux/arm/v7 --rm docker.io/debian:trixie uname -m
...
Exec format error
そのため、32-bit版ではqemu/binfmtを使うrunnerイメージを作ります。
作業ディレクトリを分けます。
$ WORK=/tmp/raspios-container-armhf
$ mkdir -p "$WORK"
$ cd "$WORK"
Raspberry Pi OS Lite 32-bitを取得します。
$ curl -L -C - -o 2026-04-21-raspios-trixie-armhf-lite.img.xz \
https://downloads.raspberrypi.com/raspios_lite_armhf/images/raspios_lite_armhf-2026-04-21/2026-04-21-raspios-trixie-armhf-lite.img.xz
$ shasum -a 256 2026-04-21-raspios-trixie-armhf-lite.img.xz
f393b8bc3fc49aef49ddc5d5af124333002f34e4b23ede439789145e5280d210 2026-04-21-raspios-trixie-armhf-lite.img.xz
rootfsの抽出とユーザー作成は64-bit版とほぼ同じですが、chroot内でarmhfバイナリを実行するためにqemu-armをbinfmtへ登録します。
$ container run --arch arm64 -it --rm \
--cap-add ALL \
--volume "$PWD:/work" \
docker.io/debian:trixie /bin/bash
Debianコンテナ内で作業します。
# apt-get update
# apt-get install -y xz-utils util-linux fdisk mount tar openssl passwd \
ca-certificates qemu-user qemu-user-static acl attr
# cd /work
# xz -dk 2026-04-21-raspios-trixie-armhf-lite.img.xz
# sha256sum 2026-04-21-raspios-trixie-armhf-lite.img
9705e3bbd217446b9859352655231deba49f90ae69cff7611088f9a6727da63a 2026-04-21-raspios-trixie-armhf-lite.img
# fdisk -l 2026-04-21-raspios-trixie-armhf-lite.img
2026-04-21版のLite 32-bitでは、第2パーティション開始セクタは1064960でした。
# START=1064960
# mkdir -p /mnt/raspios
# mount -o loop,offset=$((512*START)) \
2026-04-21-raspios-trixie-armhf-lite.img /mnt/raspios
qemu-armをbinfmtへ登録します。筆者のDebian trixieコンテナではqemu-armが自動登録されていなかったため、以下のように手動登録しました。
# mountpoint -q /proc/sys/fs/binfmt_misc || \
mount -t binfmt_misc binfmt_misc /proc/sys/fs/binfmt_misc
# [ -e /proc/sys/fs/binfmt_misc/qemu-arm ] || \
cat /usr/share/qemu/binfmt.d/qemu-arm.conf > /proc/sys/fs/binfmt_misc/register
rootfsにqemuを入れ、ユーザーを作成します。ここでも例としてpi/raspberryを使っていますが、実際には各自で別のユーザー名とパスワードを設定してください。
# cp /usr/bin/qemu-arm-static /mnt/raspios/usr/bin/qemu-arm-static
# mountpoint -q /mnt/raspios/proc || mount -t proc proc /mnt/raspios/proc
# mountpoint -q /mnt/raspios/sys || mount -t sysfs sysfs /mnt/raspios/sys
# mountpoint -q /mnt/raspios/dev || mount --bind /dev /mnt/raspios/dev
# USERNAME=pi
# PASSWORD=raspberry
# HASH=$(printf '%s' "$PASSWORD" | openssl passwd -6 -stdin)
# chroot /mnt/raspios /usr/lib/userconf-pi/userconf "$USERNAME" "$HASH"
# chroot /mnt/raspios /bin/uname -m
armv7l
# umount /mnt/raspios/dev
# umount /mnt/raspios/sys
# umount /mnt/raspios/proc
rootfsをtar化します。
# tar --numeric-owner --xattrs --acls \
-C /mnt/raspios \
-cpf /work/raspios-trixie-armhf-rootfs.tar .
# umount /mnt/raspios
# exit
次に、armhf用のrunnerイメージを作ります。FROM scratchにqemu-arm-staticを入れてentrypointにするだけでは不十分です。最初の/bin/bashは動いても、そこから起動されるunameやidなどの子プロセスがExec format errorになります。
そのため、外側はarm64のDebian、内側/raspiosにRaspberry Pi OS armhf rootfsを置き、起動時にbinfmtを登録してからchrootします。
# Dockerfile.armhf
FROM docker.io/debian:trixie
RUN apt-get update \
&& DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \
ca-certificates \
mount \
qemu-user \
util-linux \
&& rm -rf /var/lib/apt/lists/*
ADD raspios-trixie-armhf-rootfs.tar /raspios/
COPY run-raspios-armhf /usr/local/bin/run-raspios-armhf
ENTRYPOINT ["/usr/local/bin/run-raspios-armhf"]
CMD ["/bin/bash"]
run-raspios-armhfは以下です。
#!/bin/sh
set -eu
if ! mountpoint -q /proc/sys/fs/binfmt_misc; then
mount -t binfmt_misc binfmt_misc /proc/sys/fs/binfmt_misc
fi
if [ -e /proc/sys/fs/binfmt_misc/qemu-arm ] \
&& ! grep -q '^flags: .*C' /proc/sys/fs/binfmt_misc/qemu-arm; then
echo -1 > /proc/sys/fs/binfmt_misc/qemu-arm
fi
if [ ! -e /proc/sys/fs/binfmt_misc/qemu-arm ]; then
sed 's/:OPF$/:POCF/' /usr/share/qemu/binfmt.d/qemu-arm.conf \
> /proc/sys/fs/binfmt_misc/register
fi
mountpoint -q /raspios/proc || mount -t proc proc /raspios/proc
mountpoint -q /raspios/sys || mount -t sysfs sysfs /raspios/sys
mountpoint -q /raspios/dev || mount --rbind /dev /raspios/dev
mount --make-rslave /raspios/dev 2>/dev/null || true
hostname="$(hostname)"
if ! grep -q "[[:space:]]${hostname}\\([[:space:]]\\|$\\)" /raspios/etc/hosts; then
printf '127.0.1.1\t%s\n' "${hostname}" >> /raspios/etc/hosts
fi
exec chroot /raspios "$@"
重要な点は2つあります。
-
binfmt_miscのqemu-arm登録にCflagを付けること。これがないとsudoのsetuidが効かず、sudo: effective uid is not 0になります。 -
/devを--rbindすること。これがないとchroot内で/dev/ptsが見えず、対話式sudoでsudo: unable to allocate ptyになります。
ビルドします。
$ chmod +x run-raspios-armhf
$ container build --arch arm64 \
--file Dockerfile.armhf \
--tag raspios-trixie-armhf-qemu:20260421 .
起動します。起動時にもbinfmt_misc登録とmountが必要なので、--cap-add ALLを付けます。
$ container run --arch arm64 -it --rm \
--cap-add ALL \
raspios-trixie-armhf-qemu:20260421 /bin/bash
確認例です。
# uname -m
armv7l
# dpkg --print-architecture
armhf
# cat /etc/os-release
PRETTY_NAME="Raspbian GNU/Linux 13 (trixie)"
# su - pi
armhf版でも、apt upgradeの前に前述のkernel/initramfs関連パッケージ削除を実行してください。
armhf版はqemu経由なので、64-bit版に比べるとかなり遅くなります。Raspberry Pi Zero(32-bitのみ)向けのビルド環境が欲しい場合でも、Raspberry Pi 5上でarmhf環境を使った方が単純な場合があります。
apt upgradeに失敗した場合
先に削除せずにapt upgradeして、mkinitramfs: failed to determine device for /で失敗した場合は、kernel/initramfs関連を削除してからdpkgの状態を直します。
# apt-get purge -y 'linux-image*' 'linux-headers*' 'initramfs-tools*'
# apt-get autoremove --purge -y
# dpkg --configure -a
# apt-get -f install
それでも詰まる場合は、対象パッケージをdpkgで直接purgeします。
# dpkg-query -W -f='${binary:Package}\n' 'linux-image*' 'linux-headers*' 'initramfs-tools*' \
| xargs -r dpkg --purge --force-depends
# apt-get -f install
# dpkg --configure -a
# apt-get autoremove --purge -y
特にContainer Machineでapt upgradeした場合も、同じinitramfs更新で失敗することがあります。
Apple siliconでの速度について
Apple siliconを搭載したMacはarm64アーキテクチャで動いているので、Raspberry Pi OS 64-bitのコンテナはネイティブに近い速度で動きます。(M4 Pro上で公式Debian arm64コンテナと比較)
以下は2024年にDockerで測った参考値です。64-bit版がarm64上で動くという点はApple containerでも同じです。
Qt base 6.8.1のビルド時間の比較で検証しました。手順は tal.org を参照し、必要最小限の範囲で行いました。(configure optionに -DINPUT_opengl=no を追加)
$ cmake -G Ninja -DCMAKE_INSTALL_PREFIX=(インストール先) -DCMAKE_BUILD_TYPE=Release -DINPUT_opengl=no -DBUILD_PrintSupport=OFF -DBUILD_Testlib=OFF -DQT_BUILD_TESTS=OFF -DQT_BUILD_EXAMPLES=OFF -DQT_AVOID_CMAKE_ARCHIVING_API=ON (qtbase-everywhere-srcのフォルダ)
$ time cmake --build . --parallel
$ cmake --install .
| 環境 | 所要時間 [min:sec] |
|---|---|
| Raspberry Pi OS 64-bit (on Raspberry Pi 5 4CPU&8GB) | 26:20 |
| Docker: Debian arm64 (on M4 Pro 12CPU&8GB) | 2:26 |
| Docker: Raspberry Pi OS(64-bit) (on M4 Pro 12CPU&8GB) | 2:30 |
| Docker: Raspberry Pi OS(32-bit) (on M4 Pro 12CPU&8GB) | 27:22 |
Raspberry Pi Zero 2, Raspberry Pi 3, 4の64bit環境に対するビルド環境として使うなら大いに恩恵がありそうです。
逆にRaspberry Pi Zero (32bitのみ)向けなら、わざわざコンテナを作らずRaspberry Pi 5上で行った方が良さそうです。
Intel Macの手順
Intel Macではホストがx86_64なので、Raspberry Pi OSのarmhf/arm64環境はネイティブには動きません。Docker Desktop等のLinux環境を使い、必要に応じてqemuを使います。
以下は元記事の手順をベースにしています。
Dockerのインストール
Homebrewを使ったインストール方法は以下ですが、割愛します。
$ brew install --cask docker
Linux環境を用意
ここも詳細は割愛しますが、上述のDockerにDebianを入れた前提で記載を進めます。
別環境で行う場合、特権が必要なコマンドは頭にsudoをつけてください。
Dockerで行うときはイメージファイルがmountできるよう、--privilegedオプションをつけてください。
$ docker pull debian
$ docker run -it --privileged debian
(Debian環境にログイン)
#
Linux環境でRaspberry Pi OSイメージを取得し、イメージファイルを展開
Lite、desktop、recommended software入りdesktop、どれでも構いません。
URLはダウンロードページを参照してください。
現在の配布形式は主に.img.xzです。
# apt-get update
# apt-get install -y xz-utils fdisk mount tar
# wget ダウンロードURL
# xz -dk ダウンロードした.img.xz
.imgはディスク全体のイメージなので、第2パーティションの開始セクタを確認します。
# fdisk -l imgファイル
例です。
Device Start End Sectors Size Id Type
2026-04-21-raspios-trixie-arm64-lite.img1 16384 1064959 1048576 512M c W95 FAT32 (LBA)
2026-04-21-raspios-trixie-arm64-lite.img2 1064960 6307839 5242880 2.5G 83 Linux
第2パーティションのStartを使ってmountします。この例では1064960です。
# mkdir image
# START=1064960
# mount -o loop,offset=$((512*START)) imgファイル image
リリースによって開始セクタは変わるため、古い記事にある固定値をそのまま使うのではなく、必ずfdisk -lで確認してください。
qemuを入れる
ホストとコンテナ内環境のアーキテクチャが異なる場合、qemuが必要です。
32-bit armhfの場合の例です。
# apt-get install -y qemu-user-static
# cp /usr/bin/qemu-arm-static image/usr/bin/
古いRaspberry Pi OSでは/etc/ld.so.preloadが問題になることがあったため、必要に応じて退避します。最近のRaspberry Pi OSでは不要な場合があります。
# [ -f image/etc/ld.so.preload ] && mv image/etc/ld.so.preload image/etc/ld.so.preload.bak
64-bit arm64の場合はqemu-aarch64-staticを使います。
# apt-get install -y qemu-user-static
# cp /usr/bin/qemu-aarch64-static image/usr/bin/
Docker Desktop側のqemu/binfmt設定で動く場合もありますが、環境差が出やすい部分です。Exec format errorが出る場合は、qemuの配置や--platform指定を確認してください。
Dockerイメージを作成
いつ基準のものかをファイル名のYYYY-MM-DDにつけておくとあとでわかりやすいと思います。不要な場合は除去してください。
# cd image
# tar cf ../docker-image-YYYY-MM-DD-raspios.tar .
何らかの手段でホスト環境に上記tarファイルをコピー
(Linux環境を抜けます)
# exit
(ホスト環境にて)
$ docker import docker-image-YYYY-MM-DD-raspios.tar raspios:YYYYMMDD
環境によっては、docker import時またはdocker run時にplatformを明示します。
$ docker import --platform linux/arm/v7 docker-image-YYYY-MM-DD-raspios.tar raspios:YYYYMMDD
Dockerを起動
ホスト環境にて実施します。docker run時は必要に応じてオプションをいじってください。
$ docker run -it raspios:YYYYMMDD /bin/bash
無事起動したら、いつもの通りapt-get update等で環境を整えます。
ユーザーpiを作成済みの場合は、以下のようにします。
# su - pi
$ cd
(以下、/home/pi下で作業)
また、CPUやメモリをどのくらい割くかはDockerのオプションで指定してください。
CPU8コアメモリ4GBとか、贅沢な環境が手に入ります。
Raspberry Pi OSをコンテナ上で動かす場合、kernelやinitramfs関連の更新が失敗することがあります。apt upgradeの前に以下のパッケージを削除します。
# apt-get purge -y 'linux-image*' 'linux-headers*' 'initramfs-tools*'
# apt-get autoremove --purge -y
普段の運用
詳細は割愛しますが、以下の繰り返しになります。stopしないと裏でずっと回ってくれます。VNCを併用するのもいいと思います。
上記の手順を辿るとコンテナ名は不定になりますが、docker rename (現在のコンテナ名) (新しいコンテナ名)で変更できます。
$ docker start (コンテナ名またはコンテナID)
$ docker attach (コンテナ名またはコンテナID)
(ログイン)
#
(作業)
# exit
(ログアウト)
$ docker stop (コンテナID)