📓

Jupyter notebookをdockerコンテナで起動してホストのブラウザから使えるようにする

2022/03/13に公開

今回はdockerコンテナでjupyter notebookを起動してブラウザで見れるようにしました。

また、オンプレのプライベート環境の利用を想定しておりセキュリティ設定は考慮しておりません。

1. docker-compose用のファイルを作成

始めにDockerfileとDocker-compose.ymlをいかの通り作成します。

1.1 Dockerfile

pythonが使えるimageを指定して、notebookライブラリをインストールしています。

FROM python:3.9

WORKDIR /app

SHELL ["/bin/bash", "-c"]

RUN apt-get update &

RUN pip install --upgrade pip 

RUN pip install notebook

1.2 docker-compose.yml

コンテナからホストへportを渡しすためにports:の指定が必要になります。
今回はjupyter notebookがデフォルトで使用するポート8888をコンテナおよびホストで使う設定にしています。

version: '3'
services:
  app:
    build: .
    volumes:
      - ./:/app
    ports:
      - 8888:8888
    tty: true

2. コンテナに入ってjupyter notebook起動

2.1 コンテナ起動

まずはコンテナ起動。

$ docker-compose up -d

起動確認。

$ docker-compose ps

StateがUpならOK。portの設定もここで確認できます。

      Name           Command   State         Ports       
----------------------------------------------------------
jnotebook-            python3   Up      0.0.0.0:8888->8888
docker_app_1                            /tcp,:::8888->8888
                                        /tcp              

2. コンテナに入ってjupyter notebookを起動

コンテナに入る。

$ docker-comose exec app bash

以下のコマンドでjupyter notebookを起動。

jupyter notebook --port=8888 --ip=0.0.0.0 --allow-root --NotebookApp.token=''

オプションの意味は
--port=8888 8888ポートを利用。
--ip=0.0.0.0 外部からのアクセスを許可。ホストからアクセスするために設定。
--allow-root rootでの起動を許可。dockerコンテナのユーザー権限がデフォルトではrootユーザーになっているため。
--NotebookApp.token='' ブラウザでアクセスするときのトークン入力を無効にする。

実行後ターミナルには以下のように表示される。

root@875788d8dc37:/app# jupyter notebook --port=8888 --ip=0.0.0.0 --allow-root --NotebookApp.token=''
[I 05:42:04.018 NotebookApp] Authentication of /metrics is OFF, since other authentication is disabled.
[W 05:42:04.158 NotebookApp] All authentication is disabled.  Anyone who can connect to this server will be able to run code.
[I 05:42:04.163 NotebookApp] Serving notebooks from local directory: /app
[I 05:42:04.163 NotebookApp] Jupyter Notebook 6.4.8 is running at:
[I 05:42:04.163 NotebookApp] http://875788d8dc37:8888/
[I 05:42:04.163 NotebookApp] Use Control-C to stop this server and shut down all kernels (twice to skip confirmation).
[W 05:42:04.165 NotebookApp] No web browser found: could not locate runnable browser.

またコンテナ内から接続できるか確認する場合はcurlコマンドを使って確認できる。

$ curl -L localhost:8888

起動していれば以下のようにhtmlが表示される。

<!DOCTYPE HTML>
<html>

<head>
    <meta charset="utf-8">

失敗してる場合は以下の様になったりする。

curl: (7) Failed to connect to localhost port 8888: 接続を拒否されました

3. ホストからブラウザ接続

ブラウザを開いてhttp://localhost:8888に接続してnotebookのページが表示されればOK!!

4. 実行時のルートディレクトリを指定

今のままだだとブラウザ接続時にdockerのファイルが見えてしまってるので、接続時のルートディレクトリを指定します。 任意のディレクトリをコンテナ外で作成し(今回はwork)、そこをルートディレクトリとして扱います。(コンテナに入って作成するとディレクトリの所有者がroot担ってしまいます。)

やり方は簡単でnotebook起動のオプションに--notebook-dir 'work'を追加するだけです。

$ mkdir work
jupyter notebook --port=8888 --ip=0.0.0.0 --allow-root --NotebookApp.token='' --notebook-dir 'work'

5. notebook実行をshファイルで行う

起動時に毎回オプション指定するのが煩わしいのでshファイルから実行するようにします。
jn.shを作成以下を記載します。

jupyter notebook --port=8888 --ip=0.0.0.0 --allow-root --NotebookApp.token='' --notebook-dir 'work'

実行するとき。以下をコマンド実行します
(権限なくて実行できないときはコンテナ外でchmod 755 jn.shする。)

 ./jn.sh

jupyter notebook --generate-config でデフォルトでオプションを指定することもできるのですがファイルの場所がユーザディレクトリ下になってしまうので今回はshファイルを採用しました。

6. コンテナ内の実行ユーザーをrootから一般ユーザーに変更する

(*2023年8月10日追記)
Linuxですと今のままだとコンテナ内の実行ユーザーがrootのため、notebookで作成したファイルの所有者がrootとなってしまいホストの一般ユーザーでは編集ができません。

macだとホスト側のユーザーをコンテナ内でもデフォルトで使うのでここは不要だと思います。
(数年前に確認したので今はわかりませんが。)

そのためコンテナ内の実行ユーザーを一般ユーザーに変更することにします。
作成する一般ユーザーの名前は任意ですが、ここではpyuserとしています。
ただし以下の方法はホストとコンテナに作成した一般ユーザーのgidが一致していることが前提となってます。(デフォルトでは双方1000になってます。)

6.1 dockerfile

イメージのビルド時に一般ユーザーを作成するようにします。変更後はイメージをビルドし直す必要があります。

FROM python:3.9

WORKDIR /app

SHELL ["/bin/bash", "-c"]

RUN apt-get update &

RUN pip install --upgrade pip 

RUN pip install notebook

####### 追加箇所 #######
RUN useradd -m pyuser
USER pyuser
#######################

6.2 notebook起動コマンド jn.sh

実行オプションから --allow-rootを削除します。
削除後のnotebook起動コマンドはこちら。

jupyter notebook --port=8888 --ip=0.0.0.0 --NotebookApp.token='' --notebook-dir 'work'

これで修正は完了です。一度イメージを削除して修正前と同じ手順で実行するとユーザーがrootから変わっています。

Discussion