4: 2021-07-04 (Sun) 23:20:06 iseki |
Cur: 2021-10-16 (Sat) 14:22:59 iseki |
- | ** dockerspawner.DockerSpawner [#l39109fd] | + | ** DockerSpawner [#l39109fd] |
| - https://github.com/jupyterhub/dockerspawner.git | | - https://github.com/jupyterhub/dockerspawner.git |
| - サーバでユーザ毎に ''[[Docker]]'' でNoteBook コンテナを起動して接続. | | - サーバでユーザ毎に ''[[Docker]]'' でNoteBook コンテナを起動して接続. |
| - 作業ホームは /home/jovjan/work 固定(多分 Docker Image固定) | | - 作業ホームは /home/jovjan/work 固定(多分 Docker Image固定) |
| + | |
| + | - see also [[SystemUserSpawner>../SystemUserSpawner]] |
| #br | | #br |
| + | |
| *** Install [#v787b2b6] | | *** Install [#v787b2b6] |
| (jupyterhub) # pip --no-cache-dir install git+https://github.com/jupyterhub/dockerspawner.git | | (jupyterhub) # pip --no-cache-dir install git+https://github.com/jupyterhub/dockerspawner.git |
| or | | or |
| (jupyterhub) # pip install dockerspawner | | (jupyterhub) # pip install dockerspawner |
| + | |
| + | - pip --no-cache-dir install git+https://github.com/jupyterhub/dockerspawner.git をお勧め |
| + | |
| + | #br |
| | | |
| *** 設定 [#i5887782] | | *** 設定 [#i5887782] |
| + | #br |
| + | |
| + | |
| **** 設定ファイル(サンプル) [#sc0660b1] | | **** 設定ファイル(サンプル) [#sc0660b1] |
- | - [[jupyterhub_config.py>./jupyterhub_config.py]] | + | - [[jupyterhub_config_sample.py>./jupyterhub_config.py]] |
| #br | | #br |
- | ** Hack [#gdd93e11] | + | |
- | *** singleuser [#oea09b82] | + | *** Docker Images [#ta8920e4] |
| + | **** [[jupyterhub-sigleuser>./jupyterhub-sigleuser]] [#zf5de082] |
| + | - docker pull jupyterhub/singleuser |
| + | #br |
| + | |
| + | **** datascience-notebook [#s5b3175e] |
| + | - docker pull jupyter/datascience-notebook |
| + | #br |
| + | |
| + | *** 新しい起動用 Docker イメージの作り方 [#s2d1d7bf] |
| + | **** Dockerfile を使う方法 [#k4d600dc] |
| + | # vi Dockerfile |
| + | # cp (何処か)/start.sh . |
| + | # docker build -t jupyter_single-test . |
| + | # docker images |
| + | |
| + | - Dockerfile |
| + | FROM jupyterhub/singleuser |
| + | USER root |
| + | COPY start.sh /usr/local/bin |
| + | RUN apt-get update \ |
| + | && apt-get install -y --no-install-recommends \ |
| + | vim \ |
| + | && apt-get -y clean \ |
| + | && rm -rf /var/lib/apt/lists/* |
| + | |
| + | **** Docker commit でイメージを作ると,二重引数の問題が発生 [#t9a36c00] |
| + | - iseki でログイン時 |
| + | # docker exec -it jupyter-iseki /bin/bash |
| + | cd /home/ |
| + | mv iseki jovyan |
| + | mkdir student |
| + | cd teacher/iseki |
| + | cp ./back_orign |
| + | cp start.sh /usr/local/bin |
| + | exit |
| + | # docker commit jupyter-iseki new-image |
| + | - back_orign |
| + | 1 #!/bin/bash |
| + | 2 cp group /etc/group |
| + | 3 cp group /etc/group- |
| + | 4 cp passwd /etc/passwd |
| + | 5 cp passwd /etc/passwd- |
| + | 6 cp /etc/gshadow- /etc/gshadow |
| + | 7 cp /etc/shadow- /etc/shadow |
| + | 8 cp /etc/subgid- /etc/subgid |
| + | 9 cp /etc/subuid- /etc/subuid |
| + | |
| + | - [[解決>#xeab91b6]] |
| + | #br |
| + | |
| + | **** [[start.sh(改)>./start.sh-kai]], [[start.sh(オリジナル)>./start.sh]][#q31443f9] |
| + | - コンテナ内の /usr/local/bin/start.sh |
| + | -- コンテナ内の環境設定スクリプト |
| + | |
| + | - 利用できる環境変数 |
| + | SHELL=/bin/bash |
| + | USER_ID=10015 |
| + | MINIFORGE_VERSION=4.9.2-0 |
| + | HOSTNAME=58f17edda0c7 |
| + | LANGUAGE=en_US.UTF-8 |
| + | JUPYTERHUB_API_TOKEN=d8137932ac144ebaa70bb04ba359fbac |
| + | JUPYTERHUB_BASE_URL=/ |
| + | NB_UID=10015 |
| + | PWD=/home/teacher/iseki |
| + | NB_NOTEDIRX=/home/{groupname}/{username}/work |
| + | GRANT_SUDO=yes |
| + | JUPYTERHUB_SERVER_NAME= |
| + | HOME=/home/teacher/iseki |
| + | LANG=en_US.UTF-8 |
| + | JPY_API_TOKEN=d8137932ac144ebaa70bb04ba359fbac |
| + | NB_GID=10001 |
| + | CHOWN_HOME=yes |
| + | JUPYTERHUB_SERVICE_PREFIX=/user/iseki/ |
| + | JUPYTERHUB_OAUTH_CALLBACK_URL=/user/iseki/oauth_callback |
| + | NB_GROUP=teacher |
| + | USER=iseki |
| + | SHLVL=1 |
| + | CONDA_DIR=/opt/conda |
| + | JUPYTERHUB_API_URL=http://172.22.1.75:8081/hub/api |
| + | JUPYTERHUB_CLIENT_ID=jupyterhub-user-iseki |
| + | JUPYTERHUB_HOST= |
| + | CONDA_VERSION=4.9.2 |
| + | NB_USER=iseki |
| + | LC_ALL=en_US.UTF-8 |
| + | PATH=/opt/conda/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin |
| + | JUPYTERHUB_USER=iseki |
| + | JUPYTERHUB_ACTIVITY_URL=http://172.22.1.75:8081/hub/api/users/iseki/activity |
| + | DEBIAN_FRONTEND=noninteractive |
| + | _=/usr/bin/env |
| + | |
| + | #br |
| + | |
| + | *** 新しいクラスを作成する [#r7a6bb3c] |
| + | |
| + | - /usr/local/anaconda/envs/jupyterhub/lib/python3.8/site-packages/dockerspawner/ |
| + | -- edit __init__.py |
| + | -- ex.) nsldockerspawner.py |
| + | ...... |
| + | from dockerspawner import DockerSpawner |
| + | |
| + | class NSLDockerSpawner(DockerSpawner): |
| + | ...... |
| + | def some_func(self): |
| + | ret = super(NSLDockerSpawner, self).some_func() |
| + | ..... |
| + | return ret |
| + | ...... |
| + | def start(self, *, image=None, extra_create_kwargs=None, extra_host_config=None): |
| + | ....... |
| + | return super(NSLDockerSpawner, self).start() |
| + | #br |
| + | |
| + | **** MDLDockerSpawner [#d9dde499] |
| + | - 参考: https://gist.github.com/marufeuille/596cf6f9e26fa6fcb7e304d5b163c7c8 |
| + | |
| + | 476 # refer: https://gist.github.com/marufeuille/596cf6f9e26fa6fcb7e304d5b163c7c8 |
| + | 477 from dockerspawner import SystemUserSpawner |
| + | 478 from traitlets import Unicode |
| + | 479 import pwd, os, grp |
| + | 480 |
| + | 481 class ProjectDockerSpawner(SystemUserSpawner): |
| + | 482 |
| + | 483 dobleArguments = False |
| + | 484 #dobleArguments = True |
| + | 485 |
| + | 486 |
| + | 487 host_homedir_format_string = Unicode( |
| + | 488 "/home/{groupname}/{username}", |
| + | 489 config = True, |
| + | 490 ) |
| + | 491 |
| + | 492 image_homedir_format_string = Unicode( |
| + | 493 "/home/{groupname}/{username}", |
| + | 494 config = True, |
| + | 495 ) |
| + | 496 |
| + | 497 |
| + | 498 @property |
| + | 499 def host_homedir(self): |
| + | 500 if ( |
| + | 501 self.host_homedir_format_string is not None |
| + | 502 and self.host_homedir_format_string != "" |
| + | 503 ): |
| + | 504 homedir = self.host_homedir_format_string.format(username=self.user.name, groupname=self.get_groupname()) |
| + | 505 else: |
| + | 506 import pwd |
| + | 507 |
| + | 508 homedir = pwd.getpwnam(self.user.name).pw_dir |
| + | 509 return homedir |
| + | 510 |
| + | 511 |
| + | 512 @property |
| + | 513 def homedir(self): |
| + | 514 return self.image_homedir_format_string.format(username=self.user.name, groupname=self.get_groupname()) |
| + | 515 |
| + | 516 |
| + | 517 def get_args(self): |
| + | 518 args = super(ProjectDockerSpawner, self).get_args() |
| + | 519 if (not self._user_set_cmd) and self.dobleArguments: |
| + | 520 args = [] |
| + | 521 return args |
| + | 522 |
| + | 523 |
| + | 524 #def get_command(self): |
| + | 525 # cmd = super(ProjectDockerSpawner, self).get_command() |
| + | 526 # return cmd |
| + | 527 # |
| + | 528 # ''' |
| + | 529 # if self._user_set_cmd: |
| + | 530 # cmd = self.cmd |
| + | 531 # else: |
| + | 532 # image_info = yield self.docker("inspect_image", self.image) |
| + | 533 # cmd = image_info["Config"]["Cmd"] |
| + | 534 # return cmd + self.get_args() |
| + | 535 # ''' |
| + | 536 |
| + | 537 |
| + | 538 def template_namespace(self): |
| + | 539 d = super(ProjectDockerSpawner, self).template_namespace() |
| + | 540 if self.group_id >= 0: |
| + | 541 d['groupname'] = self.get_groupname() |
| + | 542 return d |
| + | 543 |
| + | 544 |
| + | 545 def get_groupname(self): |
| + | 546 gname = '' |
| + | 547 if self.group_id >= 0: |
| + | 548 gname = grp.getgrgid(self.group_id).gr_name |
| + | 549 return gname |
| + | 550 |
| + | 551 |
| + | 552 def get_env(self): |
| + | 553 env = super(ProjectDockerSpawner, self).get_env() |
| + | 554 if self.group_id >= 0: |
| + | 555 #env.update(NB_GID=self.group_id) |
| + | 556 import grp |
| + | 557 gname = self.get_groupname() |
| + | 558 env.update(NB_GROUP=gname) |
| + | 559 return env |
| + | 560 |
| + | 561 |
| + | 562 def start(self): |
| + | 563 name = self.user.name |
| + | 564 user_data = pwd.getpwnam(name) |
| + | 565 user_gid = user_data.pw_gid |
| + | 566 gid_list = os.getgrouplist(name, user_gid) |
| + | 567 |
| + | 568 work_dir = self.notebook_dir |
| + | 569 self.volumes['jupyterhub-user-{username}'] = work_dir |
| + | 570 |
| + | 571 for gid in gid_list: |
| + | 572 gname = grp.getgrgid(gid).gr_name |
| + | 573 if gname.startswith("project-"): |
| + | 574 dirname = gname.replace("project-", "") |
| + | 575 self.volumes[gname] = work_dir + '/projects/' + dirname |
| + | 576 |
| + | 577 return super(ProjectDockerSpawner, self).start() |
| + | |
| + | #br |
| + | |
| + | |
| + | #br |
| + | |
| + | *** Tools [#ke66d2d2] |
| + | **** アイドルしている Docker コンポーネントを殺す! [#uf1854cf] |
| + | ***** %%jupyterhub-idle-culler%% [#eb3404d4] |
| + | - jupyterhub_idle_culler |
| + | - https://github.com/jupyterhub/jupyterhub-idle-culler |
| + | |
| + | - pip で入れると No module named が出て,動かない模様 |
| + | -- No module named jupyterhub_idle_culler |
| + | |
| + | - GitHub から直接入れる. |
| + | -- git clone https://github.com/jupyterhub/jupyterhub-idle-culler.git |
| + | -- cd jupyterhub-idle-culler |
| + | -- python setup.py build |
| + | -- python setup.py build |
| + | |
| + | - ''期待通りに動かん!'' |
| + | |
| + | - jupyterhub_config.py |
| + | lmport sys |
| + | |
| + | c.JupyterHub.services = [ |
| + | { |
| + | 'name': 'idle-culler', |
| + | 'admin': True, |
| + | 'command': [ |
| + | sys.executable, |
| + | '-m', 'jupyterhub_idle_culler', |
| + | '--timeout=3600' |
| + | ], |
| + | } |
| + | ] |
| + | |
| + | ***** cull_idle_servers.py [#zc9428f7] |
| + | - jupyterhub-idle-culler は期待通りに動かない.cull_idle_servers.py の方が良いみたい. |
| + | - https://github.com/jupyterhub/jupyterhub/tree/a6b7e303df03865d6420f6bccdf627b39f1d0dc1/examples/cull-idle |
| + | |
| + | - 実行状態(run)も確実に殺してくれる(stop でなくて, rm). |
| + | - Webで開いたままだとダメ |
| + | |
| + | |
| + | - jupyterhub_config.py |
| + | import sys |
| + | |
| + | c.JupyterHub.services = [ |
| + | { |
| + | 'name': 'idle-culler', |
| + | 'admin': True, |
| + | 'command': [ |
| + | sys.executable, |
| + | '/usr/local/bin/cull_idle_servers.py', |
| + | '--timeout=3600' |
| + | ], |
| + | } |
| + | ] |
| + | #br |
| + | |
| + | ** Trouble Shooting [#j137c8ff] |
| + | |
| + | **** 新しいファイルがパーミッションが無いとして,作成できない. [#z72fb1be] |
| + | - %%SystemUserSpawnar の場合は,まず現実のファイルのパーミッションをチェック%% |
| + | - コンテナ内 に入って,ファイルのパーミッションをチェック. (力ずく!) |
| + | - start.sh の設定がダメダメだった. |
| + | -- start.sh 内でパーミッションを設定すれば OK |
| + | |
| + | #br |
| + | |
| + | * Hack [#gdd93e11] |
| + | *** カスタマイズ [#p63e4677] |
| + | - https://jupyterhub.readthedocs.io/en/stable/reference/spawners.html |
| + | #br |
| + | |
| + | *** DockerSpawner が self.get_env() で取れる情報 [#bb38d813] |
| + | |
| + | { |
| + | 'JUPYTERHUB_API_TOKEN': 'cfd4fbcd6ea6491492016765dbbf4805', |
| + | 'JPY_API_TOKEN': 'cfd4fbcd6ea6491492016765dbbf4805', |
| + | 'JUPYTERHUB_CLIENT_ID': 'jupyterhub-user-bob', |
| + | 'JUPYTERHUB_HOST': '', |
| + | 'JUPYTERHUB_OAUTH_CALLBACK_URL': '/user/bob/oauth_callback', |
| + | 'JUPYTERHUB_USER': 'bob', |
| + | 'JUPYTERHUB_SERVER_NAME': '', |
| + | 'JUPYTERHUB_API_URL': 'http://172.22.1.75:8081/hub/api', |
| + | 'JUPYTERHUB_ACTIVITY_URL': 'http://172.22.1.75:8081/hub/api/users/bob/activity', |
| + | 'JUPYTERHUB_BASE_URL': '/', |
| + | 'JUPYTERHUB_SERVICE_PREFIX': '/user/bob/', |
| + | 'GRANT_SUDO': 'yes', |
| + | 'USER': 'bob', |
| + | 'NB_USER': 'bob', |
| + | 'USER_ID': 1001, |
| + | 'NB_UID': 1001, |
| + | 'HOME': '/home/users/bob', |
| + | 'NB_GID': 100 |
| + | } |
| + | |
| + | *** 認証モジュール [#xecc82c3] |
| + | - /usr/local/anaconda/envs/jupyterhub/lib/python3.8/site-packages/ldapauthenticator/ |
| + | - /usr/local/anaconda/envs/jupyterhub/lib/python3.8/site-packages/ltiauthenticator/ |
| + | - /usr/local/anaconda/envs/jupyterhub/lib/python3.8/site-packages/jupyterhub/auth.py |
| + | #br |
| + | |
| + | *** Groups毎にマウントするボリュームを変える [#wefff3af] |
| + | - https://qiita.com/marufeuille/items/62e3a842f7a039c35aac |
| + | #br |
| + | |
| + | ** Users [#m3f602dc] |
| + | - 以下でやろうとしたこと(ユーザを jovyan以外する)は [[''dockerspawner.SystemUserSpawner''>../SystemUserSpawner]] を使用すれば解決するので,没. |
| + | #br |
| + | |
| + | *** singleuser (コンテナ内)[#oea09b82] |
| **** プロセスの起動順 [#z1fe719e] | | **** プロセスの起動順 [#z1fe719e] |
| + /opt/conda/bin/tini | | + /opt/conda/bin/tini |
| | | |
| **** start.sh [#lb268269] | | **** start.sh [#lb268269] |
- | - [[start.sh>./start.sh]] | + | - [[start.sh(改)>./start.sh-kai]] |
| #br | | #br |
- | *** 設定ファイルから,パラメータ(引数)を渡す [#y62d4f07] | |
- | - 任意のパラメータ(引数)に ''{username}'' 等を使用可能にする | |
| | | |
| + | **** 起動コマンド [#mde3032e] |
| + | tini -g -- \ |
| + | start-notebook.sh --ip=0.0.0.0 --port=8888 --notebook-dir=/home/teacher/iseki/jupyter --SingleUserNotebookApp.default_url=/lab |
| + | |
| + | sudo -E -H -u iseki PATH=/opt/conda/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin XDG_CACHE_HOME=/home/teacher/iseki/.cache PYTHONPATH= \ |
| + | jupyterhub-singleuser --ip=0.0.0.0 --port=8888 --notebook-dir=/home/teacher/iseki/jupyter --SingleUserNotebookApp.default_url=/lab |
| + | |
| + | *** Docker の起動 [#o46a3f42] |
| + | - Docker の起動コマンド |
| + | -- /usr/local/anaconda/envs/jupyterhub/lib/python3.8/site-packages/dockerspawner/dockerspawner.py |
| + | -- L804 の get_command() |
| + | #br |
| + | *** 設定ファイルから,パラメータ(引数)を渡す [#y62d4f07] |
| + | **** 下記機能の実現は環境変数によっても可能 [#da119405] |
| + | - file |
| + | /usr/local/anaconda/envs/jupyterhub/lib/python3.8/site-packages/jupyterhub/spawner.py |
| + | - Docker に渡す引数の制御 |
| + | -- 任意のパラメータ(引数)に ''{username}'' 等を使用可能にする |
| c.DockerSpawner.args = ['--username={username}'] | | c.DockerSpawner.args = ['--username={username}'] |
| + | -- ''self.format_string''() を通すと {...} を処理してくれる. |
| | | |
- | **** 1.0.0 [#y39182eb] | + | - ''注:''[[SystemUserSpawner>../SystemUserSpawner]] が正しく動けば, コンテナ内の環境変数 NB_USER で取れるので,''以下のコード修正は不要''. |
- | - /usr/local/anaconda/envs/jupyterhub/lib/python3.8/site-packages/jupyterhub/spawner.py | + | -- さらに jupyterhub_config.py 内などで新しい Class を定義してやれば,グループ名も取れる! |
| + | #br |
| | | |
| + | ***** code [#td63949c] |
| + | |
| + | - /usr/local/anaconda/envs/jupyterhub/lib/python3.8/site-packages/jupyterhub/spawner.py |
| + | - 継承を使う方がスマート |
| + | - 1.0.0 |
| 936 if self.debug: | | 936 if self.debug: |
| 937 args.append('--debug') | | 937 args.append('--debug') |
| 945 return args | | 945 return args |
| | | |
- | **** 1.4.1 [#t8c2f07d] | + | - 1.4.1 |
| --- envs/jupyterhub/lib/python3.8/site-packages/jupyterhub/spawner.py.orig 2021-07-04 23:06:38.269817910 +0900 | | --- envs/jupyterhub/lib/python3.8/site-packages/jupyterhub/spawner.py.orig 2021-07-04 23:06:38.269817910 +0900 |
| +++ envs/jupyterhub/lib/python3.8/site-packages/jupyterhub/spawner.py 2021-07-04 23:07:45.485894520 +0900 | | +++ envs/jupyterhub/lib/python3.8/site-packages/jupyterhub/spawner.py 2021-07-04 23:07:45.485894520 +0900 |
| + args.append(self.format_string(arg)) | | + args.append(self.format_string(arg)) |
| return args | | return args |
| + | |
| def run_pre_spawn_hook(self): | | def run_pre_spawn_hook(self): |