Docker部署JupyterHub问题记录

一、问题概述

最近项目使用到JupyterHub,要求版本低于2.0.0,使用Docker部署。小编接到任务后立刻着手处理,过程中遇到了不少困难,特以此记录,供有需要的小伙伴参考。如果你在使用JupyterHub:1.5.1过程中遇到以下问题,那本篇文章可能会给予你一定解决思路。

  1. 登录用户名密码未知
  2. 初始化工作空间失败。浏览器报错Spawn failed: Server at http://127.0.0.1:58530/user/admin/ didn't respond in 30 seconds
  3. 初始化工作空间失败。日志报错ModuleNotFoundError: No module named 'notebook'
  4. 初始化工作空间失败。日志报错ModuleNotFoundError: No module named 'notebook.notebookapp'

扩展知识:JupyterHub:2.0.0之后的版本API状态码发生变更,部分API返回状态码从200变为了201

二、过程记录

  1. 小编从未接触过JupyterHub,一切从零开始,按照惯例,先查看了官方文档

    Docker

    A starter docker image for JupyterHub gives a baseline deployment of JupyterHub using Docker.

    Important: This quay.io/jupyterhub/jupyterhub image contains only the Hub itself, with no configuration. In general, one needs to make a derivative image, with at least a jupyterhub_config.py setting up an Authenticator and/or a Spawner. To run the single-user servers, which may be on the same system as the Hub or not, Jupyter Notebook version 4 or greater must be installed.

    The JupyterHub docker image can be started with the following command:

    docker run -p 8000:8000 -d --name jupyterhub quay.io/jupyterhub/jupyterhub jupyterhub
    

    This command will create a container named jupyterhub that you can stop and resume with docker stop/start.

    The Hub service will be listening on all interfaces at port 8000, which makes this a good choice for testing JupyterHub on your desktop or laptop.

    If you want to run docker on a computer that has a public IP then you should (as in MUST) secure it with ssl by adding ssl options to your docker configuration or by using an ssl enabled proxy.

    Mounting volumes will allow you to store data outside the docker image (host system) so it will be persistent, even when you start a new image.

    The command docker exec -it jupyterhub bash will spawn a root shell in your docker container. You can use the root shell to create system users in the container. These accounts will be used for authentication in JupyterHub’s default configuration.

    文档中提到的什么衍生镜像配置文件创建系统用户,对于初次接触JupyterHub的小编而言,不是很理解。但小编怎么也没想到,这些不理解的名词最终均成为了使用过程中的拦路虎。

  2. 按照官方文档,拉取镜像并运行容器

    docker pull jupyterhub/jupyterhub:1.5.1
    docker run -p 8000:8000 -d --name jupyterhub jupyterhub/jupyterhub:1.5.1
    
  3. 通过浏览器访问http://192.168.10.60:8000,注意:192.168.10.60是小编的虚机地址,观众老爷们使用时请更换为自己的IP地址

    请添加图片描述

    到目前为止,似乎一切正常,但一切只是暴风雨前的宁静

三、相关问题

1. 登录用户名密码未知

一般docker容器运行起来后,都会预置一个用户,但JupyterHub没有,需要用户自己创建。参考文档语句

You can use the root shell to create system users in the container.

具体的创建步骤如下:

# 1. 使用 docker exec -it jupyterhub bash 进入容器。
[root@kubernetes ~]# docker exec -it jupyterhub bash

# 2. 使用 adduser 创建用户。用户名密码根据个人喜好而定,以用户名admin为例,则执行命令adduser admin,密码根据后续提示输入
root@8f00c665c51b:/srv/jupyterhub# adduser admin
Adding user `admin' ...
Adding new group `admin' (1000) ...
Adding new user `admin' (1000) with group `admin' ...
Creating home directory `/home/admin' ...
Copying files from `/etc/skel' ...
New password: 
Retype new password: 
passwd: password updated successfully
Changing the user information for admin
Enter the new value, or press ENTER for the default
	Full Name []: 
	Room Number []: 
	Work Phone []: 
	Home Phone []: 
	Other []: 
Is the information correct? [Y/n] Y

创建成功后,浏览器访问http://192.168.10.60:8000,使用对应的用户名密码登录,你应该可以看到如下界面

请添加图片描述

但问题还远远未结束,请继续往下看。

2. 初始化工作空间失败

初次使用账号密码登录后,JupyterHub将生成对应用户的工作空间,但由于JupyterHub缺少部分模块,你将出现如下报错

