ARM環境の Raspberry Pi OS を Docker Desktop for Windows 上で動かす

経緯

Raspberry Pi で色々試したいとは思っているのですが、いざやろうと思うと

  • イメージをダウンロードして
  • microSDカード に焼いて
  • Raspberry Pi 本体に諸々接続して実機で設定して
  • SSHサーバ が建ったら、漸く開発環境から SSH で接続して操作する

……という段取りを踏むことになるので、それを考えると中々重い腰が上がらなくなってしまいました。

しかも、そこまでやって初めてスタートラインに立つ段階で、そこから諸々試すための環境構築が始まるわけです。

そこからさらに失敗するとやり直しをしたり……と考えるとさらに腰が重くなりがちです。

なので、まずは手軽に何度もトライアンドエラーできるように Docker (今回は Docker Desktop for Windows )でどうにかできないかと考えました。

ただし、 Raspberry Pi は ARM で、開発環境は Windows を想定……つまりアーキテクチャ x86-64 や AMD64 だったりするわけなので、アーキテクチャが異なるという壁を越えなければ実現できません。

ということで、今回はこの壁を越えたいと思います。

手順

手順としては以下の記事をほぼそのまま実施することで実現できました。

手順の概要としては以下のような流れになります。

  1. Debian の仮想環境を Docker 上に建てる
  2. 仮想の Debian 内で Raspberry Pi OS のイメージをダウンロード、マウント
  3. プロセッサエミュレータの QEMU (qemu-user-static) をインストールして x86-64 上で ARM を動かせるようにする
  4. 2.+3. の環境を Debian のコンテナからホスト側に持ち出す
  5. 4.で持ち出したイメージを Docker でインポートする

具体的な手順

まずは Debian のイメージを pull して、コンテナを起動します。

> docker pull debian:latest

## 略

> docker run -it --privileged debian

続いて Debian のコンテナに入り、作業していきます。

# apt update -y

## 略


# apt upgrade -y

## 略


# apt install -y wget sudo fdisk xz-utils

## 略


#

apt でアップデート・アップグレードして、必要なパッケージをインストールします。

# cd /var/
# mkdir raspi
# cd raspi/
# wget https://downloads.raspberrypi.org/raspios_lite_armhf/images/raspios_lite_armhf-2023-05-03/2023-05-03-raspios-bullseye-armhf-lite.img.xz

## 略


#

作業用ディレクトリを作成・移動して wget で Raspberry Pi OS のイメージをダウンロードします。元記事ではまだ Raspbian でしたが、今は Raspberry Pi OS なのでその辺りは適宜ダウンロードリンクを差し替えて実行。

# xz -dv 2023-05-03-raspios-bullseye-armhf-lite.img.xz 

## 略


#

ダウンロードした Raspberry Pi OS のイメージはxz形式で圧縮されているので、このイメージを展開します。

# fdisk 2023-05-03-raspios-bullseye-armhf-lite.img 

Welcome to fdisk (util-linux 2.38.1).
Changes will remain in memory only, until you decide to write them.
Be careful before using the write command.


Command (m for help): p
Disk 2023-05-03-raspios-bullseye-armhf-lite.img: 1.83 GiB, 1967128576 bytes, 3842048 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: 0x4c4e106f

Device                                      Boot  Start     End Sectors  Size Id Type
2023-05-03-raspios-bullseye-armhf-lite.img1        8192  532479  524288  256M  c W95 FAT32 (LBA)
2023-05-03-raspios-bullseye-armhf-lite.img2      532480 3842047 3309568  1.6G 83 Linux

展開したイメージをマウントするため、 fdisk コマンドで開始セクタを調べます。

# mkdir image
# sudo mount -o loop,offset=$((512*532480)) 2023-05-03-raspios-bullseye-armhf-lite.img image
#

作業用ディレクトリ image を作成し、そこに先程の開始セクタの値を offset として指定してイメージを image ディレクトリ内にマウントします。

# apt install -y qemu-user-static

ここで今回の要、 qemu-user-static をインストールします。

# mv image/etc/ld.so.preload image/etc/ld.so.preload.bak
# cp /usr/bin/qemu-arm-static image/usr/bin
#

設定を退避したり qemu-arm-static を Raspberry Pi OS 内にコピーしたりします。

# cd image
# tar cf ../docker-image-2023-05-03-raspios-bullseye-armhf-lite.tar .
# cd ../
# ls
2023-05-03-raspios-bullseye-armhf-lite.img  docker-image-2023-05-03-raspios-bullseye-armhf-lite.tar  image

#

マウントした Raspberry Pi OS のディレクトリ内に移動して、 Raspberry Pi OS の一式を親ディレクトリ(先程までいた作業用ディレクトリ)に tar として圧縮します。

今回はこれで docker-image-2023-05-03-raspios-bullseye-armhf-lite.tar ができ上がりました。

