5分でできるTensorflow Jupyter notebook on Docker on VirtualBox

タイトルの通りVirtualBox上のUbuntuでTensorflowとJupyter notebook用コンテナをインストールした時のメモです。
何番煎じかわかりませんがメモとして残しておきます。

# 環境

- Windows 10 pro 1809
- VirtualBox 6.0.4
- Ubuntu 18.04.2
- Docker 18.09.2

母艦PCにはWindows10 Proを使用していて、そこでVirtualBoxにUbuntuをいれて、UbuntuにDockerをインストールしています。
docker on VirtualBox on Windowsな環境で動かしています。

# インストール

tensorflowをjupyter環境のあるコンテナをダウンロードしてきます。ダウンロード後`docker images`コマンドで確認するとイメージが存在することがわかります。

```
~$ docker pull jupyter/tensorflow-notebook
：
Status: Downloaded newer image for jupyter/tensorflow-notebook:latest
~$ docker images
REPOSITORY                    TAG                 IMAGE ID            CREATED             SIZE
jupyter/tensorflow-notebook   latest              5246106207ee        18 hours ago        4.78GB
```

# コンテナの起動

サーバとして動かしたいので`-d`オプションを付けます。`-p 8088:8888`はホスト側(Ubuntu)の8088番ポートにアクセスするとコンテナの8888番ポートにフォワーディングするようにします。`--name jupyter`はコンテナにjupyterという名前を付けます。`-v /home/yoshi/docker/jupyter:/home/jovyan/work`はホストの/home/yoshi/docker/jupyterをコンテナの/home/jovyan/workにマウントします。ホスト側は好きなディレクトリで良いですが、コンテナ側はこのディレクトリにしてください。`--name`と`-v`オプションは必要ない場合はつけなくても大丈夫です。

`docker run`で起動した後`docker ps -a`コマンドでコンテナが実行されていることが確認できます。

```
~$ docker run -d --name jupyter -p 8088:8888 -v /home/yoshi/docker/jupyter:/home/jovyan/work jupyter/tensorflow-notebook
9e16f3294d6baf1a9beb650024ea5cc91acc2663fbd580907efe8cde79bcbe78

~$ docker ps -a
CONTAINER ID        IMAGE                         COMMAND                  CREATED              STATUS              PORTS                    NAMES
9e16f3294d6b        jupyter/tensorflow-notebook   "tini -g -- start-no…"   About a minute ago   Up About a minute   0.0.0.0:8088->8888/tcp   jupyter
```

# セキュリティトークンの取得

jupyter notebookはセキュリティトークンが設定されていてアクセス制限されているため、`docker exec <コンテナID> jupyter note book list`コマンドでトークンを取得します。`?token=`以下の文字列がトークンになりJupyter notebookにアクセスするときに必要になります。

```
~$ docker exec 9e16f3294d6b jupyter notebook list
Currently running servers:
http://0.0.0.0:8888/?token=c45fe6b415b5ecd82a4c7eb5cd91e6080b66239c9d156f38 :: /home/jovyan
```

# VirtualBoxのポートフォワーディング

windowsからアクセスするためVirtualBoxのポートフォワーディングの設定が必要になります。windowsの8008番ポートにアクセスするとUbuntuの8088番ポートにポートフォワーディングするようにします。

VirtualBox マネージャー-->設定-->ネットワーク-->高度の三角マークを押すとポートフォワーディングのボタンが登場するので押します。

![Tensorflow_Jupyternotebook_on_Docker_00.jpg](https://qiita-image-store.s3.amazonaws.com/0/271649/a29c8368-370e-bebe-f2a6-704147703cbb.jpeg)

基本好きな値で良いですが次のように設定します。名前は何でも良いので`jupyter`で、プロトコルは`TCP`でホストIPはローカルアドレスの`127.0.0.1`。ホストポートは`8008`で、これはjupyter nootbookにアクセスするときにこの値をブラウザに指定します。ブラウザで指定する値と同じにすればwell known portを除けばなんでも良いです。ゲストIPはUbuntu上で`ip a`で調べた値を入れます。ゲストポートは`docker run`する時に指定した値と同じ`8088`にする必要があります。

![Tensorflow_Jupyternotebook_on_Docker_01.jpg](https://qiita-image-store.s3.amazonaws.com/0/271649/8c591721-de38-61a0-a07e-f0d3b28e3d03.jpeg)

```
~$ ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host 
       valid_lft forever preferred_lft forever
2: enp0s3: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
    link/ether 08:00:27:7e:e7:dd brd ff:ff:ff:ff:ff:ff
    inet 10.0.2.15/24 brd 10.0.2.255 scope global dynamic enp0s3
       valid_lft 80494sec preferred_lft 80494sec
    inet6 fe80::a00:27ff:fe7e:e7dd/64 scope link 
       valid_lft forever preferred_lft forever
3: docker0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default 
    link/ether 02:42:77:6c:2c:ae brd ff:ff:ff:ff:ff:ff
    inet 172.17.0.1/16 brd 172.17.255.255 scope global docker0
       valid_lft forever preferred_lft forever
    inet6 fe80::42:77ff:fe6c:2cae/64 scope link 
       valid_lft forever preferred_lft forever
25: veth3b86037@if24: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 state UP group default 
    link/ether 26:df:bc:10:5b:49 brd ff:ff:ff:ff:ff:ff link-netnsid 0
    inet6 fe80::24df:bcff:fe10:5b49/64 scope link 
       valid_lft forever preferred_lft forever
```

# jupyter notebookにアクセス

`docker exec`コマンドを実行した時に表示された、後ろにトークンが付いたアドレスをアドレスを`127.0.0.l`に変更して、ポート番号をVirtualBoxのポートフォワーディングの設定でホストポートに指定した値`8008`に変更してアクセスします。

![Tensorflow_Jupyternotebook_on_Docker_02.jpg](https://qiita-image-store.s3.amazonaws.com/0/271649/e8216ed5-8ed8-83cb-77aa-73af516ae872.jpeg)

すると次のようにページが表示されました。ばんざーい(^^)/

![Tensorflow_Jupyternotebook_on_Docker_03.jpg](https://qiita-image-store.s3.amazonaws.com/0/271649/33d11a1f-9f5b-5a6c-140f-0fb02b6f2ad7.jpeg)

# ポンチ絵

雑ですがポンチ絵で表すとポートフォワーディングの様子はこんな感じです。Jupyter notebookの`8888`は固定ですがVirtualBoxとWindowsのポートは好きなポートに変更して大丈夫です。

![Tensorflow_Jupyternotebook_on_Docker_04.jpg](https://qiita-image-store.s3.amazonaws.com/0/271649/e91ba706-a376-a9e5-6d1b-00328cf0e92d.jpeg)