Spawn failed: Server at http://127.0.0.1:58530/user/admin/ didn’t respond in 30 seconds

请添加图片描述

通过docker logs -f jupyterhub查看日志,可发现ModuleNotFoundError: No module named 'notebook',即缺少notebook模块

Traceback (most recent call last):
  File "/usr/local/bin/jupyterhub-singleuser", line 5, in <module>
    from jupyterhub.singleuser import main
  File "/usr/local/lib/python3.8/dist-packages/jupyterhub/singleuser/__init__.py", line 5, in <module>
    from .app import main
  File "/usr/local/lib/python3.8/dist-packages/jupyterhub/singleuser/app.py", line 16, in <module>
    App = import_item(JUPYTERHUB_SINGLEUSER_APP)
  File "/usr/local/lib/python3.8/dist-packages/traitlets/utils/importstring.py", line 30, in import_item
    module = __import__(package, fromlist=[obj])
ModuleNotFoundError: No module named 'notebook'
Task exception was never retrieved
future: <Task finished name='Task-5280' coro=<BaseHandler.spawn_single_user() done, defined at /usr/local/lib/python3.8/dist-packages/jupyterhub/handlers/base.py:802> exception=HTTPError()>
Traceback (most recent call last):
  File "/usr/local/lib/python3.8/dist-packages/jupyterhub/handlers/base.py", line 1002, in spawn_single_user
    await gen.with_timeout(
asyncio.exceptions.TimeoutError: Timeout

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/usr/local/lib/python3.8/dist-packages/jupyterhub/handlers/base.py", line 1036, in spawn_single_user
    raise web.HTTPError(
tornado.web.HTTPError: HTTP 500: Internal Server Error (Spawner failed to start [status=1]. The logs for admin may contain details.)
[W 2024-05-30 03:18:12.285 JupyterHub user:767] admin's server never showed up at http://127.0.0.1:58530/user/admin/ after 30 seconds. Giving up
[E 2024-05-30 03:18:12.314 JupyterHub gen:630] Exception in Future <Task finished name='Task-5281' coro=<BaseHandler.spawn_single_user.<locals>.finish_user_spawn() done, defined at /usr/local/lib/python3.8/dist-packages/jupyterhub/handlers/base.py:906> exception=TimeoutError("Server at http://127.0.0.1:58530/user/admin/ didn't respond in 30 seconds")> after timeout
    Traceback (most recent call last):
      File "/usr/local/lib/python3.8/dist-packages/tornado/gen.py", line 625, in error_callback
        future.result()
      File "/usr/local/lib/python3.8/dist-packages/jupyterhub/handlers/base.py", line 913, in finish_user_spawn
        await spawn_future
      File "/usr/local/lib/python3.8/dist-packages/jupyterhub/user.py", line 748, in spawn
        await self._wait_up(spawner)
      File "/usr/local/lib/python3.8/dist-packages/jupyterhub/user.py", line 795, in _wait_up
        raise e
      File "/usr/local/lib/python3.8/dist-packages/jupyterhub/user.py", line 762, in _wait_up
        resp = await server.wait_up(
      File "/usr/local/lib/python3.8/dist-packages/jupyterhub/utils.py", line 237, in wait_for_http_server
        re = await exponential_backoff(
      File "/usr/local/lib/python3.8/dist-packages/jupyterhub/utils.py", line 185, in exponential_backoff
        raise TimeoutError(fail_message)
    TimeoutError: Server at http://127.0.0.1:58530/user/admin/ didn't respond in 30 seconds

既然缺少模块,那就安装模块。经验丰富的开发者,可能已经想到通过如下命令安装

pip3 install notebook

但如果你真的这样做,模块安装不会报错,但当你浏览器访问http://192.168.10.60:8000,再次初始化工作空间时,你将再次收到报错Spawn failed: Server at http://127.0.0.1:34220/user/admin/ didn't respond in 30 seconds。同时,日志报错更换为了ModuleNotFoundError: No module named 'notebook.notebookapp'

Traceback (most recent call last):
  File "/usr/local/bin/jupyterhub-singleuser", line 5, in <module>
    from jupyterhub.singleuser import main
  File "/usr/local/lib/python3.8/dist-packages/jupyterhub/singleuser/__init__.py", line 5, in <module>
    from .app import main
  File "/usr/local/lib/python3.8/dist-packages/jupyterhub/singleuser/app.py", line 16, in <module>
    App = import_item(JUPYTERHUB_SINGLEUSER_APP)
  File "/usr/local/lib/python3.8/dist-packages/traitlets/utils/importstring.py", line 30, in import_item
    module = __import__(package, fromlist=[obj])
ModuleNotFoundError: No module named 'notebook.notebookapp'
Task exception was never retrieved
future: <Task finished name='Task-6806' coro=<BaseHandler.spawn_single_user() done, defined at /usr/local/lib/python3.8/dist-packages/jupyterhub/handlers/base.py:802> exception=HTTPError()>
Traceback (most recent call last):
  File "/usr/local/lib/python3.8/dist-packages/jupyterhub/handlers/base.py", line 1002, in spawn_single_user
    await gen.with_timeout(
asyncio.exceptions.TimeoutError: Timeout

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/usr/local/lib/python3.8/dist-packages/jupyterhub/handlers/base.py", line 1036, in spawn_single_user
    raise web.HTTPError(
tornado.web.HTTPError: HTTP 500: Internal Server Error (Spawner failed to start [status=1]. The logs for admin may contain details.)
[W 2024-05-30 03:38:52.002 JupyterHub user:767] admin's server never showed up at http://127.0.0.1:34220/user/admin/ after 30 seconds. Giving up
[E 2024-05-30 03:38:52.022 JupyterHub gen:630] Exception in Future <Task finished name='Task-6807' coro=<BaseHandler.spawn_single_user.<locals>.finish_user_spawn() done, defined at /usr/local/lib/python3.8/dist-packages/jupyterhub/handlers/base.py:906> exception=TimeoutError("Server at http://127.0.0.1:34220/user/admin/ didn't respond in 30 seconds")> after timeout
    Traceback (most recent call last):
      File "/usr/local/lib/python3.8/dist-packages/tornado/gen.py", line 625, in error_callback
        future.result()
      File "/usr/local/lib/python3.8/dist-packages/jupyterhub/handlers/base.py", line 913, in finish_user_spawn
        await spawn_future
      File "/usr/local/lib/python3.8/dist-packages/jupyterhub/user.py", line 748, in spawn
        await self._wait_up(spawner)
      File "/usr/local/lib/python3.8/dist-packages/jupyterhub/user.py", line 795, in _wait_up
        raise e
      File "/usr/local/lib/python3.8/dist-packages/jupyterhub/user.py", line 762, in _wait_up
        resp = await server.wait_up(
      File "/usr/local/lib/python3.8/dist-packages/jupyterhub/utils.py", line 237, in wait_for_http_server
        re = await exponential_backoff(
      File "/usr/local/lib/python3.8/dist-packages/jupyterhub/utils.py", line 185, in exponential_backoff
        raise TimeoutError(fail_message)
    TimeoutError: Server at http://127.0.0.1:34220/user/admin/ didn't respond in 30 seconds
   

通过小编分析,推断应该是在新版的notebook(小编出现问题的版本是7.2.0)中对notebook.notebookapp进行了变更,通过百度等手段发现似乎新版的nodebook中notebook.notebookapp变更为了notebook.app

故你不能直接升级最新版的nodebook,对于jupyterhub:1.5.1,建议你安装notebook:6.5.2,其他jupyterhub版本详见附录一:查询缺失的模块版本

pip3 install notebook==6.5.2

提示:若网络不好,建议使用pip国内镜像源,如清华镜像源

pip3 install -i https://pypi.tuna.tsinghua.edu.cn/simple notebook==6.5.2

安装成功后,浏览器访问http://192.168.10.60:8000,你应该就可以发现工作空间初始化成功,并进入到如下界面

请添加图片描述

安装问题,到此告一段落,但对于Jupyterhub的深度使用者可能还想要自定义jupyterhub配置,详情请见 附录二:自定义JupyterHub配置

四、总结(省流版)

1. 登录用户名密码未知

一般docker容器运行起来后,都会预置一个用户,但JupyterHub没有,需要用户自己创建。命令如下:

# 1. 使用 docker exec -it jupyterhub bash 进入容器。
docker exec -it jupyterhub bash

# 2. 使用 adduser 创建用户。用户名密码根据个人喜好而定,以用户名admin为例,则执行命令adduser admin,密码根据后续提示输入
adduser admin

2. 初始化工作空间失败

当使用的JupyterHub版本为1.5.1,登录后报错Spawn failed: Server at http://127.0.0.1:58530/user/admin/ didn't respond in 30 seconds。同时通过docker logs -f jupyterhub查看日志,发现ModuleNotFoundError: No module named 'notebook'。可通过安装notebook:6.5.2解决,其他jupyterhub版本详见附录一:查询缺失的模块版本

# 1. 使用 docker exec -it jupyterhub bash 进入容器。
docker exec -it jupyterhub bash

# 2. 安装notebook:6.5.2
pip3 install notebook==6.5.2

提示:若网络不好,建议使用pip国内镜像源,如清华镜像源

pip3 install -i https://pypi.tuna.tsinghua.edu.cn/simple notebook==6.5.2

五、附录

附录一:查询缺失的模块版本

不同版本的JupyterHub所需的依赖及依赖版本是不同的,这里给大家提供一种简单的方法。

官方除了提供jupyterhub/jupyterhub镜像,还提供了一个jupyterhub/jupyterhub-demo示例镜像,jupyterhub-demo的版本和jupyterhub的版本是相对应的,当jupyterhub依赖缺失时,我们可以去对应版本的jupyterhub-demo中寻找。例如,当jupyterhub:1.5.1存在依赖缺失,我们可以使用如下方式查找

  1. 创建jupyterhub-demo容器

    docker run -d --name jupyterhub-demo jupyterhub/jupyterhub-demo:1.5.1
    
  2. 进入jupyterhub-demo容器

    docker exec -it jupyterhub-demo bash
    
  3. 使用pip3 list查看依赖及版本

    demo@e5666f444a6b:/srv/jupyterhub$ pip3 list
    Package              Version
    -------------------- -----------
    alembic              1.8.1
    anyio                3.6.2
    argon2-cffi          21.3.0
    argon2-cffi-bindings 21.2.0
    asttokens            2.2.1
    async-generator      1.10
    attrs                22.1.0
    backcall             0.2.0
    beautifulsoup4       4.11.1
    bleach               5.0.1
    certifi              2022.9.24
    certipy              0.1.3
    cffi                 1.15.1
    charset-normalizer   2.1.1
    cryptography         38.0.4
    debugpy              1.6.4
    decorator            5.1.1
    defusedxml           0.7.1
    entrypoints          0.4
    executing            1.2.0
    fastjsonschema       2.16.2
    greenlet             2.0.1
    idna                 3.4
    importlib-metadata   5.1.0
    importlib-resources  5.10.0
    ipykernel            6.17.1
    ipython              8.7.0
    ipython-genutils     0.2.0
    jedi                 0.18.2
    Jinja2               3.1.2
    jsonschema           4.17.3
    jupyter_client       7.4.8
    jupyter_core         5.1.0
    jupyter-server       1.23.3
    jupyter-telemetry    0.1.0
    jupyterhub           1.5.1
    jupyterlab-pygments  0.2.2
    Mako                 1.2.4
    MarkupSafe           2.1.1
    matplotlib-inline    0.1.6
    mistune              2.0.4
    nbclassic            0.4.8
    nbclient             0.7.2
    nbconvert            7.2.6
    nbformat             5.7.0
    nest-asyncio         1.5.6
    notebook             6.5.2
    notebook_shim        0.2.2
    oauthlib             3.2.2
    packaging            21.3
    pamela               1.0.0
    pandocfilters        1.5.0
    parso                0.8.3
    pexpect              4.8.0
    pickleshare          0.7.5
    pip                  22.3.1
    pkgutil_resolve_name 1.3.10
    platformdirs         2.5.4
    prometheus-client    0.15.0
    prompt-toolkit       3.0.33
    psutil               5.9.4
    ptyprocess           0.7.0
    pure-eval            0.2.2
    pycparser            2.21
    pycurl               7.43.0.2
    Pygments             2.13.0
    pyOpenSSL            22.1.0
    pyparsing            3.0.9
    pyrsistent           0.19.2
    python-dateutil      2.8.2
    python-json-logger   2.0.4
    pyzmq                24.0.1
    requests             2.28.1
    ruamel.yaml          0.17.21
    ruamel.yaml.clib     0.2.7
    Send2Trash           1.8.0
    setuptools           65.6.3
    six                  1.16.0
    sniffio              1.3.0
    soupsieve            2.3.2.post1
    SQLAlchemy           1.4.44
    stack-data           0.6.2
    terminado            0.17.1
    tinycss2             1.2.1
    tornado              6.2
    traitlets            5.6.0
    urllib3              1.26.13
    wcwidth              0.2.5
    webencodings         0.5.1
    websocket-client     1.4.2
    wheel                0.34.2
    zipp                 3.11.0
    
    [notice] A new release of pip available: 22.3.1 -> 24.0
    [notice] To update, run: python3 -m pip install --upgrade pip
    

    提示:如果你仅查询某指定模块版本,可使用如下命令,以notebook为例

    demo@e5666f444a6b:/srv/jupyterhub$ pip3 list | grep notebook
    notebook             6.5.2
    notebook_shim        0.2.2
    
    [notice] A new release of pip available: 22.3.1 -> 24.0
    [notice] To update, run: python3 -m pip install --upgrade pip
    

附录二:自定义JupyterHub配置

jupyterhub镜像仅包含Hub本身,不包含配置,详见文档语句:

This quay.io/jupyterhub/jupyterhub image contains only the Hub itself, with no configuration

自定义配置可通过如下方式:

  1. 创建自定义配置,存放位置根据个人喜好,这里使用/etc/jupyterhub/jupyterhub_config.py。在例子中,我们配置登录时可使用任意用户名密码

    # Configuration file for jupyterhub-demo
    
    c = get_config()
    
    # Use DummyAuthenticator and SimpleSpawner
    c.JupyterHub.spawner_class = "simple"
    c.JupyterHub.authenticator_class = "dummy"
    

    提示:不同版本的jupyterhub配置文件格式可能不同,具体格式可按照 附录一:查询缺失的模块版本 类似的方式查找,jupyterhub-demo通常会把配置文件放在/srv/jupyterhub路径下

  2. 挂载配置文件,并更改docker容器启动参数

    docker run -p 8000:8000 -d --name jupyterhub \
    -v /etc/jupyterhub/jupyterhub_config.py:/etc/jupyterhub/jupyterhub_config.py \
    jupyterhub/jupyterhub:1.5.1 jupyterhub -f=/etc/jupyterhub/jupyterhub_config.py
    

    等待容器运行后,浏览器访问http://192.168.10.60:8000,便可发现任意用户名密码均可登录系统。

参考文档

jupyterhub/jupyterhub - Docker Image | Docker Hub

jupyterhub/jupyterhub-demo - Docker Image | Docker Hub

  • 29
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
要在Docker中配置JupyterHub,您可以按照以下步骤进行操作: 1. 首先,确保您已经安装了DockerDocker Compose。如果没有,请先安装它们。 2. 创建一个名为`jupyterhub`的文件夹,并在其中创建一个名为`Dockerfile`的文件。 3. 在`Dockerfile`中添加以下内容: ```Dockerfile FROM jupyterhub/jupyterhub:1.4 # 安装 JupyterHub 的依赖包 RUN pip install jupyterhub-dummyauthenticator # 添加自定义配置文件 COPY jupyterhub_config.py /srv/jupyterhub/jupyterhub_config.py ``` 这个Dockerfile基于官方的JupyterHub镜像,并安装了一个名为`jupyterhub-dummyauthenticator`的虚拟认证器,以便在测试环境中使用。您可以根据需要更改认证器。 4. 在`jupyterhub`文件夹中创建一个名为`jupyterhub_config.py`的文件,并添加您的JupyterHub配置。例如: ```python c.JupyterHub.authenticator_class = 'dummyauthenticator.DummyAuthenticator' c.JupyterHub.spawner_class = 'dockerspawner.DockerSpawner' .DockerSpawner.image = 'jupyter/scipy-notebook' c.DockerSpawner.remove_containers = True # 添加其他配置选项... ``` 这里使用了`dummyauthenticator`作为虚拟认证器,并使用了`dockerspawner`作为启动器。您可以根据需要添加其他配置选项。 5. 确保您在`jupyterhub`文件夹中有一个名为`jupyterhub_config.py`的配置文件和一个名为`Dockerfile`的Docker文件。 6. 打开终端,导航到`jupyterhub`文件夹,并构建Docker镜像: ``` docker build -t jupyterhub-image . ``` 这会构建一个名为`jupyterhub-image`的Docker镜像。 7. 创建一个名为`docker-compose.yml`的文件,并添加以下内容: ```yaml version: '3' services: jupyterhub: image: jupyterhub-image ports: - 8000:8000 volumes: - /var/run/docker.sock:/var/run/docker.sock ``` 这个`docker-compose.yml`文件定义了一个名为`jupyterhub`的服务,使用之前构建的Docker镜像,并将主机的8000端口映射到容器的8000端口。 8. 在终端中导航到包含`docker-compose.yml`文件的目录,并运行以下命令启动JupyterHub: ``` docker-compose up -d ``` 现在,您应该可以通过访问`http://localhost:8000`来访问JupyterHub。 请注意,这只是一个简单的示例配置。根据您的需求,您可能需要进行更多的配置和调整。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值