JupyterHub 安装

  本文主要内容来自 JupyterHub 官方文档,加入了一些必要的解释说明并剔除冗余的句子,便于国内用户参阅使用。

  纯手工码字,支持原创,转载请注明出处。

JupyterHub 官方文档:https://jupyterhub.readthedocs.io/en/latest/quickstart.html

安装须知

  JupyterHub 支持 Linux。JupyterHub 服务器可以在内网上,也可以在公网运行(在这种情况下,要注意服务的安全性)。

  JupyterHub 不支持 Windows。Spawner 和 Authenticator 可以在 Windows 上使用,但 JupyterHub 不能。官方不接受 Windows 上的 bug 报告,测试套件也不能在 Windows 上运行。建议在 docker 容器或 linuxvm 中运行 JupyterHub。

在开始安装之前,最好考虑以下几点:

  • 部署方式——裸机、Docker
  • 身份验证方式——PAM、OAuth等
  • 单用户 notebook 服务的 Spawner 方式——Docker、Batch等
  • 服务方式——nbgrader等
  • JupyterHub 数据库——默认是SQLite;也支持传统的RDBMS(PostgreSQL)、MySQL 或 SQLAlchemy 支持的其他数据库

文件相关

  建议将 JupyterHub 使用的所有文件放入标准的 UNIX 文件系统位置。

/srv/jupyterhub  # 安全和运行时文件
/etc/jupyterhub  # 配置文件
/var/log  # 日志文件

 

快速开始

准备工作

  • 一台 Linux 机器
  • Python3.5 以上版本,配有 pip 或 conda 
  • nodejs/npm
    • 如果使用 conda,nodejs 和 npm 的依赖项将由conda安装
    • 如果使用 pip,需要自行安装
      sudo apt-get install npm nodejs-legacy
  • 一个可插入的身份验证模块(PAM)来使用默认的身份验证程序。PAM通常在大多数发行版上默认可用,如果不行的话,可以使用操作系统的包管理器安装它。
  • 用于 HTTPS 通信的 TLS 证书和密钥
  • 域名

 

安装 JupyterHub

  • 使用 pip 安装
    python3 -m pip install jupyterhub
    npm install -g configurable-http-proxy
    python3 -m pip install notebook  # needed if running the notebook servers locally
  • 使用 conda 安装
    conda install -c conda-forge jupyterhub  # installs jupyterhub and proxy
    conda install notebook  # needed if running the notebook servers locally

 

测试安装是否成功

jupyterhub -h
configurable-http-proxy -h

 

运行

jupyterhub   # 访问https://localhost:8000
sudo jupyterhub  # 允许多用户

 

使用 Docker 安装

  官方提供了 JupyterHub 的 Docker 镜像,不过这个只是运行 Hub 服务本身的镜像。不提供单用户服务器所需的其他 Jupyter 组件,如 Jupyter Notebook 安装。要运行单用户服务器,必须自行安装 Jupyter Notebook version 4或更高版本。

命令

docker run -d -p 8000:8000 --name jupyterhub jupyterhub/jupyterhub jupyterhub
docker exec -it jupyterhub bash  # 进入容器

 

  此命令将创建一个名为 jupyterhub 的容器,监听 8000 端口,可以使用 docker stop/start. 停止和恢复该容器。

  如果需要在具有公网 IP 的服务器上运行 Docker,需要在 Docker 配置中添加 ssl 选项或使用启用 ssl 的代理来保护 Docker

 

