🕯️

wsl2環境下で作るjupyterHub dockerspawnerに他のPCからアクセスする

2022/06/11に公開

初めに

jupyterlab(jupyter notebook)は便利ですね。
特にJupyterHubではマルチユーザ環境が構築できてだいぶ便利です。
さらにDockerspawnerを使えばユーザ単位で環境分離できて非常に便利です。
ワークショップや社内研修で助かること間違いなしです。

非常に便利なのですがwsl2でdockerを用いたjupyterhubを作成するとlocalhostではアクセスできても別のPCからdocker内に入れないなんてことが起きます。
悲しみのRedirect loop

何とか解決できたのでもしこれからどうしてもwslでjupyterHubを立てたい!となったときの参考になればと思い共有させていただきます。

ざっくりとですが最終的には以下のような状況を目指します

要点

上の状態を達成するために重要な内容は以下の2つです。
ここ以外は基本的なdockerspawnerのjupyterhubの構築ですので特にハードルなく達成可能かと思います。

  1. jupyterhubのIPアドレスをlocalhostではなく明示的にwslのIPアドレスで指定する
  2. 指定したIPアドレスにポートフォワーディングでwindowからwslに横流しするようにする

本記事でわかること

  • wsl2でdockerspawnerを用いたjupyterhubを作成する方法
  • 作成したjupyterhubに同一ネットワーク内の別PCからアクセスする方法

本記事で説明しないこと

  • シェルスクリプト・コマンド操作
  • wsl2の導入方法
  • dockerの概念・操作方法
  • docker desktopでの環境構築(宗教上の理由でdocker engineを使います)
  • anacondaを用いたjupyterhub環境構築(宗教上の理由もありすべてpipで行います)
  • jupyterhub dockerspawnerクラスの詳細
  • pipやpythonの概念・操作方法
  • wsl1(区別するために明示的に1と記載してます)でのjupyterhub dockerspawner環境構築
  • セキュアな通信環境(サイトのSSL化など)
  • 同一ネットワーク外からのアクセス方法
  • Jupyterhubのスタートアップ時自動起動設定

一般的なLinux環境での環境構築などは下記サイト様が参考になります。
JupyterHubのDockerSpawnerで起動するイメージを替える
Python初心者講習のためのJupyterHub
JupyterHubの構築

環境

今回の構築環境は以下です

  • OS:Windows11
  • wslイメージ: Ubuntu-20.04
  • Python3.8.10
  • dockerイメージ: python:3.8.13-buster
  • proxyは特にない前提

各種インストール

jupyterhubのインストール

wslで構築したubuntu環境にjupyterhubをインストールしていきます。

$ sudo apt update -y
$ sudo apt upgrade -y
$ curl -sL https://deb.nodesource.com/setup_18.x | sudo -E bash - 
$ sudo apt install nodejs -y
$ sudo python3 -m pip install jupyterhub notebook
$ sudo python3 -m pip install dockerspawner jupyterhub-nativeauthenticator 

これでひとまずjupyterhubに入れるようになるはずです

$ sudo jupyterhub

jupyterhubコンソール画面

Jupyterhub is now running at ~以下をブラウザでコピペして入れることを確認しましょう

jupyterhubログイン画面

次はdockerspawnerでユーザ事に空間を分離できるようにDockerを導入します

dockerのインストール

$ curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
OK
$ sudo add-apt-repository  "deb[arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable"
$ sudo apt update -y
$ sudo apt install -y docker-ce docker-ce-cli containerd.io

インストールできたらコマンドを打って確認してみましょう

$ sudo docker version
Client: Docker Engine - Community
 Version:           20.10.17
 API version:       1.41
 Go version:        go1.17.11
 Git commit:        100c701
 Built:             Mon Jun  6 23:02:57 2022
 OS/Arch:           linux/amd64
 Context:           default
 Experimental:      true
Cannot connect to the Docker daemon at unix:///var/run/docker.sock. Is the docker daemon running?

環境構築

フォルダの作成

dockerfileとjupyterの設定ファイルを保存するためのフォルダを用意し、その中にそれぞれDockerfileとjupyterhub_config.pyを作成します
ここらへんのディレクトリ構造はお好みで大丈夫です

$ mkdir ~/jupyter
$ mkdir ~/docker
$ touch ~/jupyter/jupyterhub_config.py
$ touch ~/docker/Dockerfile

Dockerイメージの作成

各ユーザー毎に割り当てるためのdockerイメージを作成していきます。

Dockerfileの作成

先ほど作ったDockerfileを書き換えてください
ソースコード

~/docker/Dockerfile
FROM python:3.8.13-buster
# rootユーザでないとノートブックが新規作成できないらしい
USER root 
# お好みでワークスペースを作成
WORKDIR /root/workspace 


RUN apt update

# timezoneの設定
RUN apt install -y tzdata
RUN ln -sf /usr/share/zoneinfo/Asia/Tokyo /etc/localtime
ENV TZ=Asia/Tokyo

