Python package "lssvr"を使うためにDockerで環境を作った苦労話

# こんな人におすすめ

- pythonのパッケージ [lssvr](https://github.com/zealberth/lssvr)を使いたい人
    - Least squares support vector regression (LSSVR) をpythonで使えるようにするパッケージ
- dockerで環境を作りたい人
- 簡単に環境を作りたい人

# 環境
- CPU : Intel(R) Core(TM) i9-9900k CPU @ 3.60GHz
- RAM : 64GB
- GPU : NVIDIA TITAN RTX (not used for this package)
- windows : windows10 Education 22H2
- wsl2 :
    - Description: Ubuntu 22.04.3 LTS
    - Release: 22.04
    - Codename: jammy

# やったことまとめ

- レポジトリは[こちら](https://github.com/oct0pus8winner/EnvironmentToTestPythonPackageLSSVR)

Dockerfileはこちら
```dockerfile
#FROM ubuntu:22.04
FROM ubuntu:20.04

ARG DEBIAN_FRONTEND=noninteractive
ENV TZ=Asia/Tokyo

# maybe obtain useless
RUN apt-get update \
    && apt-get upgrade -y \
    && apt-get -y install --no-install-recommends \
    build-essential \
    gcc \
    python3-dev \
    python3 \
    python3-pip \
    && rm -rf /var/lib/apt/lists/*

RUN python3 -m pip install --upgrade pip
# COPY requirements.txt .
COPY requirements.txt /app/requirements.txt
RUN python3 -m pip install --no-cache-dir -r /app/requirements.txt
WORKDIR /app/

CMD ["bash"]
```

用意したdocker-compose.ymlはこちら
```yaml
# docker-compose.yml to generate ubuntu 
# it needs 'Dockerfile'
# usage: 
# 1. $docker compoes up -d
# 2. $docker exec -it workspace /bin/bash

version: '3'
services:
  myapp:
    container_name: "workspace"
    build:
      context: .
      dockerfile: ./Dockerfile
    volumes:
      - .:/app
    tty: true
```

使用したパッケージ一覧(requirement.txt)はこちら
```txt
contourpy==1.1.1
cycler==0.12.0
fonttools==4.43.0
importlib-resources==6.1.0
joblib==1.3.2
kiwisolver==1.4.5
lssvr==0.1.0
matplotlib==3.7.3
numpy==1.20.0
packaging==23.2
Pillow==10.0.1
pyparsing==3.1.1
python-dateutil==2.8.2
pytz==2023.3.post1
scikit-learn==0.23.2
scipy==1.10.1
six==1.16.0
threadpoolctl==3.2.0
tzdata==2023.3
zipp==3.17.0
```
作り終わった後に`pip freeze` で作りました．

上記の３ファイルを用意した後に次のコマンドを実行すればコンテナができます．

```bash
$docker compose up -d
```

作った環境に入りたいときは次のようなコマンドを打ちます．

```bash
$docker exec -it workspace /bin/bash
```

コンテナに入った後，サンプルプログラムを動かしたいときは，
次のコマンドを実行すれば動作を確認できると思います．

```bash
$python3 example.py
```

ファイル名は気にしないでください（）

# 苦労した話

ここからは私が設定するに至った経緯や苦労した話を書いていくので，
もう興味ないよという方はブラウザバックしていただいて結構です．

## 作るに至った経緯

研究室の同期に,
"lssvrを使用したいが，自分の環境ではうまくいかない"
ということで，
私の環境でできないか試してほしいという依頼が来ました．

私もそんなにpython, docker や wsl2 での環境構築に詳しいわけではなかったのですが，
依頼を受けたのでやってみました．

学びもあったので備忘録とテクニカルライティングの練習も兼ねて記事に残したいと思います．

## 最初につまったところ

最初は次のようにubuntu22.04のイメージから作るようにしてしまってました．
（これが後々めちゃくちゃ効いてきます）

Dockerfile
```dockerfile
FROM ubuntu:22.04

ARG DEBIAN_FRONTEND=noninteractive
ENV TZ=Asia/Tokyo

# maybe obtain useless
RUN apt-get update \
    && apt-get -y install --no-install-recommends \
    build-essential \
    gcc \
    python3 \
    python3-dev \
    python3-pip \
    && rm -rf /var/lib/apt/lists/*

RUN python3 -m pip install --upgrade pip
# requirements.txt generated by using 'pip freeze'
# COPY requirements.txt .
COPY requirements.txt /app/requirements.txt
RUN python3 -m pip install --no-cache-dir -r /app/requirements.txt
#ENV PATH $PATH:/usr/include/python3.10
WORKDIR /app/

CMD ["bash"]
```

docker-compose.yml
```yaml
# docker-compose.yml to use BAM
# it needs 'Dockerfile'
# usage: 
# 1. $docker-compose up -d -> docker compoes up -d
# 2. $docker-compose exec -it bam bash

version: '3'
services:
  myapp:
    container_name: "bci"
    build:
      context: .
      dockerfile: ./Dockerfile
    volumes:
      - .:/app
    tty: true
```

requirements.txt
```txt
matplotlib
numpy
pandas
lssvr
sklearn
```

さぁ実行してみましょう．．．

なにやらエラーが
```bash
...
note: This error originates from a subprocess, and is likely not a problem with pip.
56.74         ERROR: Failed building wheel for numpy
56.74         Running setup.py clean for numpy
56.74         error: subprocess-exited-with-error
...
```

警告文で調べてみると，どうやらpythonのバージョンが悪いみたいな記事がちらほら

- ["This error originates from a subprocess, and is likely not a problem with pip."のエラーが出た](https://tech.takake-blog.com/this-error-originates/)
- [Pythonのpygameインストール時のエラーについて](https://qiita.com/sfukuhara/questions/f390182ddde657870f6a)

じゃあpythonのバージョンを変えてみよう！（安直）
ということで`python3 → python 3.9`に変更してみました．

変更後の実行結果（一部）がこちら

```shell
26.41 E: Unable to locate package python3.9-dev
26.41 E: Couldn't find any package by glob 'python3.9-dev'
26.41 E: Couldn't find any package by regex 'python3.9-dev'
26.41 E: Unable to locate package python3.9-pip
26.41 E: Couldn't find any package by glob 'python3.9-pip'
26.41 E: Couldn't find any package by regex 'python3.9-pip'

failed to solve: process "/bin/sh -c apt-get update     && apt-get -y install --no-install-recommends     build-essential     gcc     python3.9     python3.9-dev     python3.9-pip     && rm -rf /var/lib/apt/lists/*" did not complete successfully: exit code: 10
```

怒られました．

いったんpython3.9に改修したところを元に戻して，
今度は今まで自分が使ってたrequiremnts.txtを指定して
pythonとかpipがどうなっているのか確認してみました

requirements.txt
```txt
matplotlib
numpy
pandas
#lssvr <--
#sklearn<-こいつらのどっちかが悪さしてる
```

コンテナが無事起動したのでpythonのバージョンチェック
```shell
$ python3 --version
Python 3.10.12
$ pip --version
pip 23.2.1 from /usr/local/lib/python3.10/dist-packages/pip (python 3.10)
```

numpyのバージョンを変えると耐えるのかなと思いコンテナの中で実行してみた

```shell
$ pip3 install numpy==1.18.0
Collecting numpy==1.18.0
Downloading numpy-1.18.0.zip (5.4 MB)
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 5.4/5.4 MB 36.3 MB/s eta 0:00:00
Installing build dependencies ... done
Getting requirements to build wheel ... done
Preparing metadata (pyproject.toml) ... error
error: subprocess-exited-with-error
× Preparing metadata (pyproject.toml) did not run successfully.
│ exit code: 1
╰─> [59 lines of output]
Running from numpy source directory.
```

(エラーは自分がコピペしたメモなので実際完全にこれだったかは怪しいですごめんなさい)

## git からインストール

公式のレポジトリに`git`からインストールする方法が書いてあったのでやってみました

`git`から入れようとしてもやっぱりエラーで止まりました
エラーは割愛します

そもそものエラーの前に`git`を`apt-get install`
する部分でエラーに詰まったりもしました．

どうやら，dockerを使って環境を構築する際には，
必要なパッケージをインストールするために必要なパッケージ
(例えばbuild-essentialなど)
だけを先にインストールしておいて，
別のところで`RUN apt-get install ...`
としたほうがいいらしいです

ここら辺については，
dockerの公式サイトにbest-practiceに関するページがあったので，
おいおい読んでいきたいなと思います．

## 原因

結局何が原因だったかというと
- **ubuntu22.04にはデフォルトでpython3.10が入っている**
- lsvvrパッケージのpythonのバージョン比較の部分が3.10を使用することを考慮されていない

という二つの原因が組み合わさって起きていました．

怒られていたエラーをよくよく読んでいくと
```shell
Ignoring numpy: markers 'python_version == "3.6" and platform_system != "AIX" and platform_python_implementation == "CPython"' don't match your environment
Ignoring numpy: markers 'python_version == "3.6" and platform_system != "AIX" and platform_python_implementation != "CPython"' don't match your environment
Ignoring numpy: markers 'python_version == "3.7" and platform_system != "AIX"' don't match your environment
Ignoring numpy: markers 'python_version == "3.6" and platform_system == "AIX"' don't match your environment
Ignoring numpy: markers 'python_version == "3.7" and platform_system == "AIX"' don't match your environment
Ignoring numpy: markers 'python_version >= "3.8" and platform_system == "AIX"' don't match your environment
```

というわけで **3.10** がversion10ではなくversion 1 として認識されてしまっていたんですね．
（おそらく）

最終的には冒頭に貼ったようなコードになりました

用意されているパッケージにおけるpythonのバージョン比較の部分が
文字列に変換してから比較されているので発生したエラーですが，
インストールしたパッケージのものを書き換えるのはタブー（というかめちゃくちゃやばい）らしいので，
ubuntuのバージョンを下げて，再度ダウンロードしたところ成功しました
（パッケージのバージョン合わせ等の作業は行いました）

# まとめ

ubuntu22.04系にはpython3.10が入ってる！！！

作業している中で知人に聞いたりして小耳にはさんだ話ですが，
今回私が書いたみたいに昔のイメージを引っ張ってきたりすると，
イメージがそもそもなかったり，
インポート中にエラーが発生したりするのであんまりよくないらしいです．

また，今回苦労したパッケージの競合というところも，
今回はたまたま解決することができましたが，
どうしても依存関係で解決できないことがあったりするらしいです．


今までずっとDockerで環境作ってきましたが，
Dockerにもちゃんとよくないところがあるという話を改めて教えてもらいました．

すごく苦労したんですが，その分血肉になったんじゃないかなと思います．