[Docker / alpine / numpy] ERROR: Failed building wheel for numpy の対処

# 1. 概要

alpineのdocker上でnumpyをインストールしようとしたら、インストールに失敗した。

その対処法になります。

# 2. エラー文

なるべく、今回のエラーに関係しそうな部分だけを残して記載してみました。

```bash
$ docker-compose up
Starting ml_sample_postgres_1 ... done
Starting ml_sample_waitfordb_1 ... done
Starting ml_sample_web_1       ... done
web_1        | Requirement already satisfied: asgiref==3.5.0 in /usr/local/lib/python3.9/site-packages (from -r requirements.txt (line 12)) (3.5.0)

...

web_1        | Requirement already satisfied: mypy==0.931 in /usr/local/lib/python3.9/site-packages (from -r requirements.txt (line 24)) (0.931)
web_1        | Collecting numpy==1.22.2
web_1        |   Downloading numpy-1.22.2.zip (11.4 MB)
web_1        |      ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 0.0/11.4 MB ? eta -:--:     ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 11.4/11.4 MB 22.2 MB/s eta 0:00:00
web_1        |   Installing build dependencies ... done
web_1        |   Getting requirements to build wheel ... done
web_1        |   Preparing metadata (pyproject.toml) ... done
web_1        | Requirement already satisfied: psycopg2-binary==2.9.3 in /usr/local/lib/python3.9/site-packages (from -r requirements.txt (line 26)) (2.9.3)

...

web_1        | Requirement already satisfied: setuptools>=3.0 in /usr/local/lib/python3.9/site-packages (from gunicorn==20.1.0->-r requirements.txt (line 20)) (58.1.0)
web_1        | Building wheels for collected packages: numpy
web_1        |   Building wheel for numpy (pyproject.toml) ... error
web_1        |   error: subprocess-exited-with-error
web_1        |
web_1        |   × Building wheel for numpy (pyproject.toml) did not run successfully.
web_1        |   │ exit code: 1
web_1        |   ╰─> [251 lines of output]
web_1        |       Running from numpy source directory.
web_1        |       Processing numpy/random/_bounded_integers.pxd.in

...

web_1        |       WARN: don't know how to compile Fortran code on platform 'posix'
web_1        |
web_1        |
web_1        |       [Errno 2] No such file or directory: 'g++'
web_1        |
web_1        |
web_1        |       Traceback (most recent call last):
web_1        |         File "/usr/local/lib/python3.9/site-packages/pip/_vendor/pep517/in_process/_in_process.py", line 363, in <module>
web_1        |           main()

...

web_1        |
web_1        |   note: This error originates from a subprocess, and is likely not a problem with pip.
web_1        |   ERROR: Failed building wheel for numpy
web_1        | Failed to build numpy
web_1        | ERROR: Could not build wheels for numpy, which is required to install pyproject.toml-based projects
web_1        | Traceback (most recent call last):
web_1        |   File "/opt/manage.py", line 22, in <module>
web_1        |     main()
web_1        |   File "/opt/manage.py", line 18, in main
web_1        |     execute_from_command_line(sys.argv)

...

web_1        |   File "<frozen importlib._bootstrap>", line 228, in _call_with_frames_removed
web_1        |   File "/opt/mlapp/urls.py", line 2, in <module>
web_1        |     from . import views
web_1        |   File "/opt/mlapp/views.py", line 1, in <module>
web_1        |     import joblib
web_1        | ModuleNotFoundError: No module named 'joblib'
web_1        | Watching for file changes with StatReloader
web_1        | Performing system checks...
web_1        |
web_1        | Exception in thread django-main-thread:
web_1        | Traceback (most recent call last):
web_1        |   File "/usr/local/lib/python3.9/threading.py", line 973, in _bootstrap_inner
web_1        |     self.run()

...

web_1        |   File "<frozen importlib._bootstrap>", line 228, in _call_with_frames_removed
web_1        |   File "/opt/mlapp/urls.py", line 2, in <module>
web_1        |     from . import views
web_1        |   File "/opt/mlapp/views.py", line 1, in <module>
web_1        |     import joblib
web_1        | ModuleNotFoundError: No module named 'joblib'
```

# 3. 手掛かりになったエラー文

いくつかあるのですが、リストアップしていきます。
ご自身のシステム上に表示されているエラー文を1行ずつ見ていき、以下のうちどれかが見つかれば同じ原因でエラーが出ている可能性があるのかな、と思います。

- `× Building wheel for numpy (pyproject.toml) did not run successfully.`
- `[Errno 2] No such file or directory: 'g++'`
- `ERROR: Failed building wheel for numpy`
- `Failed to build numpy`
- `ERROR: Could not build wheels for numpy, which is required to install pyproject.toml-based projects`

ちなみに、`joblib`のエラーも出ていますが、これは、私がnumpyと一緒にインストールしようとしたモジュールです。
numpyのインストールに失敗したので、結局joblibもインストールできずじまいになってこのようなエラーが出ているのだと思います。

# 4. 対処法

今回は、pythonモジュール関連のエラーでよく見かける「`g++`が見つからない」というエラー文があったので、これをインストールしたところ、問題が解消しました。

具体的には、Dockerfileで`g++`も`apk add`させるようにすれば大丈夫でした。

```Dockerfile: 元々書いていたDockerfile
FROM python:3.9-alpine

RUN apk add --no-cache \
    # Necessary for pip install
    gcc libc-dev \
    # For psycopg2 (postgresql client)
    postgresql-dev

# (以下略)
```

これを、以下のように修正

```Dockerfile: 修正後のDockerfile
FROM python:3.9-alpine

RUN apk add --no-cache \
    # Necessary for pip install
    # !!!! g++ を追加 !!!
    gcc g++ libc-dev \
    # For psycopg2 (postgresql client)
    postgresql-dev

# (以下略)
```

この状態でdocker imageのbuild、containerの起動を行ったところ、numpyが無事インストールされました！\( ˙꒳˙ \三/ ˙꒳˙)/

# 5. 参考記事

alpineのせいかなと思って検索した際に見つけた記事です。

https://qiita.com/hayatek/items/42da7e66b0eeea3f3f38

この記事にはpandasの話が書いてありますが、pandasとnumpyは利用しているパッケージが結構被るので、pandas問題の対処法がnumpyの問題に効くことは結構あります！