dockerコンテナ内の複数python環境に外部から接続する方法（jupyter-notebook利用）

## はじめに
以前に`venv`を使った仮想環境の構築について記事を書いたことがあるが、コンテナ内にPython環境を構築して外部からそこにアクセスする使い方は自分で試した事がなかったため、今回はそれを試してみる。


## 実行環境
【Docker導入環境】
　　・Ubuntu 20.04 LTS（GCP上）
　　・docker 19.03.13
　　・docker-compose 1.25.0


## 手順
１．環境準備
２．コンテナ構築用のDockerfile作成（2つ）
３．`docker-compose.yml`でコンテナ起動
４．操作確認

## １．環境準備

**GCP上にVMインスタンスを作成**
　※イメージはUbuntu20.4 LTS

**パッケージ管理ツールのアップデート**

```
$ sudo apt update
$ sudo apt -y upgrade
```

**dockerのインストール**
　[【Dockerコンテナ内のUbuntuではsystemctlは使えない】](https://qiita.com/smiler5617/items/2a33d1aba0174480e9d3)の手順１を参考に。

**docker-composeのインストール**

```shell:
$ sudo apt install -y docker-compose 
```

問題なくインストールできているか確認

```shell:
$ docker-compose --version
docker-compose version 1.25.0, build unknown
```

## ２．コンテナ構築用のDockerfile作成（2つ）

Dockerfile格納用のディレクト作成

```shell:
$ sudo mkdir ./con1
$ sudo mkdir ./con2
```

**Dockerfileの作成**

コンテナ１のDockerfile作成

```shell:
$ sudo nano ./con1/Dockerfile
```

```Dockerfile:Dockerfile
# ベースイメージの取得
FROM python:3

# 適当にパッケージのインストール
RUN pip install jupyter notebook
RUN pip install numpy

# マウント用のディレクトリを作成
RUN mkdir /root/analysis

##########################
# コンフィグファイルの設定#
##########################

RUN jupyter notebook --generate-config
# ⇒このコマンドにより [/root/.jupyter/jupyter_notebook_config.py] が生成される

# jupyter-notebook上のホワイトリストを許可（ホスト側でファイウォールを設定するためOK）
RUN echo "c.NotebookApp.ip = '0.0.0.0'" >> /root/.jupyter/jupyter_notebook_config.py

# 初期ディレクトリの設定
RUN echo "c.NotebookApp.notebook_dir = '/root/analysis'" >> /root/.jupyter/jupyter_notebook_config.py

# パスワード認証 or Token認証を無効化（公式では非推奨）
RUN echo "c.NotebookApp.token = ''" >> /root/.jupyter/jupyter_notebook_config.py
RUN echo "c.NotebookApp.password = ''" >> /root/.jupyter/jupyter_notebook_config.py

# ポート開放
EXPOSE 8888

CMD ["jupyter", "notebook","--allow-root"]
```

　

コンテナ２のDockerfile作成（インストールパッケージ以外１と同じ）

```shell:
$ sudo nano ./con2/Dockerfile
```

```Dockerfile:Dockerfile
# ベースイメージの取得
FROM python:3

# 適当にパッケージのインストール
RUN pip install jupyter notebook
RUN pip install pandas

# マウント用のディレクトリを作成
RUN mkdir /root/analysis

##########################
# コンフィグファイルの設定#
##########################

RUN jupyter notebook --generate-config
# ⇒このコマンドにより [/root/.jupyter/jupyter_notebook_config.py] が生成される

# jupyter-notebook上のホワイトリストを許可（ホスト側でファイウォールを設定するためOK）
RUN echo "c.NotebookApp.ip = '0.0.0.0'" >> /root/.jupyter/jupyter_notebook_config.py

# 初期ディレクトリの設定
RUN echo "c.NotebookApp.notebook_dir = '/root/analysis'" >> /root/.jupyter/jupyter_notebook_config.py

# パスワード認証 or Token認証を無効化（公式では非推奨）
RUN echo "c.NotebookApp.token = ''" >> /root/.jupyter/jupyter_notebook_config.py
RUN echo "c.NotebookApp.password = ''" >> /root/.jupyter/jupyter_notebook_config.py

# ポート開放
EXPOSE 8888

CMD ["jupyter", "notebook","--allow-root"]
```


## ３．`docker-compose.yml`でコンテナ起動

Notebook起動時の初期ディレクトリをホスト側に準備
　※初期ディレクトリは、各コンテナ毎にマウント先を指定したいたいめ。

```shell:
$ sudo mkdir ./con1/analysis_file
$ sudo mkdir ./con2/analysis_file
```

**`docker-compose.yml`の作成**

```shell:
$ sudo nano ./docker-compose.yml
```

```yml:docker-compose.yml
version: '3.7'

services:
  python1:
    build:
      context: ./con1
      dockerfile: Dockerfile
    volumes:
      - ./con1/analysis_file:/root/analysis
    ports:
      - 8080:8888

  python2:
    build:
      context: ./con2
      dockerfile: Dockerfile
    volumes:
      - ./con2/analysis_file:/root/analysis
    ports:
      - 8081:8888
```


## ４．操作確認

**全サービスの起動**

```shell:
$ docker-compose up
```
　※初回起動時は、ビルドやイメージのダウンロードが自動で開始される。

以下のURLにアクセスして、認証なしでnotebookが開くか確認する。
　　`http://[VMの外部IP(グローバルIPアドレス)]:8080/`
　　`http://[VMの外部IP(グローバルIPアドレス)]:8081/`
　

試しに`port:8080`で開かれるnotebookで`import`コマンドを実行してみると、`./con1/Dockerfile`でパッケージインストールされていないものはできないはず。

また、作成したファイルはホスト側のディレクトリをマウントしていて、そこをjupyter noteobookの初期ディレクトリに設定しているため、作成ファイルはホスト側上で永続化されるはず。