RaspbianをDockerイメージに変換する

# 

## 3行まとめ

1. Raspbianのイメージファイルからファイルシステムを`tar`ファイルとして抽出する。
2. `docker image import`で`tar`ファイルをインポートし、Dockerイメージに変換する。
3. QEMUを用いてRaspbianのDockerイメージをx86_64環境で起動する。

## 1. 概要

　Raspberry Pi用のLinuxディストリビューションである「Raspbian」には公式Dockerイメージがありません。（非公式イメージであればDocker Hubにいくつかあります）
セキュリティなどの懸念もあり、業務では非公式イメージは使いづらいのが実情です。

　そこで、Raspbianのイメージファイル（`*.img`）からDockerイメージを作成してみました。また、ARMv7版RaspbianのDockerイメージをx86_64環境で動作させてみました。

**2019年9月11日12時55分追記:** [mt08さんからのコメント](https://qiita.com/yuyakato/items/5dd06fb179922206044d#comment-885516a16b64e5e442a0)によると、Raspbianは公式のルートファイルシステムが別途配布されているとのことです。そのため、「4. ファイルシステムの抽出」の手順は不要です。

## 2. 環境

　今回試した環境は以下の通りです。

* OS: Ubuntu 16.04.5 LTS
* Docker: 18.09.4

```text
host$ cat /etc/lsb-release
DISTRIB_ID=Ubuntu
DISTRIB_RELEASE=16.04
DISTRIB_CODENAME=xenial
DISTRIB_DESCRIPTION="Ubuntu 16.04.5 LTS"

host$ docker version
Client:
 Version:           18.09.4
 API version:       1.39
 Go version:        go1.10.8
 Git commit:        d14af54
 Built:             Wed Mar 27 18:34:51 2019
 OS/Arch:           linux/amd64
 Experimental:      false

Server: Docker Engine - Community
 Engine:
  Version:          18.09.4
  API version:      1.39 (minimum version 1.12)
  Go version:       go1.10.8
  Git commit:       d14af54
  Built:            Wed Mar 27 18:01:48 2019
  OS/Arch:          linux/amd64
  Experimental:     false
```

## 3. 対象イメージ

　今回の対象イメージは「Raspbian Stretch Lite」（2019-04-08版）です。

```text
host$ wget https://downloads.raspberrypi.org/raspbian_lite/images/raspbian_lite-2019-04-09/2019-04-08-raspbian-stretch-lite.zip
host$ ls -l 2019-04-08-raspbian-stretch-lite.zip
-rw-rw-r-- 1 yuya yuya 368729233 Apr  8 19:26 2019-04-08-raspbian-stretch-lite.zip

host$ sha256sum 2019-04-08-raspbian-stretch-lite.zip
03ec326d45c6eb6cef848cf9a1d6c7315a9410b49a276a6b28e67a40b11fdfcf  2019-04-08-raspbian-stretch-lite.zip

host$ unzip 2019-04-08-raspbian-stretch-lite.zip
host$ ls -l 2019-04-08-raspbian-stretch-lite.img
-rw-r--r-- 1 yuya yuya 1803550720 Apr  8 11:25 2019-04-08-raspbian-stretch-lite.img

host$ sha256sum 2019-04-08-raspbian-stretch-lite.img
d4e7d2caa051432a3b6f320c44939b9f65fd454d957904d1cb9fc1c1683ed716  2019-04-08-raspbian-stretch-lite.img
```

## 4. ファイルシステムの抽出

　まず、イメージファイルをマウントし、ファイルシステムを抽出します。
Dockerコンテナ上にイメージファイルをマウントする方法については別記事『[Dockerコンテナ上でイメージファイルをマウントする](https://qiita.com/yuyakato/items/dee9a6f17cf0b49e6579)』をご参照ください。
以下、Dockerホスト側のプロンプトを`host$`、Dockerコンテナ内のプロンプトを`docker$`で示します。

```text
host$ docker container run --interactive --tty --rm --privileged \
  --volume $(pwd):/workspace \
  ubuntu:18.04

docker$ apt-get update && apt-get install --yes --no-install-recommends parted
docker$ parted /workspace/2019-04-08-raspbian-stretch-lite.img unit B print
Model:  (file)
Disk /workspace/2019-04-08-raspbian-stretch-lite.img: 1803550720B
Sector size (logical/physical): 512B/512B
Partition Table: msdos
Disk Flags:

Number  Start      End          Size         Type     File system  Flags
 1      4194304B   49174015B    44979712B    primary  fat32        lba
 2      50331648B  1803550719B  1753219072B  primary  ext4

docker$ mkdir --parents /mnt/image
docker$ mount --options loop,offset=50331648 /workspace/2019-04-08-raspbian-stretch-lite.img /mnt/image
docker$ ls -l /mnt/image
total 88
drwxr-xr-x  2 root root  4096 Apr  8 09:51 bin
drwxr-xr-x  2 root root  4096 Apr  8 10:24 boot
drwxr-xr-x  4 root root  4096 Apr  8 09:39 dev
drwxr-xr-x 84 root root  4096 Apr  8 10:25 etc
drwxr-xr-x  3 root root  4096 Apr  8 09:48 home
drwxr-xr-x 16 root root  4096 Apr  8 09:58 lib
drwx------  2 root root 16384 Apr  8 10:24 lost+found
drwxr-xr-x  2 root root  4096 Apr  8 09:37 media
drwxr-xr-x  2 root root  4096 Apr  8 09:37 mnt
drwxr-xr-x  3 root root  4096 Apr  8 09:48 opt
drwxr-xr-x  2 root root  4096 Feb 17  2019 proc
drwx------  2 root root  4096 Apr  8 09:37 root
drwxr-xr-x  5 root root  4096 Apr  8 09:49 run
drwxr-xr-x  2 root root  4096 Apr  8 09:59 sbin
drwxr-xr-x  2 root root  4096 Apr  8 09:37 srv
drwxr-xr-x  2 root root  4096 Feb 17  2019 sys
drwxrwxrwt  2 root root  4096 Apr  8 10:25 tmp
drwxr-xr-x 10 root root  4096 Apr  8 09:37 usr
drwxr-xr-x 11 root root  4096 Apr  8 09:37 var

docker$ tar cfv /workspace/2019-04-08-raspbian-stretch-lite.tar -C /mnt/image .
docker$ ls -l /workspace/2019-04-08-raspbian-stretch-lite.tar
-rw-r--r-- 1 root root 856811520 Sep 10 07:38 /workspace/2019-04-08-raspbian-stretch-lite.tar

docker$ tar tfv /workspace/2019-04-08-raspbian-stretch-lite.tar | head
drwxr-xr-x root/root         0 2019-04-08 09:46 ./
drwxr-xr-x root/root         0 2019-04-08 10:24 ./boot/
drwx------ root/root         0 2019-04-08 10:24 ./lost+found/
drwxr-xr-x root/root         0 2019-02-17 15:05 ./proc/
drwxr-xr-x root/root         0 2019-04-08 09:39 ./dev/
crw------- root/tty        4,1 2019-04-08 09:39 ./dev/tty1
crw-rw---- root/audio    14,48 2019-04-08 09:39 ./dev/mixer3
crw-rw---- root/audio   35,131 2019-04-08 09:39 ./dev/smpte3
crw-rw---- root/audio     35,3 2019-04-08 09:39 ./dev/midi3
brw-rw---- root/disk       1,2 2019-04-08 09:38 ./dev/ram2
```

　イメージファイルの内容を`2019-04-08-raspbian-stretch-lite.tar`として抽出することができました。

## 5. Dockerイメージへの変換

　続いて、`tar`ファイルをDockerイメージに変換（インポート）します。

```text
host$ docker image import 2019-04-08-raspbian-stretch-lite.tar raspbian-stretch-lite:2019-04-08
host$ docker image ls raspbian-stretch-lite
REPOSITORY              TAG                 IMAGE ID            CREATED             SIZE
raspbian-stretch-lite   2019-04-08          b53519ee6f33        22 seconds ago      828MB
```

　`tar`ファイルをDockerイメージとしてインポートすることができました。

## 6. 異なるCPUアーキテクチャのDockerイメージを実行

　上記のDockerイメージはARMv7用のDockerイメージであるため、当然ながらx86_64環境ではそのまま実行できません。
ここではCPUエミュレータである「QEMU」を使うことで、x86_64環境上でARMv7のDockerイメージを動かしてみます。

```text
host$ sudo apt-get update && sudo apt-get install --yes --no-install-recommends qemu-user-static
host$ docker container run --interactive --tty --rm \
  --volume /usr/bin/qemu-arm-static:/usr/bin/qemu-arm-static \
  raspbian-stretch-lite:2019-04-08 \
  /bin/bash

docker$ arch
armv7l

docker$ cat /etc/debian_version
9.8
```

　無事に動作しました。

### 6.1. エラー例: QEMUを使用しない場合

```text
host$ docker container run --interactive --tty --rm \
  raspbian-stretch-lite:2019-04-08 \
  /bin/bash
standard_init_linux.go:207: exec user process caused "no such file or directory"
```

## 7. 応用: クロスビルド用のルートファイルシステムの作成

　上記のDockerイメージを活用することで「Raspbian向けクロスビルド環境のためのルートファイルシステムの作成」なども行うことができます。
OpenCVをインストールしたルートファイルシステムを作成する具体例を以下に示します。

```text
host$ docker container run --interactive --tty \
  --volume /usr/bin/qemu-arm-static:/usr/bin/qemu-arm-static \
  --name raspbian_cross_build \
  raspbian-stretch-lite:2019-04-08 \
  /bin/bash

docker$ apt-get update && apt-get install --yes --no-install-recommends libopencv-dev
docker$ rm --recursive --force /var/lib/apt/lists/*
docker$ exit

host$ docker container export raspbian_cross_build > raspbian_cross_build.tar
host$ tar tf raspbian_cross_build.tar | sort | head
bin/
bin/bash
bin/bunzip2
bin/bzcat
bin/bzcmp
bin/bzdiff
bin/bzegrep
bin/bzexe
bin/bzfgrep
bin/bzgrep
```

## 8. 参考

* [QEMU でARM エミュレータ環境を作成する - Qiita](https://qiita.com/zonomasa/items/b33fba457503e166967a)
* [QEMU for windowsでRaspbian Jessieを動作させる - Qiita](https://qiita.com/u6k/items/af43ab9a4326586b9071)