ラズパイでdockerを構築したときに一日かかったので、どうどのような解決法があるか試行錯誤した結果を忘備録として残します。結論から言うとpiwheel.orgのレポジトリを使ってください。それでも解決しない場合はラズパイのスペックが足りないので良いハードを買いましょう。buildx
を活用する手も考えられますが未検証です。以下の記述は2021年3月執筆時点の情報です。
この記事はDockerをラズパイで動かそうシリーズ(?)の一つです
更新履歴
- 2021年03月07日 初版投稿
- 2021年04月24日 MacOS,Windows上でのDockerのメモリ制限について追記
背景
ラズパイでnumpy
やpandas
が入った環境を構築したらビルド完了するのに半日がかかったので、なんとかならないか色々調べてみました。
以下の環境で行いました。
- Raspberry pi 4B 8GB RAM
ソフト | バージョン |
---|---|
Ubuntu | 20.04.2 LTS (64bit) |
git | 2.25.1 |
docker | 20.10.5, build 55c4c88 |
docker-compose | 1.28.5 |
- MacBook Pro (2017) /
buildx
実行環境
ソフト | バージョン |
---|---|
macOS | Big Sur(V11.2.2) |
docker | 20.10.2, build 2291f61 |
docker-compose | version 1.27.4, build 40524192 |
解決策1:時間が解決する
対処でもなんでもないですが、一番確実な方法。
下記のようにnohup
コマンドを使用すれば端末を閉じてもログアウトしても処理が続きます。
sudo nohup docker-compose build &
解決策2:違うマシンでbuildしラズパイにインポートする
あらかじめ違うマシンでビルドしたのち、ビルドしたイメージをラズパイにインポートします。
下記ではsample-imageというイメージを保存したのち、ラズパイでロードします。
参考:Dockerでイメージをインポート・エクスポートする | UX MILK
# sample-imageをセーブする
docker save sample-image > sample-image.tar
# ラズパイでイメージをロードする
docker load < sample-image.tar
ただし、dockerイメージはCPUアーキテクチャ間の互換性がないのでIntel(x_86
)でビルドしたイメージはラズパイ(arm/v7
やarm64
)で使えません。
Raspberry Pi 3
で構築出来なかったものをRaspberry Pi 4
でビルドしたのち転送してロードするのは可能です。私の場合はラズパイ3でpandas
を構築した際に以下のエラーが発生しました。おそらく原因はメモリ不足です。
参考:
- gcc: fatal error: Killed signal terminated program cc1 compilation terminated during Docker build - rakhesh.com
- v1.10.0rc5: Docker build fails with "gcc: fatal error: Killed signal terminated program cc1" · Issue #6889 · matrix-org/synapse
[[[前略]]]
gcc -pthread -Wno-unused-result -Wsign-compare -DNDEBUG -g -fwrapv -O3 -Wall -fPIC -DNPY_NO_DEPRECATED_API=0 -Ipandas/_libs/src/klib -I/tmp/pip-build-env-61o34tpt/overlay/lib/python3.7/site-packages/numpy/core/include -I/tmp/pip-build-env-61o34tpt/overlay/lib/python3.7/site-packages/numpy/core/include -I/tmp/pip-build-env-61o34tpt/overlay/lib/python3.7/site-packages/numpy/core/include -I/tmp/pip-build-env-61o34tpt/overlay/lib/python3.7/site-packages/numpy/core/include -I/tmp/pip-build-env-61o34tpt/overlay/lib/python3.7/site-packages/numpy/core/include -I/tmp/pip-build-env-61o34tpt/overlay/lib/python3.7/site-packages/numpy/core/include -I/tmp/pip-build-env-61o34tpt/overlay/lib/python3.7/site-packages/numpy/core/include -I/usr/local/include/python3.7m -c pandas/_libs/join.c -o build/temp.linux-armv7l-3.7/pandas/_libs/join.o
gcc: fatal error: Killed signal terminated program cc1
compilation terminated.
error: command 'gcc' failed with exit status 1
----------------------------------------
ESC[0mESC[91m ERROR: Failed building wheel for pandas
ただし上記の方法はSDカードの容量をケチると重たいイメージが書き出せないので、なるべく容量の大きいSDカードを使用しましょう(そもそもラズパイの用途として向いていないと言われるとそれまでですが)
解決策3: buildxを使用する
注意 : 以下の解決方法は試していましたが、私の場合では時間がかかりあまりうまくいきませんでした。
IntelのCPUでもraspberry piのDockerをビルドする方法はあります。Dockerのbuildx
機能を使用することで実現します。
- Multi-arch build and images, the simple way - Docker Blog
- Dockerの「マルチCPUアーキテクチャ」に対応したイメージをビルドする | DevelopersIO
- Dockerのマルチアーキテクチャイメージについて調べてみた | DevelopersIO
まずはmacOS
かwindows
でdockerを開き[Preferences]>[Experimental Features]からEnable CLI experimental features
を有効化します。
mac
の場合「設定」は右上の歯車ボタンを押せば開きます。
以下を実行してどのようなbuilder
があるか調べます
$ docker buildx ls
NAME/NODE DRIVER/ENDPOINT STATUS PLATFORMS
default * docker
default default running linux/amd64, linux/arm64, linux/riscv64, linux/ppc64le, linux/s390x, linux/386, linux/arm/v7, linux/arm/v6
PlATFORMS
の箇所にlinux/arm64
やlinux/arm/v7
が並んでいます。これでarm
アーキテクチャでビルドできることを示しています。以下のコマンドではarm64
をビルドしています。
docker buildx build \
--platform linux/arm64 \
--tag your-username/multiarch-example:buildx-latest .
Dockerのメモリ上限を引き上げよう
ビルド中にエラーが出ていくらググっても解決策が見つからない場合は、とりあえずスペック不足を疑いましょう。Windows
とMacOS
はデフォルトだとDocker containerに2GBのメモリ制限があるのでその上限を引き上げてみよう。
スペックの問題ではない...?
最初、buildに時間がかかるのはスペックの問題だと思っていましたが、私が直面した問題ではどうやら違っていました。以下の場合、numpy
は1時間以上pandas
は8時間以上構築に時間がかかっています(下記参照)
% sudo docker buildx build --platform linux/arm/v7 .
[+] Building 37461.7s (15/17)
=> [internal] load build definition from Dockerfile 0.1s
=> => transferring dockerfile: 1.01kB 0.0s
=> [internal] load .dockerignore 0.0s
=> => transferring context: 2B 0.0s
=> [internal] load metadata for docker.io/library/python:3.9.2 3.4s
=> [ 1/13] FROM docker.io/library/python:3.9.2@sha256:e2cd43d291bbd21bed01bcceb5c0a8d8c50a9cef319a7b5c5ff6f85232e82021 47.2s
=> => resolve docker.io/library/python:3.9.2@sha256:e2cd43d291bbd21bed01bcceb5c0a8d8c50a9cef319a7b5c5ff6f85232e82021 0.0s
=> => sha256:2d873e84995af4aea1f14a350eaf612030dbd30d856a1e21052da9332b31d399 8.33kB / 8.33kB 0.0s
=> => sha256:4c2a0a79594a20b9c2f0bfbd535f875ca1b079625052cdd801afb1cc0362d6d0 45.87MB / 45.87MB 18.7s
=> => sha256:06c11c595f6421f88e1b10286a766ae8db88f67c2c0f41cedd170640aee498ab 7.12MB / 7.12MB 2.7s
=> => sha256:e2cd43d291bbd21bed01bcceb5c0a8d8c50a9cef319a7b5c5ff6f85232e82021 2.11kB / 2.11kB 0.0s
=> => sha256:47cb22b679409f00e04b8d645444df7181f05cb2967ed73f1a377e7f774b6873 9.34MB / 9.34MB 3.5s
=> => sha256:63380245baa70552542d5e2b0debe9e2eb557a1bbedcbbbc08933d5f36ff9cdb 2.22kB / 2.22kB 0.0s
=> => sha256:5e90d4e143c069feee70f90eea83d55b7b0761c67fbbfb7f3734c16c0811ac13 47.36MB / 47.36MB 27.1s
=> => sha256:3d7064acb6373ca1f0f12ecbbace9c16a2f741e61286783b17096d3db440b91c 168.55MB / 168.55MB 39.0s
=> => sha256:8df02116face90b959309647c1079aba91692478f29e5d94d8273fd09a2d5b81 5.54MB / 5.54MB 21.2s
=> => extracting sha256:4c2a0a79594a20b9c2f0bfbd535f875ca1b079625052cdd801afb1cc0362d6d0 1.7s
=> => extracting sha256:06c11c595f6421f88e1b10286a766ae8db88f67c2c0f41cedd170640aee498ab 0.3s
=> => extracting sha256:47cb22b679409f00e04b8d645444df7181f05cb2967ed73f1a377e7f774b6873 0.3s
=> => sha256:4c3170a9f3989580585e55075a7fa75d9ef013e2f35f717fad7dc4b3cc7020c4 18.01MB / 18.01MB 27.6s
=> => sha256:6abf7991c3a2713d4ec8aeb45f7bf97cb215cba09332474421baf22f1ab31e99 233B / 233B 28.0s
=> => extracting sha256:5e90d4e143c069feee70f90eea83d55b7b0761c67fbbfb7f3734c16c0811ac13 2.2s
=> => sha256:cf4935c4f818ff52eba24266f44e0aaa18dc8ce8eb758afb5dd92c2d00df255e 2.16MB / 2.16MB 29.4s
=> => extracting sha256:3d7064acb6373ca1f0f12ecbbace9c16a2f741e61286783b17096d3db440b91c 6.2s
=> => extracting sha256:8df02116face90b959309647c1079aba91692478f29e5d94d8273fd09a2d5b81 0.3s
=> => extracting sha256:4c3170a9f3989580585e55075a7fa75d9ef013e2f35f717fad7dc4b3cc7020c4 0.6s
=> => extracting sha256:6abf7991c3a2713d4ec8aeb45f7bf97cb215cba09332474421baf22f1ab31e99 0.0s
=> => extracting sha256:cf4935c4f818ff52eba24266f44e0aaa18dc8ce8eb758afb5dd92c2d00df255e 0.2s
=> [internal] load build context 0.5s
=> => transferring context: 4.84MB 0.5s
=> [ 2/13] RUN mkdir /app/ 0.5s
=> [ 3/13] ADD requirements.txt /app/ 0.0s
=> [ 4/13] RUN apt-get update -y 14.6s
=> [ 5/13] RUN apt-get install vim -y 17.0s
=> [ 6/13] RUN pip install --upgrade pip 17.7s
=> [ 7/13] WORKDIR /app/ 0.0s
=> [ 8/13] RUN pip install Cython numpy 4624.6s
=> [ 9/13] RUN apt-get install build-essential libssl-dev libffi-dev python3-dev cargo -y 57.3s
=> [10/13] RUN pip install pandas 30112.7s
そして、なぜかコンパイルに失敗する。正直原因がわからず。
#15 214.7 File "/usr/local/lib/python3.8/subprocess.py", line 516, in run
#15 214.7 raise CalledProcessError(retcode, process.args,
#15 214.7 subprocess.CalledProcessError: Command '['cargo', 'metadata', '--manifest-path', 'src/rust/Cargo.toml', '--format-version', '1']' returned non-zero exit status 101.
なぜ時間がかかるのか
piwheels: making "pip install" fast - Raspberry Piに書かれている内容をざっくり要約するとラズパイはARM
アーキテクチャのCPUを使用しており、他のアーキテクチャで作られたwheelと互換性がないため、ソースからコンパイルしている状態とのこと。
解決策4:piwheel.orgのレポジトリを使う
解決策としてはあらかじめコンパイル済みのwheelをダウンロードできるレポジトリを使用すれば時間の節約になります。piwheels.orgがコンパイル済みのwheelを提供しており、Raspbianはデフォルトでpiwheelsを参照していますが、ほとんどのdockerは参照していないと考えてよいでしょう。なので、ラズパイでpipで必要なパッケージをインストールする際はDockerfileに必ず--extra-index-url https://www.piwheels.org/simple
を付加することでpiwheelsを参照するようにします。
- piwheels: making "pip install" fast - Raspberry Pi
- python - Installing libraries via pip is taking forever. Raspberry pi 3b+ - Raspberry Pi Stack Exchang
以下は構築例です。numpy
とpandas
をインストールしています。
FROM python:3.9.2
ARG project_dir=/app/
RUN mkdir $project_dir
ADD requirements.txt $project_dir
RUN apt-get update -y
RUN apt-get install vim -y
RUN pip install --upgrade pip setuptools
WORKDIR $project_dir
RUN pip install Cython numpy --extra-index-url https://www.piwheels.org/simple
RUN apt-get install build-essential libssl-dev libffi-dev python3-dev cargo -y
RUN pip install pandas --extra-index-url https://www.piwheels.org/simple
RUN pip install cryptography --extra-index-url https://www.piwheels.org/simple
RUN pip install -r requirements.txt --extra-index-url https://www.piwheels.org/simple
試しにbuildx
で実行結果した結果です。numpy
は1分以内で構築できていますがpandas
は12時間以上実行しても終わらない結果に......ちなみに下記ではplatformをarm64
にしていますがarm/v7
でも同様にpandas
で長時間かかりました。また、buildx
で構築したイメージが動作するかは未確認です。
sudo docker buildx build --platform linux/arm64 -t HOGEHOGE .
Password:
[[中略]]
[+] Building 52839.0s (19/19) FINISHED
[[中略]]
=> [ 8/14] RUN pip install Cython numpy --extra-index-url https://www.piwheels.org/simple 43.2s
=> [ 9/14] RUN apt-get install build-essential libssl-dev libffi-dev python3-dev cargo -y 50.1s
=> [10/14] RUN pip install pandas --extra-index-url https://www.piwheels.org/simple 52195.0s
[[中略]]
ラズパイの実機(Raspberry pi 4B (8GB)
)で上記と同じDockerfileで構築してみた結果1時間以内(3181秒)でビルドできました。実機でbuild
するのとbuildx
を使うのとで差があるみたいですが、原因は私では分かりませんでした。
結論
ラズパイでDockerを構築する際はpiwheels.org
を指定すれば大幅な時間削減になるので、--extra-index-url https://www.piwheels.org/simple
をおまじないとして使ってください。