# 無駄なキャッシュを削除してなるべくイメージ容量を小さくする
RUN apt autoremove
RUN apt clean
RUN rm -r /var/lib/apt/lists/*

#  計算機関連のライブラリをインストールする
RUN pip install --no-cache-dir numpy pandas scipy opencv-python matplotlib Pillow scikit-learn optuna keras

# jupyterlabの拡張関係をインストールする
RUN pip install --no-cache-dir jupyterhub jupyterlab_code_formatter jupyterlab-git lckr-jupyterlab-variableinspector jupyterlab_widgets ipywidgets import-ipynb jupyterlab-language-pack-ja-JP

# 必要に応じてサンプルコードなどをgitから落とすなど
RUN git clone https//github.com/username/python_samplcode.git /root/workspace

# jupyterhubの起動時設定 dockerspawnerを使うときは原則これ
CMD ["jupyterhub-singleuser", "--allow-root"]

docker build

作成したDockerfileをbuildします
イメージ名は好きな名前で

$ sudo service docker start
 * Starting Docker: docker
$ cd ~/docker
$ sudo docker build . -t jupyterhub

作成が終わったらちゃんとイメージができているか確認しましょう

$ sudo docker images
REPOSITORY               TAG          IMAGE ID       CREATED         SIZE
jupyterhub               latest       827e63b3b9ce   2 minutes ago   1.84GB

jupyterhubの起動

いよいよJupyterhubを起動していきます。
ここで上手に設定しておかないと外部からアクセスした際にdockerコンテナにアクセスする際にRedirect loopが発生してログイン画面まではいけるけどノートブックにアクセスできない問題が発生してしまいました

Jupyterhub の実行IPをlocalhostではなく、明示的にwslのIPアドレスを指定してあげることで解決します
なぜlocalhostだとだめなのかは下記サイト様が参考になりました
http://var.blog.jp/archives/84997759.html

jupyterhub_config.pyの編集

jupyterhub_config.pyを編集します。
詳細は割愛しますがc.JupyterHub.ipおよびc.JupyterHub.hub_ipをwslのIPアドレスと合わせてあげると上手くいきます。

jupyterhub_config.py
# wslのIPアドレスを取得する ≠ WindowsのIPアドレス
ip = public_ips()[0]

# jupyterのhubへのルート
c.JupyterHub.hub_ip = ip
c.JupyterHub.hub_port = 8111 #好きなポート

# JupyterhubにアクセスするためのIP
c.JupyterHub.ip= ip
c.JupyterHub.port = 8888 #好きなポート

jupyterhub_config.pyのソースは以下を確認してください
ソースコード

ここまで出来たら一回jupyterhubを起動してみましょう。

$ cd ~/jupyterhub
$ sudo jupyterhub

Jupyterhub is now running at ~以下が最初に起動したときと異なりwslのIPアドレスになっていることに注目してください

Adminユーザの作成

WebブラウザでIPアドレス手打ちでログイン画面に映ります
Adminユーザを作成するためにSignup!をクリックします

ユーザー名にjupyterhub_config.pyc.Authentivator.admin_usersに指定した名称、パスワードは好きなパスワードを入力します

もう一回ログイン画面に戻り設定したユーザーネームとパスワードを入力することでNotebookが立ち上がります。

Windowsのファイアウォール・ポートフォワーディング設定

WSLの入ったパソコンからのアクセスができるようになりましたが、他のPCからアクセスすることはできません。
なのでWindowsのファイアウォールとポートフォワーディングを設定してWindowsに来たアクセスをWSLに横流しすることでアクセスできるようにします。

PowerShellを管理者権限で開いて以下を実行します

  1. ファイアウォールを設定してポートを有効にする
  2. ポートフォワーディングを設定する
    今回は仮にWindowsのポート8880に来たアクセスをwslに流すことにします
$ netsh advfirewall firewall add rule name="port forwarding from 8880 to wsl" dir=in action=allo protocol=TCP localport=8880
$ netsh interface portproxy add v4tov4 listenport=8880 connectaddress=$wslのIPアドレス connectport=$c.JupyterHub.portで設定したポート

他のパソコンからアクセス

最後に他のパソコンのブラウザからhttp://windowsのIPアドレス:8880でアクセスをしてみましょう。
ログインをしてみてノートブックのが開けたら成功です。

補足

wslのIPアドレスは起動ごとに変わってしまうため非常に面倒です。
下記サイト様のようにスタートアップ時にwslを起動してwslのIPアドレスを同定、ポートフォワーディングするように設定すると便利です。またjupyterhubをサービス化して同時に起動するようにしましょう。

https://tkyonezu.com/windows10/【メモ】wsl2上のsshサーバに外部から接続する/
https://qiita.com/DQNEO/items/0b5d0bc5d3cf407cb7ff

まとめ

外部環境からwsl内のjupyterhubサーバ・dockerコンテナにアクセスする方法を説明しました。
下記二つの要点に気を付けることで達成が可能です

  1. jupyterhubのIPアドレスをlocalhostではなく明示的にwslのIPアドレスで指定する
  2. 指定したIPアドレスにポートフォワーディングでwindowからwslに横流しするようにする

サーバPCのlocalhostからはアクセスできるのに外部からサーバPCのIPを叩いてもアクセスできなかったり、とくに指定なくjupyterhubを起動するとアドレスがlocalhostになってしまったり、構築するまでにかなりの時間を費やしてしまいました…

Discussion