condaが管理するpythonを固定する

`conda install hogehoge`をした際に予定外のパッケージ(というか`python`)が更新されて全体が死んだので，備忘録がてら対策を書いておきます．

## 顛末

やりたかったこと: `pytorch`のdockerイメージをもとに，いくつかライブラリを足した自前イメージを作りたかった

やったこと: `Dockerfile`内に素直に`conda install`を書いた
おきたこと: `conda install`時に`python`のバージョンが変わってしまい，conda環境が破損?してまともに使えなかった

げんいん: `conda`と`python`のバージョンにミスマッチが起きた
やらなければならなかったこと(結論): `pinned`というファイル内に固定したいものを書いておく (今回は`python==3.6.*`で解決)
(もしくは更新される`python`のバージョンに合う`conda`も一緒に入れる; 今回は未実施; 参考リンクの一番下)

## 参考

[Is it possible to lock versions of packages in Anaconda? - Stack Overflow](https://stackoverflow.com/questions/48726621/is-it-possible-to-lock-versions-of-packages-in-anaconda/48733093)
[How to pin Conda | Damian's blog](http://damianavila.github.io/blog/posts/how-to-pin-conda.html)
[condaのpython versionを変更する時の注意点 - Qiita](https://qiita.com/tommarute/items/192585cc36a02d9bba97)

## やったこと詳細

以下のような`Dockerfile`を書きました(使ってる元イメージが古いのも問題の一部かもしれませんね……)．

```Dockerfile
FROM pytorch/pytorch:0.4.1-cuda9-cudnn7-devel

RUN apt update && apt upgrade -y

# 後々ここが問題になります
# joblib etc
RUN conda install -y \
    joblib \
    matplotlib \
    scikit-learn \
    tqdm
```

で，ビルド．

```bash
$ docker build -t mypytorch .
```

この際，`conda install`ではアップデートされるパッケージとしてこいつらが表示されました(後々問題になる部分)．

```
The following packages will be UPDATED:

    ca-certificates:  2018.03.07-0            --> 2020.1.1-0
    certifi:          2018.4.16-py36_0        --> 2019.11.28-py38_0
    freetype:         2.9.1-h8a8886c_0        --> 2.9.1-h8a8886c_1
    libedit:          3.1.20170329-h6b74fdf_2 --> 3.1.20181209-hc058e9b_0
    libgcc-ng:        7.2.0-hdf63c60_3        --> 9.1.0-hdf63c60_0
    libpng:           1.6.34-hb9fc6fc_0       --> 1.6.37-hbc83047_0
    libstdcxx-ng:     7.2.0-hdf63c60_3        --> 9.1.0-hdf63c60_0
    mkl:              2018.0.3-1              --> 2020.0-166
    mkl_fft:          1.0.4-py36h4414c95_0    --> 1.0.15-py38ha843d7b_0
    mkl_random:       1.0.1-py36h4414c95_1    --> 1.1.0-py38h962f231_0
    ncurses:          6.1-hf484d3e_0          --> 6.2-he6710b0_0
    numpy:            1.14.5-py36h1b885b7_4   --> 1.18.1-py38h4f9e942_0
    numpy-base:       1.14.5-py36hdbf6ddf_4   --> 1.18.1-py38hde5b4d6_1
    openssl:          1.0.2o-h20670df_0       --> 1.1.1d-h7b6447c_4
    pip:              10.0.1-py36_0           --> 20.0.2-py38_1
    python:           3.6.5-hc3d631a_2        --> 3.8.1-h0371630_1
    readline:         7.0-ha6073c6_4          --> 7.0-h7b6447c_5
    scipy:            1.1.0-py36hc49cb51_0    --> 1.4.1-py38h0b6359f_0
    setuptools:       39.2.0-py36_0           --> 45.2.0-py38_0
    six:              1.11.0-py36h372c433_1   --> 1.14.0-py38_0
    sqlite:           3.23.1-he433501_0       --> 3.31.1-h7b6447c_0
    tk:               8.6.7-hc745277_3        --> 8.6.8-hbc83047_0
    wheel:            0.31.1-py36_0           --> 0.34.2-py38_0
    zlib:             1.2.11-ha838bed_2       --> 1.2.11-h7b6447c_3
```

## おきたこと詳細

ビルドが終わったので意気揚々とコンテナを作ります．

```bash
$ docker run -it --rm mypytorch bash
```

コンテナ内で`conda`系のコマンドを使おうとするとあら不思議，動きません．

```bash
root@ce88f6b1ba73:/workspace# conda
Traceback (most recent call last):
  File "/opt/conda/bin/conda", line 7, in <module>
    from conda.cli import main
ModuleNotFoundError: No module named 'conda'
```

その他`ipython`が動かなかったり，仕方ないので以下のように`python`から試そうとしてもだめだったり．

```bash
root@ce88f6b1ba73:/workspace# python
Python 3.8.1 (default, Jan  8 2020, 22:29:32)
[GCC 7.3.0] :: Anaconda, Inc. on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import torch
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ModuleNotFoundError: No module named 'torch'
>>>
```

ということで，動かしたいものがなにひとつ動かない状態のイメージが出来上がってしまいました．

## やらなければならなかったこと

ここが問題でした．`python`のバージョンが3.8.1に更新されています．

```
The following packages will be UPDATED:

...
    python:           3.6.5-hc3d631a_2        --> 3.8.1-h0371630_1
...
```

どうも`conda`のバージョンを変えないまま`python`だけが更新されると動かなくなってしまうようです．解決には以下のふたつの方法があります．

1. `conda`と`python`を一緒に更新する
2. `python`のバージョンを固定する

今回はバージョンを固定するほうでいきます．バージョンの固定には，anaconda/minicondaの管理ディレクトリ以下`conda-meta/pinned`に固定したいものを書けばOKです(複数の環境を作っている場合どういう扱いになるかは未検証です)．

今回は`python`を3.6系に固定するため，以下のようになります(ここではインストール先が`/opt`です．これはお使いの環境によって異なります)．

```bash
$ echo "python=3.6.*" >> /opt/conda/conda-meta/pinned
```

これがDockerfileに入っていればうまくいきます．つまり以下のようになります．

```Dockerfile
FROM pytorch/pytorch:0.4.1-cuda9-cudnn7-devel

RUN apt update && apt upgrade -y

# conda install前にバージョンを固定
RUN echo "python=3.6.*" >> /opt/conda/conda-meta/pinned

# joblib etc
RUN conda install -y \
    joblib \
    matplotlib \
    scikit-learn \
    tqdm
```

------


あまり多くはおきない事故だとは思いますが，誰かの参考になれば幸いです．