Jupyter Notebook on DockerでVim keybindsを利用する

## 3行まとめ
- `$(jupyter --data-dir)../../`と`$(jupyter --config-dir)/nbconfig`をvolumeとして永続化・マウント
- [lambdalisue/jupyter-vim-binding][vim_binding]を配置
- `$(jupyter --config-dir)/nbconfig/notebook.json`で`vim_binding`読み込み


## はじめに
本記事ではDockerコンテナで動作している[Jupyter Notebook][jupyter/notebook]上で，[vim_binding][vim_binding]を利用しVimのKeybindを有効にする方法について説明する．

[Jupyter Notebook][jupyter/notebook]について本記事では説明を省略する．その素晴らしさ，および使い方等については『[現代のエンジニアのための強力なメモ帳 Jupyter notebookのすゝめ - クックパッド開発者ブログ][chezou2015]』『[Jupyter事始め - Qiita][taka4sato2016]』等を参照ください．

### Jupyter Notebook on Docker ?
Pythonに慣れていない人間にとって，[Jupyter Notebook][jupyter/notebook]の環境を整えるのは意外と難しい．その手間を省くため，Docker imageを利用することで環境構築の手間を省くことがある（『[Pythonista以外が環境を汚さずにJupyter Notebookに触れる方法 ... - Qiita][izumin52102015]』）
また，機械学習やデータ解析の便利ツールがつまったDocker imageが提供されていることも多い（e.g. [jupyter/datascience-notebook][ds-notebook], [tensorflow/tensorflow][tensorflow], etc.）．

### Vim keybind on Jupyter Notebook ?
一方，Web上でテキスト入力を行うとiiiijjjjddjkkkkiijjjkkpkkkiiijjjhhhhh:wqな我々Vimmerにとって，Jupyter Notebookを利用する際には[**vim_binding**][vim_binding]の有効化が必須となる（『[Jupyter (旧 IPython notebook）の本来あるべき姿を垣間見る - Λlisue's blog][lambdalisue2015]』）．
しかし，Docker上で動作してるJupyter Notebookでこれらextensionを有効化させるためにはちょっとした工夫が必要となる．

## Vim keybindings on Jupyter Notebook on Docker
方針としては簡単で， **extensionsとその設定ファイル群をvolumeとして永続化**してあげればいい．

以下の作業は基本的にすべてhostで行う（Dockerコンテナ起動前）．

### vim_bindingのclone
cloneでもいいしzip持ってきてもいいけど，あとで管理を楽にするためにここではsubmoduleとしてリポジトリに追加する．

```
$ git submodule add https://github.com/lambdalisue/jupyter-vim-binding .local/share/jupyter/nbextensions/vim_binding
```


### vim_bindingの有効化
`.jupyter/nbconfig/notebook.json`に以下のような設定を記述（他にもextension使ったりする場合はよしなに）．

```json
{
  "load_extensions": {
    "vim_binding/vim_binding": true
  }
}
```


### volumeの設定
3ディレクトリ以上のvolumeを設定することになるので，[docker-compose](https://docs.docker.com/compose/)を利用する．

```yml
datascience-cv-notebook:
  image: izumin5210/datascience-cv-notebook
  ports:
    - 8888:8888
  volumes:
    - ./notebooks:/notebooks
    - ./.local:/home/jovyan/.local
    - ./.jupyter/nbconfig:/home/jovyan/.jupyter/nbconfig
```

名前（最初のkey）とimageは必要に応じて変更する（ここでは datasience-notebbok + OpenCVな[datascience-cv-notebook](https://hub.docker.com/r/izumin5210/datascience-cv-notebook/)を利用している）．
ポイントは`volumes`の部分．

- `./notebooks:/notebooks`
    - 保存したnotebookや利用するimageやデータファイル等を`./notebbok`以下に永続化
    - Jupyter公式が提供するDocker imageをベースに利用している場合はこれでOK
    - それ以外の場合は適宜変更
- `./.local:/home/jovyan/.local`
    - `$(jupyter --data-dir)/../../` => extensionsをcloneしてくるディレクトリ
    - Jupyter公式のImageではまだ作られていないディレクトリなので大きめにとってる
    - あとで`.gitignore`をいい感じにして対応する
- `./.jupyter/nbconfig:/home/jovyan/.jupyter/nbconfig`
    - `$(jupyter --config-dir)/nbconfig`にあたる
    - 読み込むextensionの設定とか置くディレクトリ

### `.gitignore`の設定
前述の通り，`.local`をそのまま永続化しているため余計なファイルがいっぱい入ってくる．管理ファイルは少ないに越したことはないので，これをすべてignoreしておく．

```
!.local/share/jupyter
.local/share/jupyter/*
!.local/share/jupyter/nbextensions/
```

これで本当に管理しないといけないディレクトリ（`$(jupyter --data-dir)/nbextensions`）以外をすべてignoreできる．はず．


### Enjoy !
以下のコマンドでJupyterが起動する．`datascience-cv-notebook`の部分は自分が使いたいやつに変える．

```
$ docker-compose up datascience-cv-notebook
```

### 最終的なファイル構成
リポジトリのファイル構成はだいたい以下のような感じになる．

```

├── .gitignore
├── .gitmodules
├── .jupyter
│   └── nbconfig
│       └── notebook.json
├── .local
│   └── share
│       └── jupyter
│           └── nbextensions
│               └── vim_binding
├── Dockerfile
├── docker-compose.yml
└── notebooks
    ├── images
    │   ├── ...
    │   └── test0001.png
    ├── ...
    └── awesome-notebook.ipynb

```

## References
- [**lambdalisue/jupyter-vim-binding**][vim_binding]
- [**Jupyter (旧 IPython notebook）の本来あるべき姿を垣間見る - Λlisue's blog**][lambdalisue2015]
- [Jupyter事始め - Qiita][taka4sato2016]
- [現代のエンジニアのための強力なメモ帳 Jupyter notebookのすゝめ - クックパッド開発者ブログ][chezou2015]
- [Pythonista以外が環境を汚さずにJupyter Notebookに触れる方法 あるいは，Rubyist以外が環境を汚さずにJupyter NotebookでRubyに触れる方法 - Qiita][izumin52102015]

[jupyter/notebook]: https://github.com/jupyter/notebook
[vim_binding]: https://github.com/lambdalisue/jupyter-vim-binding
[lambdalisue2015]: http://lambdalisue.hatenablog.com/entry/2015/12/22/233817

[taka4sato2016]: http://qiita.com/taka4sato/items/2c3397ff34c440044978
[chezou2015]: http://techlife.cookpad.com/entry/write-once-share-anywhare
[izumin52102015]: http://qiita.com/izumin5210/items/5531f58f31d788bb8b9b
[ds-notebook]: https://hub.docker.com/r/jupyter/datascience-notebook/
[tensorflow]: https://hub.docker.com/r/tensorflow/tensorflow/