Jupyter on Dockerでパスワードの設定方法が分からないあなたへ

# はじめに
機械学習試したい→Tensorflowでしょ
Web上でインタラクティブに試したい→Jupyterでしょ
手軽にインフラ構築したい→Dockerでしょ
ってことで、やってみたけど、パスワードどこで設定するねんって詰まっちゃったので、その解法書いておきます

## 想定読者
下記に当てはまる人

- インフラエンジニアだけど機会学習試したい
- Docker最近触ってるけど詳しくわからん
- Pythonちょっと触ってるけどあんま知らん
- Jupyterいいんちゃう？知らんけど

## Dockerを使う理由
基本的に今持ってるMacBook Airで試せるならしたいけど、明らかにリソースが足りない。
なので、がっつりやるならAWSやGCPなどのクラウド上がベスト解です。
ローカルであたりをつけてからクラウドへ持っていきたいので、それが一番楽で、かつ最近流行ってるものと言えば、そう、Dockerです。
Jupyterの構築は何かと面倒なので、全部入りのコンテナ使えばホント楽です。
（AnsibleやChefで入れようとすると色々詰まっちゃう。。。）

# イメージの取得
まずはイメージの取得です。
Jupyterのイメージは下記にいろんな種類があるので、目的によって選びましょう。
https://github.com/jupyter/docker-stacks

今回はtensorflow使いたいので、下記を使います。
https://github.com/jupyter/docker-stacks/tree/master/tensorflow-notebook

docker pullりましょう

```
$ docker pull jupyter/tensorflow-notebook
Unable to find image 'jupyter/tensorflow-notebook:latest' locally
latest: Pulling from jupyter/tensorflow-notebook
75a822cd7888: Pulling fs layer 
f74dd7a42a1f: Pulling fs layer 
7b03c47d9699: Pull complete 
ecef67eb4d88: Pull complete 
bd6c8cee2aa9: Pull complete 
8ecf884c467a: Pull complete 
7dc68d7c7ffd: Pull complete 
3369a456e292: Pull complete 
e626c4a34300: Pull complete 
619d5c673fb7: Pull complete 
eff746881b74: Pull complete 
fae5187ea9e1: Pull complete 
e1fd76e4adb2: Pull complete 
b5d2ba91f6a5: Pull complete 
5804e217f19f: Pull complete 
7719a427e59f: Pull complete 
33ea9d473883: Pull complete 
d28a865b24f6: Pull complete 
7e2fa13ce090: Pull complete 
15b63cba13fd: Pull complete 
adcb147a9782: Pull complete 
ce56ab01574f: Pull complete 
aa6a6ae0b01e: Pull complete 
2c54a9d73fcd: Pull complete 
47c2872f3870: Pull complete 
Digest: sha256:dd7b9e81c167647a87300043f21e3b37eee6d463815b86db9976c299cd4cc046
Status: Downloaded newer image for jupyter/tensorflow-notebook:latest
101e77006b40935607969dbad87e4540719ec55e66168d507f0ea8bb04ffe713
```

## 注意点
下みたいにエラーが出ることがあります。

```
$ docker pull jupyter/tensorflow-notebook
Unable to find image 'jupyter/tensorflow-notebook:latest' locally
latest: Pulling from jupyter/tensorflow-notebook
75a822cd7888: Pulling fs layer 
f74dd7a42a1f: Pulling fs layer 
f74dd7a42a1f: Pull complete 
ecef67eb4d88: Download complete 
bd6c8cee2aa9: Download complete 
8ecf884c467a: Download complete 
7dc68d7c7ffd: Download complete 
3369a456e292: Download complete 
e626c4a34300: Download complete 
619d5c673fb7: Download complete 
eff746881b74: Download complete 
fae5187ea9e1: Download complete 
e1fd76e4adb2: Download complete 
b5d2ba91f6a5: Downloading 96.62 MB/660.8 MB
5804e217f19f: Download complete 
7719a427e59f: Downloading 126.5 MB/281.6 MB
33ea9d473883: Download complete 
d28a865b24f6: Downloading 314.1 MB/314.1 MB
7e2fa13ce090: Waiting 
15b63cba13fd: Waiting 
adcb147a9782: Waiting 
ce56ab01574f: Waiting 
aa6a6ae0b01e: Waiting 
2c54a9d73fcd: Waiting 
47c2872f3870: Waiting 
docker: write /var/lib/docker/tmp/GetImageBlob222925529: no space left on device.
See 'docker run --help'.
```

原因はイメージが5Gほどあるので、容量が足りなくなってるみたい。
なので、他のイメージを削除すればOK（neural styleでかすぎ）

