Raspberry PI上のPython-slimコンテナ（Debianベース）でrustc依存のパッケージ構築に苦労した話

初投稿です．今後よろしくお願いします．

ある研究案件でRaspberry PI上のPythonのslimコンテナ（執筆時python:3.9-slim）にpip経由で色々入れようとしたところいろいろ躓いたのでメモ<br/>
Debianのaptで入るrustが古かったり，Dockerfile内でのPATH変数の更新などで一苦労しました<br/>
最後に書きますが，今のところこの方法じゃない方がよいかもです．

2023.02.02追記
Arm32v7環境のみです．Arm64v8環境では特に問題なくpipによるインストールが通ります

<h1>前提条件</h1>
OS: Rasbian( on Raspberrypi4 )<br/>
Docker及びDocker-composeをapt経由でインストール<br/>
Dockerfile内にpip経由でbcryptを含むいくつか（主にFlask関係）をインストールする文を書いた<br/>
ベースコンテナはpython:3.9-slim

<h1>経緯</h1>
面倒な方は<a href="#Conclusion">結論</a>だけどうぞ
<h2>出てきたエラー</h2>

~~~Dockerfile
From: python:3.9-slim
.....
RUN pip install bcrypt....
~~~
とbcryptパッケージのpipインストールを含むコンテナ（例えばdocker-composeやFlask-bcryptなど)を構築しようとすると
```console
  error: can't find Rust compiler
``` 

でbcryptパッケージのインストールがこけます
Rustのコンパイラが見つからないようです
<h3>対策1</h3>
apt-get install rustc を追加
<h3>結果</h3>

~~~console
This package requires Rust >=1.56.0.
~~~

執筆時点でのPython:slimコンテナのベースはDebian(Bullseye)，apt経由で入るrustは1.42
古いのが入ってしまいました
<h3>対策2</h3>
<a href=https://www.rust-lang.org/learn/get-started>本家</a>の情報を元にインストールシェルをcurlで落として来て実行．<br/>
なお，本家シェルファイルはInteractiveな形式なので本家のInstructionにある<br/>

~~~Dockerfile
RUN curl https://sh.rustup.rs -sSf | sh
~~~
ではなく
~~~Dockerfile
RUN curl https://sh.rustup.rs -sSf > /rust.sh && sh /rust.sh -y
~~~
としています．そのままshに投げると躓きます．
なお，slimコンテナではgccパッケージもomitされてるので事前にapt-get gccしないとコケます．
<h3>結果2</h3>

~~~Cosole
error: can't find Rust compiler<br/>
~~~

入れたはずのrustが見つかりません
どうやらPATHが通ってない様子
そもそも本家インストールシェルの最後にsource $HOME/.cargo/env を実行しろと出るくらいなのでPATHはいじってくれない様子
Dockerfileはsh環境で実行されるので愚直にsource..とやるとアウトです
sourceの代わりに . $HOME/.cargo/envとやりますが．．．コケます
その代わりに直打ちでPATHに追加してみました
<h3>対策3</h3>
Dockderfileに以下のrustcへのPATHを追加<br/>

~~~Dockerfile
RUN PATH=$PATH:/root/.cargo/bin
~~~

<h3>結果3</h3>
何故かまた見つかりません．<br/>

ここで調べたら以下の記事を発見
<a href=https://www.baeldung.com/ops/dockerfile-path-environment-variable>Updating PATH Environment Variable in Dockerfile</a>
Dockerfile開発中はRUN構文を小分けにすることもあるかと思いますが
（少なくとも自分はそうして，ある程度固まってからまとめてます）
<span style=font-weight:bold;>RUN構文でPATH変数を更新しても恒久的には変わらないのだそうです．</span>

ということで
<h2>最終対策</h2>
pip installと同じRUN文にPATH追加分を合わせて書きます

~~~
RUN PATH=$PATH:/root/.cargo/bin && pip install .....
~~~

ようやく通りました.
参考記事では
~~~Dockerfile
ENV PATH=$PATH:<追加PATH>
~~~
する方法もあるよ，と書いています
（個人的にはコンポーネント入ってからPATHいじるものだろという固定概念があったので目から鱗でした）

<h2>そもそも</h2>
途中で開発環境入れたりするせいか，slimコンテナの恩恵であるサイズがむしろ通常コンテナをベースにした時より大きくなってます．

(注：まだチューニングしてないため今後改善する可能性あり）
（投稿後4時間後追記）コンテナの仕様も大分固まったので一つのRUN文でrustcの導入，bcryptのインストール，rustc他開発環境の削除までやってみました．
結果だらだらRUN文を並べていたころに比べイメージの容量が6分の1になりました<br/>
また詳しい方ならapt-get install python3-bcrypt　とかでいけんじゃね？と思われるかと思いますが，今のところ自分の環境では
apt経由で入れたパッケージがpip経由のpythonパッケージから見つけららず，~~別途調査中です~~ ( <a href=https://qiita.com/drafts/2cba2e97000f3cce855c>追加記事参照ください</a> )
rustとか入れなくていいようにbcrypt関係だけaptで入れてみたところ，pipで入れたflaskから見つからないのでPATHを通す必要がありました

<h1 id="Conclusion">結論</h1>

~~Dockerfile内でのPATH変数の挙動が分かっただけでもいっか~~
Pythonのslimタグが付いたコンテナだとbcryptパッケージのインストールに失敗するので
Dockerfile内に
~~~Dockerfile
RUN apc-get install gcc
~~~
した上で
~~~Dockerfile
RUN curl https://sh.rustup.rs -sSf > /rust.sh && sh /rust.sh -y
~~~
でRustの最新コンパイラを入れて，
~~~Dockerfile
RUN PATH=$PATH:/root/.cargo/bin && pip install ....
~~~
とすると通ります
但しコンパイラのコンパイルからやるので1時間近くかかります．．