M1 Mac に Docker で Jupyter Notebook 環境を構築する

# これは何か

- M1 Mac に Jupyter Notebook の解析環境をインストールします。
    - anaconda をベースに、いくつかのパッケージを pip install します。
- Docker と Docker Compose を使って入れてみます。


# 1. Docker のインストール

- ドキュメントの通りに実施します
    -  https://docs.docker.com/docker-for-mac/install/
-  ダウンロード
    -  "Mac with Apple chip" を選びます
-  インストールします
-  Rosetta 2 をインストールしておきます

```
softwareupdate --install-rosetta
```


# 2. Docker の設定ファイルを作ります

## 2.1. ホスト PC 側のフォルダ構成
- jupyter フォルダを作って、その中に docker 関連ファイルを置くことにします
- 以下のような構成にしました
    - jupyter
        - data : jupyter からアクセスさせるフォルダです
        - docker-compose.yml : ポートやボリュームアクセスを設定するファイルです
        - Dockerfile : 解析環境を記述するファイルです

![フォルダ構成.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/107797/32368654-0bc2-479c-e240-418397f12763.png)


## 2.2. Dockerfile を準備します

- 方針
    - continuumio/anaconda3 をベースにします
    - いくつか追加で使いたいモジュールがあるので pip install します

- 以下のような Dockerfile になりました

```Dockerfile
FROM continuumio/anaconda3:latest   # debian ベースです

# reproject の pip install に gcc が必要だったので
# apt install しておきます
RUN apt update && \
    apt install -y build-essential   
                                     
# 追加でインストールしたい python モジュールです
RUN pip install astroquery \
                reproject \
                ads

# ホスト PC の data フォルダへ繋ぐ入口です
RUN mkdir /work

# jupyter の起動パラメータを設定します
EXPOSE 8888
CMD ["jupyter", "notebook", \
     "--port=8888", \
     "--ip=0.0.0.0", \
     "--allow-root", \
     "--no-browser", \
     "--NotebookApp.token=''", \
     "--NotebookApp.notebook_dir='/work'"]
```


## 2.3. Docker Compose ファイルを準備します

- 方針
    - ホスト PC の 8888 ポートを入り口にします
    - ホスト PC の jupyter/data フォルダを、コンテナ内の /work に繋げます

- 以下のような Docker Compose ファイルになりました

```docker-compose.ymml
version: "3"

services:
  notebook:
    build : ./
    ports:
      - "8888:8888"
    volumes:
      - type: bind
        source: ./data
        target: /work
```


# 3. Docker イメージをビルドする

- 初回や、設定ファイル (Dockerfile, docker-compose.yml) を修正した場合は、Docker イメージをビルドする必要があります

- jupyter フォルダ内で、次のコマンドを実行します
    - 少し時間がかかります

```
docker-compose up -d --build
```

- 無事に起動すると、docker-compose ps コマンドで状態を確認できるようになります

```
$ docker-compose ps
       Name                     Command               State                    Ports                  
------------------------------------------------------------------------------------------------------
jupyter_notebook_1   jupyter notebook --port=88 ...   Up      0.0.0.0:8888->8888/tcp,:::8888->8888/tcp
```

- 動作状況や、エラーログは docker-compose logs で確認できます

```
$ docker-compose logs                   
Attaching to jupyter_notebook_1
...
notebook_1  | [I 05:15:22.760 NotebookApp] 302 GET / (172.25.0.1) 0.740000ms
```


# 4. Jupyter Notebook に接続する

- ホスト PC 側で、web ブラウザより localhost:8888 へアクセスすると、コンテナ内の jupyter に接続できるはずです。
    - 好きに解析しましょう
    - jupyter/data の中に、シンボリックリンクを入れれば、好きな場所のファイルにアクセスさせる事ができます

# 4.1. 追加でモジュールをインストールしたくなったら

- はじめに：
    - Docker では、コンテナはイメージから起動されるたびに初期化されます。
    - 起動中のコンテナの中で行った操作は、コンテナの再起動で失われます。
    - 変更を記録させておきたい場合は、イメージをビルドし直す必要があります。
- まずは、jupyter 上の terminal でインストールの手順を整理します
    - jupyter notebook 内の、右上の、"New" から、Terminal をクリックします
    - 端末が立ち上がります
    - bash に切り替えます
        - # bash
    - インストールを試します
        - (base) root@f12b0e8c5196:/# pip install (パッケージ名)
- お試しインストールが成功したら
    - Dockerfile に pip installl (パッケージ名) を追加し、Docker イメージをビルドしなおします
- お試しインストールが失敗したら
    - 何か追加の外部ライブラリが必要かもしれません。エラーメッセージに従い、必要なものを apt install などします
    - 試行錯誤の末、インストールに成功したら、使用したコマンドを全て Dockerfile に追加する必要があります


# 5. 終了と再起動

- 終了するときは、docker-compose down コマンドを使います

```
docker-compose down
```

- 再起動するときは、docker-compose up コマンドを使います
    - --build オプションを外すと、前回ビルドしたイメージを使って起動します

```
docker-compose up -d
```