Docker 安装自定制 jupyterhub

  • 官方最新 jupyterhub 镜像存在问题,这里使用1.0.0版本
  • 默认使用 linux 用户体系进行用户认证,需要在jupyterhub 的 docker 容器中,/home 路径需要加创建文件夹的权限
  • jupyterhub支持自定制,映射容器的 /srv/jupyterhub 文件夹到宿主机如 /data/jupyterhub/jupyterhub-custom,在该路径下创建自定义文件即可。 默认支持自定义的文件如下:
    • jupyterhub_config.py:自定制用户认证,支持使用 linux 用户体系或接入第三方体系(如Google、Github等)
    • 自定制templates:支持自定制某些前端页面,需要在jupyterhub_config.py指定c.JupyterHub.template_paths = ["templates"]
      • login.html:登录页面
      • home.html:个人主页
      • token.html:token页面
      • 404.html
      • admin.html
      • error.html
      • logout.html
      • page.html:其他 html 的基类模板
      • not_running.html
      • oauth.html
      • spawm.html
      • spawn_pending.html
      • stop_pending.html
  • 其他的深度自定制则需要进入容器中修改源码,如
    • 自定制后端登录功能:需要修改 /opt/conda/lib/python3.6/site-packages/jupyterhub/login.py
    • 自定制 notebook 页面的导航条:需要修改/opt/conda/lib/python3.6/site-packages/jupyterhub/singleuser.py
    • 深度自定制 notebook 页面:需要修改/opt/conda/lib/python3.6/site-packages/notebook/templates/tree.html

 