# exit

> docker ps
CONTAINER ID   IMAGE     COMMAND   CREATED       STATUS       PORTS     NAMES
XXXXXXXXXXXX   debian    "bash"    4 hours ago   Up 4 hours             hogehoge_fugafuga

> docker cp XXXXXXXXXXXX:/var/raspi/docker-image-2023-05-03-raspios-bullseye-armhf-lite.tar docker-image-2023-05-03-raspios-bullseye-armhf-lite.tar
Successfully copied 1.16GB to PATH:\TO\PROJECT\docker-image-2023-05-03-raspios-bullseye-armhf-lite.tar

コンテナから出てホスト側に戻り、 Docker のコマンド(docker cp)でコンテナ内のファイルをホスト側にコピーします。

そのために、まずは docker ps でコンテナIDを調べ、そのIDを使用して先程作成した tar ファイルをパス指定してホスト側に持ち出します。

> docker import .\docker-image-2023-05-03-raspios-bullseye-armhf-lite.tar raspios-bullseye-armhf64-lite:2023-05-03
sha256:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

最後に、 Docker のイメージとして先程持ち出した tar をインポートします。

これで作業は完了です。

起動

では、早速インポートしたイメージをコンテナとして起動してみます。

> docker run --name mariberrypi --privileged -it raspios-bullseye-armhf64-lite:2023-05-03 /bin/bash

root@XXXXXXXXXXXX:/# su pi
pi@XXXXXXXXXXXX:/ $ exit
exit

# cat /etc/issue
Raspbian GNU/Linux 11 \n \l

root@XXXXXXXXXXXX:/# apt update -y
Get:1 http://archive.raspberrypi.org/debian bullseye InRelease [23.6 kB]
Get:2 http://archive.raspberrypi.org/debian bullseye/main armhf Packages [314 kB]
Get:3 http://raspbian.raspberrypi.org/raspbian bullseye InRelease [15.0 kB]
Get:4 http://raspbian.raspberrypi.org/raspbian bullseye/main armhf Packages [13.2 MB]
Fetched 13.6 MB in 17s (793 kB/s)
Reading package lists... Done
Building dependency tree... Done
Reading state information... Done
20 packages can be upgraded. Run 'apt list --upgradable' to see them.

# apt upgrade -y
Reading package lists... Done
Building dependency tree... Done
Reading state information... Done
Calculating upgrade... Done
The following packages will be upgraded:
  base-files bind9-host bind9-libs libgstreamer-plugins-base1.0-0 libpam-systemd libssl1.1
  libsystemd0 libudev1 libwebp6 libwebpdemux2 libwebpmux3 libx11-6 libx11-data openssl
  raspberrypi-sys-mods rpi-eeprom systemd systemd-sysv systemd-timesyncd udev
20 upgraded, 0 newly installed, 0 to remove and 0 not upgraded.
Need to get 16.4 MB of archives.

## 略


#

pi ユーザになってみたり、バージョン確認してみたり、 apt updateapt upgrade してみましたが、至る所で Raspberry Pi だと分かりますね。

きちんと Docker Desktop for Windows 上で Raspberry Pi OS が動いたことが確認できました。検証成功です。

参考

イメージ

Raspberry pi OS を Docker で動かす

Docker コマンド

Docker のコンテナからホストへファイルコピー

> docker ps

> docker cp XXXXXXXXXXXX:/var/owntemp/hoge.txt hoge.txt

QEMU

Debian 系での xz を扱うパッケージ

xz-utils

途中色々試したときのエラー内容や参考記事等

Error response from daemon: archive/tar: invalid tar header

Error response from daemon: archive/tar: invalid tar header

docker: Error response from daemon: failed to create task for container: failed to create shim task: OCI runtime create failed: runc create failed: unable to start container process: exec: “/bin/bash”: stat /bin/bash: no such file or directory: unknown.

docker: Error response from daemon: failed to create task for container: failed to create shim task: OCI runtime create failed: runc create failed: unable to start container process: exec: “/bin/bash”: stat /bin/bash: no such file or directory: unknown.

Failed to run image. Error invoking remote method ‘docker-run-container’: Error: (HTTP code 400) unexpected – No command specified

Failed to run image. Error invoking remote method ‘docker-run-container’: Error: (HTTP code 400) unexpected – No command specified

Docker Desktop for Windows で直接起動しようとした際のエラー。

mount: permission denied (are you root?)

multiarch/qemu-user-static を起動しようとすると以下のメッセージが出力されてコンテナが終了してしまう。

mount: permission denied (are you root?)

Windows で起きているのですが……?

この記事を書いた人

アルム=バンド

フロントエンド・バックエンド・サーバエンジニア。LAMPやNodeからWP、Gulpを使ってejs,Scss,JSのコーディングまで一通り。たまにRasPiで遊んだり、趣味で開発したり。