DockerでAnaconda環境構築+jupyterの分析環境を整える

#0.はじめに
SIGNATEで「[日本取引所グループ ファンダメンタルズ分析チャレンジ](https://signate.jp/competitions/423)」というコンペが開催されています。私も参加していますが、その中で出てくる知識に関して基礎部分をまとめよう！という動機の記事第3弾(最終回)です。

本コンペのチュートリアルではDocker環境でサンプルコード(.ipynb )が動くようになっていて、結構運営への質問も多かったようである。私事ですが最近実務でもクラウド/コンテナを勉強しなければならなくなったので、本記事はその備忘録も多少兼ねています。

* 動作環境
 * OS : Windows10 pro (Ver.2004)
 * Docker : 20.10.2

#1.Dockerって何なのか？
これに関しても溢れるほど解説記事がありますが、**本記事は自分自身の備忘録を兼ねる**為、理解に必要な周辺知識含めて`なるべく平易な用語を使って`私なりの理解を改めて書いておこうと思います。
**※なおサーバやインフラ系の知識については自分自身もまだ勉強中な身**ですので、悪しからず。

・**仮想環境(PC)とは？**
「1つの物理的なPC(OS)の中で別の仮想的なPC(OS)を動かす」こと。
pythonをやっている方の場合「conda」等の仮想環境を思い浮かべてもらえるとわかりやすいかも。
あれは「この検証にはpython3.6を使いたいけど、あの検証にはpython3.8が使いたい！」という時に実行環境を分けることができますよね？ これをpythonだけではなくて別の言語、はたまたOSまで使い分けたい！という場合にこの仮想環境が必要なのである。

・**Dockerとは？**
↑で説明した仮想化環境を提供するソフトウェア(Docker社が公開しているOSS)の1つ。`仮想化環境の実現に「コンテナ型」という技術を使っている`。
なお、`Dockerを動かすためのOSにはlinuxが必要`である。
よって`Windowsの場合はWSL(Windows Subsystem for Linux)というものを使用することでDockerを使えるようになる`。

・**で、そのコンテナって何？**
データとかプログラムとかOS(正確にはOSっぽいもの)とかを細かい部屋に分ける「仕切り(物置)」のこと。`その物置を別のPC(環境)にそのまま移設することも出来る`ので、貿易船で積み荷として輸送されるコンテナみたいだね！っていうことで「コンテナ」と名付けられているらしい。
Dockerの場合、`Dockerエンジン`を使うことでこのコンテナが使えるようになる。


<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/373060/a1ca830d-88c9-5365-2ec7-8590eebd15e3.png" width=30%>


・**(Docker)コンテナイメージとは？**
貿易コンテナの中には当然「荷物」が入っているはずである。その積み荷を「コンテナイメージ」と呼んでいる。
CD-Rを例にすると、CD-Rの中に入っているデータがまさにここでいうイメージである。(CD-Rは持ち運んで色々なPCにインストールできるのでコンテナとも言えるかも・・)

通常は`OS(linuxとかWindowsとか)＋アプリ(pythonとかTensorflowとか)がインストール済の環境をまとめたものが積み荷(イメージ)として存在する`。
コンテナイメージ自体は、一般的に企業や有志が誰でも使えるように配布していて、我々はそのイメージをコンテナに格納することで全く同じ環境を簡単に構築できるというわけである。
**[Docker Hub](https://hub.docker.com/)**というサイトでこの配布されているイメージを確認可能。

また、当然逆に自作コンテナからイメージを作ることもできる。
配布されているイメージで足らない分を自分で改造すれば、その改造コンテナを新イメージとして作ることもできる。

・**2台の物理PCにそれぞれ環境を作るのと何が違うの？**
物理的な環境が違っていたり、PC構成が微妙に違っていても「意識せずに同じ環境が用意できる」ことが強み。
1台目のPCで苦労して環境構築し、同じ環境を2台目にも。。という場合に「あれ？うまくいかない」という場面はみんな経験したことがあるのではないだろうか？　`Qiitaを見てみても「環境構築」の記事がたくさん見受けられるということは、みんなそれだけ微妙な構成違いで苦しんでいるということの裏返し`なのである。

つまり、`どんな環境でも絶対に動いてほしい場合にこのコンテナ(Docker)という技術はとても重宝する`のである

・**でなんで、色々な仮想化手法がある中でDockerがいいの？**
とにかく動作が軽い。
詳細は記載しないが、「OSの一部機能をホストPC(物理PC)に託している」ことが軽量につながっているらしい。※これが「OSっぽいもの」と呼んでいる正体。実際には完全なOSではないのである。

#2.Dockerの導入
過去に素晴らしい解説記事があったので、この記事を参照して環境構築してください。
**なお、私のPCはwindows10 proですが今はWindows10 Homeでもproでも↓の方法で構築すればOK**なはずです。(この手の記事でよく出てくるHyper-VはWSL2になってからは不要です)

参考記事：[WindowsでDockerを始める手順](https://qiita.com/techpit-jp/items/f4a1319a909dd508f372)

※もしかしたらWin10のバージョンが古いと失敗するかもですが、その場合は現時点(2021/2時点)最新のVer.2004にアップデートしてください。


#3.Dockerでpython(Anaconda)環境を構築
Anacondaの公式がDockerイメージをDocker hubで公開しているのでこれを使うだけ。
・[continuumio/anaconda3 – Docker Hub](https://hub.docker.com/r/continuumio/anaconda3) 
↑がAnacondaの配布イメージのページである。もしAnacondaの古いバージョンで作成したい場合は「Tags」の中に入っている。


コンペの中では「Anaconda3 2019.03」のコンテナイメージ(以下参考図)を使っているので、今回はそれを例として進める。まずはコンテナイメージから取得する。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/373060/7d1a0365-061e-2506-1d85-4fecb37e38e5.png" width=90%>

```cmd:
※コマンドプロンプトにて
docker pull continuumio/anaconda3:2019.03
```

これでAnacondaイメージを取得できた。ちなみにこの時「このAnacondaイメージってなんのOSっぽいものが一緒に使われてるんだ？？」って疑問に思ったのでそれも調べてみる。

```cmd:
※コマンドプロンプトにて
docker inspect --format="{{ .Os}}" continuumio/anaconda3:2019.03
```

```:実行結果
linux
```
つまりこのAnacondaイメージで一緒になっているOSはlinuxということがわかった。
JupyterはこのAnacondaの中に入っているので、これを使う。


#4.コンテナ経由でjupyter notebookを起動

落としてきたイメージをコンテナに乗せて起動し、jupyterをそこから起動させていく。
その際に「**マウント**」といって、`自分のPCのローカルフォルダとDockerの中のディレクトリ(フォルダ)を同期`させるようなことを今回はしていく。
このマウントをすることで、コンテナから外部(自分の指定したフォルダ)を操作することができるようになる。

###4-1.まずは落としてきたイメージの確認

```cmd:
docker images
```
```:実行結果
REPOSITORY              TAG　　　　　IMAGE ID       CREATED         SIZE
continuumio/anaconda3   2019.03　　　　(略)　　　　　　(略)　　　　　(略)
```

先程`docker pull`で落としてきたanaconda3のイメージがあることが確認できた。

###4-2.コンテナの作成、コンテナ内のディレクトリ構造確認

下のコマンドでイメージからコンテナを作成し、rootディレクトリに入ることが出来る

```cmd:
docker run -it　continuumio/anaconda3:2019.03
```
```:実行結果
(base) root@*****:/#
```
このままlinuxの直下ファイル確認コマンド(ls)を押せばroot直下のコンテナ内ディレクトリ等が確認可能

```cmd:
ls

※(base) root@*****:/#の中で実行している
```
```:実行結果
bin  boot  dev  etc  home  lib  lib64  media  mnt  opt  proc  root  run  sbin  srv  sys  tmp  usr  var
```

今回は「マウント」を行うので、コンテナ内のどのディレクトリにマウントするか？を考える上でディレクトリ構造の把握をしておくといい。
ちなみに、`(base) root@*****:/#(コンテナ)`の中から抜け出すには「`exit`」コマンドを入力すればいい

###4-3.マウント設定等を反映させてコンテナを起動する
まずは、Windows側でコンテナ側とマウントさせたいフォルダ(コンテナ側のjupyterから直接参照させるフォルダ)を作成しておく

```Python:
#　Windows側のディレクトリ構成 
#「docker_sample 」の直下にIPython(jupyterのプログラム)を配置させる ※ここをマウント対象にする
#「data_dir」の中にjupyterで読み込むようなデータを入れる想定

''' Windows側ディレクトリ
Desktop -- docker_sample -- data_dir -- 共有するファイル(csvとか画像とか)
'''
```

Windows側の準備が終わったならば、まずはjupyterプログラムを配置させるディレクトリへ移動しておく。

```cmd:
cd C:\Users\***\Desktop\docker_sample

※ディレクトリをjupyterを起動させたい場所にしておく
```

次にマウント設定等をした上でのコンテナ起動コマンドを実行する

```python:
"""
【docker run + オプション(下記) + イメージ】
--name　→　コンテナ名を指定(なくてもいい)
-v　→　マウント指定(コロンの左側がローカル側、右側がコンテナ側のpath)
-p　→　ポート接続(コロンの左側がローカル側、右側がコンテナ側※jupyterは8888)
--rm　→　コンテナ終了時にコンテナ自動的に削除
--it　→　ホスト側のターミナルからコンテナ内部の操作
※^　は長いコマンドの場合に改行の意味を示すコマンド(キャレット)
※-v "%cd%":/notebook　の意味は「ローカル側が未記載≒今のpath(docker_sample)」、
「コンテナ側はnotebookフォルダ」をマウントさせるという意味。
notebookフォルダはデフォルトでは存在しないのでコンテナ側で作成される
"""

docker run --name docker_practice ^
-v "%cd%":/notebook ^
-p 8888:8888 --rm -it continuumio/anaconda3:2019.03
```
```:実行結果
(base) root@****:/#
```
これでローカル側をマウントした上でコンテナを起動できた！
後は、この起動したコンテナの中でjupyterを起動するだけである

```python:
"""
jupyter notebook以下は起動オプション。ここでの説明は省略する。
最後の「/notebook」はなくてもいいが、つけておくと最初のjupyter起動ディレクトリがマウントさせているnotebookになる
※この時点ですでに「コンテナ」に入っているのでlinux環境。改行が^ではなく、バックスラッシュになる
"""
jupyter notebook --ip 0.0.0.0 --allow-root --no-browser \
--NotebookApp.disable_check_xsrf=True  --NotebookApp.token='' \
--NotebookApp.password='' /notebook
```

```:実行結果
・・・略・・・
[I **:**:** NotebookApp] The Jupyter Notebook is running at:
[I **:**:** NotebookApp] http://*****:8888/
```

後は、ブラウザから`http://localhost:8888/ `でjupyterを起動すれば、docker_sampleをマウントした「notebook」ディレクトリでスタートする。
そしてローカル側でマウントさせたフォルダ直下であれば、適当にファイルを入れればjupyter側(コンテナ側)でも同様に確認できるはず。


![キャプチssssャ.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/373060/084d686a-3c8e-588b-93ff-60bb8fe663e3.png)


そして、適当にプログラムを作成して下のようなコマンドを入れれば、今このjupyterがいるディレクトリがコンテナ側のマウントディレクトリ「/notebook」であることがわかる。
これで後は好きに分析をやっていけばいい。
※jupyterでは、%を入れることでlinuxコマンドを扱える。`%pwd`で今自分がいるpathを表示できる

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/373060/677d6d8f-fa2c-9ce5-91dd-551238c26a95.png" alt="対象ページの検証" width=60%>

#5.おわりに
どうだったであろうか？
ちなみに今回長々と記事にしたものは、本来Dockerでは1命令で全て完結できる。
(イメージのダウンロードも実は不要。無ければ勝手にダウンロードする仕組み)
しかし`↓の命令をいきなり見ても、慣れていない人にはアレルギーが出る`ので、細かく分けて説明してきた。
本記事はDockerのほんの取っ掛かりにすぎず、まだまだ色々知ることはあると思うが、この記事をとっかかりにDockerで色々作業をしていってくれると私も報われます。一緒に勉強していきましょう

```python:
"""
Windows側のフォルダ準備やチェンジディレクトリ(cd)さえしておけば、
本記事の解説内容は実はこの1命令で済んでしまう(実際のコンペチュートリアルはこれだけが書かれていた)
"""
docker run --name docker_practice -v "%cd%":/notebook ^
-p 8888:8888 --rm -it continuumio/anaconda3:2019.03 ^
jupyter notebook --ip 0.0.0.0 --allow-root --no-browser ^
--NotebookApp.disable_check_xsrf=True  --NotebookApp.token='' ^
--NotebookApp.password='' /notebook
```