```
$ docker images
REPOSITORY                         TAG                 IMAGE ID            CREATED             SIZE
poppen/trusty-ansible-serverspec   latest              e84a5c7341fd        10 weeks ago        691 MB
flyinprogrammer/serverspec         latest              1b34b62345b3        12 weeks ago        154.4 MB
somatic/torch-fast-neural-style    latest              97645d9c69e8        3 months ago        7.323 GB
amazon/amazon-ecs-agent            latest              a76825ffa321        3 months ago        10.84 MB
elenaalexandrovna/opencv-python3   latest              910fcd0fa477        4 months ago        594.7 MB
trafferty/docker-ipython-opencv    latest              686f355ae522        19 months ago       8.676 GB
$ docker rmi a76825ffa321 910fcd0fa477 97645d9c69e8
Untagged: amazon/amazon-ecs-agent:latest
Untagged: amazon/amazon-ecs-agent@sha256:391a45a5b69a8d9fe1844310c4cf90e82e31cb167a93eb94d5a49b2b2456ad46
Deleted: sha256:a76825ffa321686b2df70a0be52fe5ecd52006a347cee5f07635b188655a5e86
...
```

# ハッシュ値取得用コンテナの起動

```
$ docker run -it --rm -p 8888:8888 jupyter/tensorflow-notebook
1b11efc02512ab60a26909ced181a16e01db57160607bb5c54c2acacae30a20b
$ docker ps
CONTAINER ID        IMAGE                         COMMAND                  CREATED             STATUS              PORTS                    NAMES
fb31e1a2fda1        jupyter/tensorflow-notebook   "tini -- start-notebo"   6 seconds ago       Up 1 seconds        0.0.0.0:8888->8888/tcp   thirsty_kilby
```

このままだと http://localhost:8888 にアクセスしても、パスワード画面を眺めるだけになっちゃう


# ハッシュ値の取得
docker execでコンテナにbashを立ち上げて

```
$ docker exec -it fb31e1a2fda1 /bin/bash
```

pythonから実行し、設定したいパスワードを2回打ち込み、パスワードのハッシュ値を取得します。
下記の例だと、ハッシュ値はsha1:hogehoge:fugafugaです。

```
< python -c 'from notebook.auth import passwd;print(passwd())'               
Enter password: 
Verify password: 
sha1:hogehoge:fugafuga
jovyan@fb31e1a2fda1:~/work$ exit
exit
```

## attachしたとき
docker attachしちゃうと、コンテナの起動の際に実行されるstart-notebook.shの標準入出力にアタッチしちゃって、pythonのコマンドが打てない

```
$ docker attach fb31e1a2fda1

★何もコマンド実行できない（ただログ眺めてるだけ）

ç^C[I 13:28:14.809 NotebookApp] Interrupted...
[I 13:28:14.810 NotebookApp] Shutting down kernels
$ 
```

# コンテナの削除

このコンテナはもう使わないので削除

```
$ docker ps
CONTAINER ID        IMAGE                         COMMAND                  CREATED             STATUS              PORTS                     NAMES
fb31e1a2fda1        jupyter/tensorflow-notebook   "tini -- start-notebo"   10 minutes ago      Up 10 minutes       0.0.0.0:32768->8888/tcp   tender_snyder
$ docker stop fb31e1a2fda1
fb31e1a2fda1
$ docker rm fb31e1a2fda1
fb31e1a2fda1
$ docker ps -a
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES
```

# 起動
ようやくパスワードを設定したコンテナを起動
さっき取得したハッシュ値、sha1:hogehoge:fugafugaをstart-notebook.shのオプションNotebookApp.passwordの値に入れ込んで実行しましょう。

```
docker run -d -p 8888:8888 jupyter/tensorflow-notebook start-notebook.sh --NotebookApp.password='sha1:hogehoge:fugafuga'
```

これで http://localhost:8888 へアクセスすれば、上で設定したパスワードを入れると、ログインできます。
あとはMNISTなり色々遊んでください。

# 余談
opensslコマンドでいけんじゃね？って思って下記をやったけど、うまくいかなかった

```
$ echo [password] | openssl sha1
```
sha1はsha1だろと思ったんだけどなんでだろ？形式が違うのかな？

# 参考
* Jupyter Notebook Scientific Python Stack + Tensorflow
https://github.com/jupyter/docker-stacks/tree/master/tensorflow-notebook
* Jupyter notebookのパスワード
http://qiita.com/Tsutomu-KKE@github/items/aee41edf1a990cad5be6
* Dockerコンテナ内で操作 attachとexecの違い
http://qiita.com/RyoMa_0923/items/9b5d2c4a97205692a560