DockerのCPUアーキテクチャの違いでハマった

# はじめに
DockerのCPUアーキテクチャ（`aarch64`と`x86_64`）の違いによってPythonの[`psutil`](https://github.com/giampaolo/psutil)ライブラリがインストールできず、それによってコンテナイメージのビルドが失敗したのでエラー内容と解決策を残しておきます。

# 実行環境
- MacOS M2チップ
- OrbStack
    - `docker info`を打つと、アーキテクチャがaarch64になっている状態
```bash
$ docker info | grep Architecture
 Architecture: aarch64
```

## Dockerfile
poetryを使って、後述の`poetry.lock`ファイルに定義されたライブラリをインストールする構成。
```Dockerfile
FROM python:3.11-slim
WORKDIR app/
COPY . .
RUN pip install poetry
RUN poetry install --no-interaction
```

## poetry.lock
poetry.lockファイルには、以下の通り`psutil`ライブラリが定義されている。
```bash
# 抜粋
[[package]]
name = "psutil"
version = "5.9.8"
description = "Cross-platform lib for process and system monitoring in Python."
optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*"
files = [
    {file = "psutil-5.9.8-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:26bd09967ae00920df88e0352a91cff1a78f8d69b3ecabbfe733610c0af486c8"},
    {file = "psutil-5.9.8-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:05806de88103b25903dff19bb6692bd2e714ccf9e668d050d144012055cbca73"},
    {file = "psutil-5.9.8-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:611052c4bc70432ec770d5d54f64206aa7203a101ec273a0cd82418c86503bb7"},
    {file = "psutil-5.9.8-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:50187900d73c1381ba1454cf40308c2bf6f34268518b3f36a9b663ca87e65e36"},
    {file = "psutil-5.9.8-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:02615ed8c5ea222323408ceba16c60e99c3f91639b07da6373fb7e6539abc56d"},
    {file = "psutil-5.9.8-cp27-none-win32.whl", hash = "sha256:36f435891adb138ed3c9e58c6af3e2e6ca9ac2f365efe1f9cfef2794e6c93b4e"},
    {file = "psutil-5.9.8-cp27-none-win_amd64.whl", hash = "sha256:bd1184ceb3f87651a67b2708d4c3338e9b10c5df903f2e3776b62303b26cb631"},
    {file = "psutil-5.9.8-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:aee678c8720623dc456fa20659af736241f575d79429a0e5e9cf88ae0605cc81"},
    {file = "psutil-5.9.8-cp36-abi3-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8cb6403ce6d8e047495a701dc7c5bd788add903f8986d523e3e20b98b733e421"},
    {file = "psutil-5.9.8-cp36-abi3-manylinux_2_12_x86_64.manylinux2010_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d06016f7f8625a1825ba3732081d77c94589dca78b7a3fc072194851e88461a4"},
    {file = "psutil-5.9.8-cp36-cp36m-win32.whl", hash = "sha256:7d79560ad97af658a0f6adfef8b834b53f64746d45b403f225b85c5c2c140eee"},
    {file = "psutil-5.9.8-cp36-cp36m-win_amd64.whl", hash = "sha256:27cc40c3493bb10de1be4b3f07cae4c010ce715290a5be22b98493509c6299e2"},
    {file = "psutil-5.9.8-cp37-abi3-win32.whl", hash = "sha256:bc56c2a1b0d15aa3eaa5a60c9f3f8e3e565303b465dbf57a1b730e7a2b9844e0"},
    {file = "psutil-5.9.8-cp37-abi3-win_amd64.whl", hash = "sha256:8db4c1b57507eef143a15a6884ca10f7c73876cdf5d51e713151c1236a0e68cf"},
    {file = "psutil-5.9.8-cp38-abi3-macosx_11_0_arm64.whl", hash = "sha256:d16bbddf0693323b8c6123dd804100241da461e41d6e332fb0ba6058f630f8c8"},
    {file = "psutil-5.9.8.tar.gz", hash = "sha256:6be126e3225486dff286a8fb9a06246a5253f4c7c53b475ea5f5ac934e64194c"},
    ]
```

# 発生したエラー

Dockerfileをビルドした際に、psutilライブラリのインストール処理が以下のエラーで失敗。
gccが見つからないとのこと。
```bash
$ docker build .
...省略

2.583   gcc -Wsign-compare -DNDEBUG -g -fwrapv -O3 -Wall -fPIC -DPSUTIL_POSIX=1 -DPSUTIL_SIZEOF_PID_T=4 -DPSUTIL_VERSION=598 -DPy_LIMITED_API=0x03060000 -DPSUTIL_ETHTOOL_MISSING_TYPES=1 -DPSUTIL_LINUX=1 -I/tmp/tmputxmmmcd/.venv/include -I/usr/local/include/python3.11 -c psutil/_psutil_common.c -o build/temp.linux-aarch64-cpython-311/psutil/_psutil_common.o
2.583   psutil could not be installed from sources because gcc is not installed. Try running:
2.583     sudo apt-get install gcc python3-dev
2.583   error: command 'gcc' failed: No such file or directory
2.583   
2.583 
2.583   at /usr/local/lib/python3.11/site-packages/poetry/installation/chef.py:164 in _prepare
2.587       160│ 
2.587       161│                 error = ChefBuildError("\n\n".join(message_parts))
2.587       162│ 
2.587       163│             if error is not None:
2.587     → 164│                 raise error from None
2.587       165│ 
2.587       166│             return path
2.587       167│ 
2.587       168│     def _prepare_sdist(self, archive: Path, destination: Path | None = None) -> Path:
2.587 
2.587 Note: This error originates from the build backend, and is likely not a problem with poetry but with psutil (5.9.8) not supporting PEP 517 builds. You can verify this by running 'pip wheel --no-cache-dir --use-pep517 "psutil (==5.9.8)"'.
2.587 
------
Dockerfile:10
--------------------
   9 |     
  10 | >>> RUN poetry install --no-interaction
  11 |     
--------------------
ERROR: failed to solve: process "/bin/sh -c poetry install --no-interaction --no-ansi" did not complete successfully: exit code: 1
```

# 切り分け
## 1. Dockerfileにgccを追加する
エラーメッセージに従い、gccが含まれた`build-essential`を追加したところ、`psutil`のインストールに成功することを確認。
```dockerfile: Dockerfile
FROM python:3.11-slim
WORKDIR app/
COPY . .

# build-essentialを追加
RUN apt-get update && apt-get install -y \
    build-essential
```
ただし、別の人の環境では`build-essential`を追加しなくても`psutil`のインストールに成功するとのこと🤔
これだと根本的な解決にならないので次へ。

## 2. Ubuntuの環境でビルド
Dockerfileに `build-essential` を追加しない状態で、
別のUbuntu環境で試したところ、`psutil`のインストールおよびビルドに成功することを確認。

違いを確認するため、ubuntu環境で`docker info`を実行したところ、アーキテクチャが`x86_64`になっていることを確認。
```bash
$ docker info | grep Architecture
 Architecture: x86_64
```

どうやらCPUアーキテクチャが怪しいぞ・・・ということで次へ。

## 3. docker buildコマンドに`--platform linux/amd64`を指定する
手元のMacで`docker info`を実行したところ、アーキテクチャが`aarch64`になっていることを確認。
```bash
$ docker info | grep Architecture
 Architecture: aarch64
```
そこで、[OrbStackの公式ドキュメント](https://docs.orbstack.dev/docker/#intel-x86-emulation)を見ると、以下の通り記載があった。

> **Intel (x86) emulation**
> On Apple Silicon, OrbStack uses Rosetta to run images built for Intel CPUs (x86_64/amd64 architecture) seamlessly with good performance. You can use multi-arch to build and run x86 and ARM images side-by-side by passing the --platform flag:

> ```
> # Run an x86 container
> docker run -it --rm --platform linux/amd64 alpine
> # Run an arm64 container
> docker run -it --rm --platform linux/arm64 alpine
>
> # Build for x86
> docker build --platform linux/amd64 .
> # Build for arm64
> docker build --platform linux/arm64 .


OrbStackでは、Rosettaを使ってx86_64をエミュレーションできるが、明示的に`--platform`オプションでアーキテクチャの指定が必要になるとのこと。

### 解決

ということで、`--platform linux/amd64`を指定したところ、`psutil`のインストールおよびイメージのビルドに成功した。

# そもそも`psutil`が`aarch64`環境にインストールできない理由
調べたところ、`psutil`は`aarch64`アーキテクチャの公式wheelを提供していないとのこと。
なので、`aarch64`環境で`psutil`を使用する際にはソースからビルドする必要があり、そのために追加のビルドツール（gccやpython3-dev）が必要になるらしい。

https://github.com/giampaolo/psutil/issues/1782

# 恒久対応
「毎回、 `--platform linux/amd64`　を指定する」

なのですが、いちいち指定するのは面倒だし忘れそうです。
この場合、Orbstackは以下の環境変数を設定することでデフォルトで`x86_64`を使用できます。
```
export DOCKER_DEFAULT_PLATFORM=linux/amd64
```
https://docs.orbstack.dev/docker/#intel-x86-emulation

# 参考
https://kuttsun.blogspot.com/2022/09/python-psutil-command-aarch64-linux-gnu.html#google_vignette