Docker

解析環境をJupyterLab+hub-extensionでマルチユーザー化した

持っている講義とは全く関係なく、僕が学部生にDeep Learningを教えるプログラムが始動することになった。ただし、これは院生時代に所属していたプログラムでお世話になっていた先生との共同研究の一環であって、普段ならそんなボランティアはしないです。そこのラボの学生さんにDeep Learningを仕込んで、最終的には共同研究用に僕が組んだモデルのパラメータ調整ぐらいはやれるようになるのを目標に。

学生さんにはとりあえずColaboratoryを使ってもらって勉強させといて、その間にこっちの研究室の解析環境もマルチユーザー環境とついでにJupyterLab移行でもしておくことにした。自分だけで使うならいつまでもJupyterと自作関数でゴリゴリDeep Learningしててもいいのだが、他人が使うとなるとレガシーな自作関数よりkerasとか使ってもらった方がいいしインタラクティブかつ見やすい最新の環境を使ってもらう方がいいに決まっている。これを一度に実現するにあたっては jupyterlab/hub-extension としてすでにJupyterLab上でHub機能が使えるように統合されている。

作業の順序としては、DockerでAnacondaを立て、JupyterLabをインストールし、その中でhub-extensionを有効化する。そこからJupyterHubの認証周りの設定をかければ完了。

1 コンテナの立ち上げ

新しいコンテナで環境を一から作り直す。コンテナイメージはオフィシャルのcontinuumio/anaconda3を利用。取り急ぎフォルダを用意しておく。ポートは8888をjupyter notebookで使ってしまっているので、とりあえず8080で。(古い環境を汚染してから万が一移行に失敗すると色々終わる)

$ cd ~
$ mkdir myJupyterLab
$ docker run -d --name jupylab -p 8080:8888 -v ~/myJupyterLab:/home/jovyan/workspace -w /workspace continuumio/anaconda3 

これでDocker上にjupylabという名前でコンテナができる。コンテナ上の~/workspaceとローカルの~/myJupyterLabが同期されている。

2 JupyterLabの設定

今のはあくまでanacondaの環境ができただけでまだ何も動いていない。ここからはJupyterLabを立ち上げるためコンテナの中に入ってもう少しいじる。手始めにJupyterLabを入れる。

$ docker exec -it jupylab /bin/bash
(conteiner)$ conda install jupyterlab
Collecting package metadata (current_repodata.json): done
Solving environment: done

## Package Plan ##

  environment location: /opt/conda

  added / updated specs:
    - jupyterlab


The following packages will be downloaded:

    package                    |            build
    ---------------------------|-----------------
    conda-4.7.12               |           py37_0         3.0 MB
    ------------------------------------------------------------
                                           Total:         3.0 MB

The following packages will be UPDATED:

  conda                                       4.7.10-py37_0 --> 4.7.12-py37_0


Proceed ([y]/n)? y

yでインストール

ここでJupyterLabのインストールと一緒に conda install nodejsでnodejsを入れておかないと、JupyterLabのhub-extentionをインストールするところで下のようなエラーが出る。

An error occured.
ValueError: Please install nodejs 5+ and npm before continuing installation. nodejs may be installed using conda or directly from the nodejs website.

ということでnodejsを入れつつhub-extensionを追加する。

(container)$ conda install nodejs
(container)$ jupyter labextension install @jupyterlab/hub-extension

できたのでとりあえずJupyterLabを立ち上げてみる(この段階ではまだ認証周りは何もできていないことに注意。実際の認証周りはJupyterHubがないと全く動作せず、hub-extensionはあくまでそことの連携だと思った方がいい)。

(container)$ jupyter-lab --notebook-dir=/workspace --ip='*' --port=8888 --no-browser --allow-root

Dockerのjovyanアカウント(=root)で立ち上げているので、Jupyter関連は通常のnotebookだろうがhubだろうがlabだろうが–allow-rootしないと問答無用で落ちる。ポートは8888になっているが、これはコンテナ側の話であって実際には本体のグローバルIP+ポート8080にアクセスしたものがlocalhost:8888としてここにポートフォワーディングされる。

これでまずJupyterLabの準備はできた。一人で使う分にはこれでいいのだが。

3 JupyterHubの設定

jupyterhubをインストールして/opt/condaに設定ファイルを吐かせて編集する。(viが動かなければ入れる)

(container)$ conda install jupyterhub
(container)$ cd /opt/conda
(container)$ jupyterhub --generate-config
(container)$ vi jupyterhub_config.py

ここで人によっては/optに吐いている場合があるけど、僕の場合はoptだと読み出さなかった。実際configはAnacondaのインストールディレクトリに作るように言われている。

jupyterhub_config.pyに追記すべきは、第一に

c.Spawner.notebook_dir = '~/notebook'
c.Spawner.default_url = '/lab'

つまるところこれは、アカウントごとのnotebookを各自のホームフォルダ直下のnotebookディレクトリ上に作っていけ、そしてログインしたらJupyterLabを開くようにしろ、ということ。

ここで認証方法に行くところで冷静に考えて気づいたが、今の構成だとGoogleアカウントでのOAuthは使えない。まず大学のGSuiteではGCP(Google Cloud Platform)が無効になっているし、Googleからのcallbackを受け付けるのに(おそらく)グローバルアクセスにしないといけない。 仕方ないのでユーザー認証にする。将来的に出来そうだったら変えよう。

ということで下記の通り自分とテスト的なユーザーのアカウントをjupyterhub_config.pyに何人分か追加する。

c.Spawner.admin_users = {'jniimi'}
c.Spawner.whitelist = {'testuser001', 'testuser002'}

コンテナ上でも同様にユーザーを作成する。

(container)$ adduser jniimi
(container)$ adduser jniimi
Adding user `jniimi' ...
Adding new group `jniimi' (1000) ...
Adding new user `jniimi' (1000) with group `jniimi' ...
Creating home directory `/home/jniimi' ...
Copying files from `/etc/skel' ...
New password: 
Retype new password: 
passwd: password updated successfully
Changing the user information for jniimi
Enter the new value, or press ENTER for the default
	Full Name []: Junichiro NIIMI
	Room Number []:    
	Work Phone []: 
	Home Phone []: 
	Other []: 
Is the information correct? [Y/n] Y

そして各ユーザーのホームにnotebookディレクトリを作ってあげる。

(container)$ cd /home/jniimi
(container)$ mkdir notebook

これでログイン付きのJupyterLabがとりあえず動く。あとは自分のファイルを全部jniimiのフォルダ以下にコピーすればいい。他の人に使わせる場合にはadduserでユーザーを追加し、jupyterhub_config.pyのwhitelistにも追記してあげればいい。まあちょっとめんどくさいけどね。

SSLには将来的に絶対にするけど今はちょっと待って
こんな感じですね。
Macのダークモードに合わせてテーマ変更してあります。

実はJupyterはnotebookしか使ったことなくて、HubもLabも初めてだったのでかなり時間がかかってしまった。