部署流程

  1. 拉取镜像 
    docker pull jupyterhub/jupyterhub:1.0.0 
    docker pull jupyterhub/singleuser:1.0.0
  2. 创建 jupyterhub_network 网络 
    docker network create --driver bridge jupyterhub_network
  3. 创建 jupyterhub 的 volume  
    mkdir -pv /data/jupyterhub/jupyterhub-custom  # 用于创建自定制的文件
    mkdir -pv /data/jupyterhub/jupyterhub-docker-con # 用于映射docker容器内部的路径,如/home
    chmod -R 777 /data/jupyterhub
  4. 若需要自定义前端页面,在 /data/jupyterhub/jupyterhub-custom 下创建文件夹 templates,在该文件夹下创建自定制模板文件。如:
    • page.html,自定义基板
    • home.html,自定义个人主页
    • login.html,自定义login页面
    • ......
  5. 在 /data/jupyterhub/jupyterhub-custom 下创建 jupyterhub_config.py 文件
    # coding:utf-8
    
    from tornado import gen
    from jupyterhub.auth import Authenticator
    import os
    import pwd
    import requests
    
    class MyAuthenticator(Authenticator):
    
        def system_user_exists(self, username):
            """Check if the user exists on the system"""
            try:
                self.log.info('create user: %s' % username)
                pwd.getpwnam(username)
            except Exception as e:
                self.log.error('create password for user error: %s' % e)
                return False
            else:
                return True
    
        def add_system_user(self, username, password):
            """Create a new local UNIX user on the system.
            Tested to work on FreeBSD and Linux, at least.
            """
            res = os.system('useradd  %(name1)s ' % {'name1': username})
            if res:
                self.log.warn('user %s create failure: %s' % (username, res))
                return False
    
            # res = os.system('echo %(pass)s |passwd --stdin %(name1)s' % {'name1': username, 'pass': password})
            res = os.system('echo %(name1)s:%(pass)s | chpasswd' % {'name1': username, 'pass': password})
    
            if res:
                self.log.warn('user %s password create failure: %s' % (username, res))
                return False
            return True
    
        def check_token_local(self, token):
            sec = 'l55cj)hh95jorr6!vmhleo0tuyors)xy@@+jaj-^l6wp)))=d$'
            algorithm = 'HS256'
            try:
                d = jwt.decode(token, sec, algorithm)
                return d.get('user_id')
            except:
                return None
    
        @gen.coroutine
        def authenticate(self, handler, data):
            '''
    
            :param handler:
            :param data:
            :return: 成功:username,失败:None
            '''
            self.log.warn(data)
            token = data.get('token')
            self.log.warn('request token is: %s' % token)
            if not token:
                return None
    
            # 验证token
            user_id, username = self.check_token_local(token)
            self.log.warn('--- current user id: %s' % user_id)
    
            if not user_id or not username:
                return None
    
            user = 'user_%s' %user_id
            password = 'deault_jupyter_pwd_random_string_for_user'
    
            if not self.system_user_exists(user):
                if self.add_system_user(user, password):
                    return user
                else:
                    return None
    
            return user
    
    
            #user = handler.request.headers.get("User_info")
            #if user is not None:
            #    user = json.loads(user)
            #    username = user.get("username")
            #    return username
    
    c.JupyterHub.authenticator_class = MyAuthenticator
    
    c.PAMAuthenticator.encoding = 'utf8'
    
    # 指定cookie secret的文件,内容必须是64位哈希字符串,如6dd65ff19de7b8cb6d53031b0ad940e7379e15cf7ab612094d19e8b5141cc52c
    # c.JupyterHub.cookie_secret_file = '/srv/jupyterhub/jupyterhub_cookie_secret'
    
    #创建用户时已经开指定的目录,这里就不需要在指定工作目了
    #c.Spawner.notebook_dir = '/data/file'
    
    #开启管理员用户
    c.JupyterHub.admin_access = True
    c.JupyterHub.admin_users = {"jupyterhub", "root"}
    
    # 白名单
    # c.Authenticator.whitelist = {}
    
    # Jupyterhub service setting
    # c.JupyterHub.spawner_class = 'sudospawner.SudoSpawner'
    c.JupyterHub.base_url = '/jupyter/'
    c.JupyterHub.cookie_max_age_days = 1  # cookie有效期为1天,默认值14为2周
    
    # customer templstes path, default is []
    c.JupyterHub.template_paths = ["templates"]
    View Code
  6. 在 /data/jupyterhub/jupyterhub-custom 下创建userlist文件,写入admin用户,该用户是容器的管理员用户
    jupyterhub admin
    root admin
  7. 在 /data/jupyterhub/jupyterhub-custom 下创建 Dockerfile
    ARG BASE_IMAGE=jupyterhub/jupyterhub:1.0.0
    FROM ${BASE_IMAGE}
    
    ADD templates /srv/jupyterhub/templates
    ADD jupyterhub_config.py /srv/jupyterhub
    ADD userlist /srv/jupyterhub
    
    RUN echo "[global]\nindex-url = https://mirrors.aliyun.com/pypi/simple/" > /etc/pip.conf &&\
        pip install --no-cache --upgrade jupyter &&\
        pip install --no-cache dockerspawner &&\
        pip install --no-cache oauthenticator  &&\
        chmod -R 777 /home
    EXPOSE 8000
    
    USER root
  8. 执行 build 命令构建镜像 
    docker build -t custom/jupyterhub .
  9. 在 /data/jupyterhub/jupyterhub-custom 下创建 singleuser 文件夹,在该文件夹下创建 Dockerfile
    ARG BASE_IMAGE=jupyterhub/singleuser:1.0.0
    FROM ${BASE_IMAGE}
    
    RUN pip install jupyterlab &&\
        jupyter serverextension enable --py jupyterlab --sys-prefix
    
    USER root
  10. 在 /data/jupyterhub/jupyterhub-custom/singleuser 下执行build命令构建镜像
     docker build -t custom/jupyter_lab_singleuser .
  11. 创建/data/jupyterhub/jupyterhub-docker-con/docker-home用于映射容器内部的/home路径
  12. 开启容器
    docker run -d --name jupyterhub -p18000:8000 \ 
    --network jupyterhub_network \
    -v /var/run/docker.sock:/var/run/docker.sock \ 
    -v /data/jupyterhub/jupyterhub-custom:/srv/jupyterhub \
    -v /data/jupyterhub/jupyterhub-docker-con/docker-home:/home \ 
    jupyterhub/jupyterhub:latest 
  13. 进入容器,修改/home路径的权限
    docker exec -it jupyterhub bash
    chmod -R 777 /home

     

 

 

另:网上看到几篇相关文章《用Docker部署自己的JupyterHub》《使用Docker安装多用户版的JupyterHub》先 Marc

 

                         

 

posted @ 2022-03-15 10:38  ''竹先森゜  阅读(2195)  评论(0编辑  收藏  举报