自定义用户环境#

此页面包含有关增强用户体验的常见方法的说明。有关所有可配置 Helm 图表选项的列表,请参阅配置参考.

用户环境是用户登录 JupyterHub 时存在的软件包、环境变量和各种文件的集合。用户还可以看到提供界面以执行专门任务的不同工具,例如 JupyterLab、RStudio、RISE 等。

Docker 镜像构建的Dockerfile将为用户提供的环境奠定基础。例如,该镜像将确定哪些 Linux 软件(curl、vim…)、编程语言(Julia、Python、R…)和开发环境(JupyterLab、RStudio…)可供使用。

要开始自定义用户环境,请参阅以下主题。

选择并使用现有的 Docker 镜像#

此图表使用一个最小的默认单用户镜像,用于快速测试。您需要选择一个不同的镜像或构建自己的镜像以供实际使用。

Project Jupyter 维护着jupyter/docker-stacks 存储库,其中包含可立即使用的 Docker 镜像。每个镜像都包含一组常用的科学和数据科学库和工具。它们还提供了有关如何选择合适的镜像的出色文档。

例如,要使用datascience-notebook镜像(包含用于数据科学的有用工具和库),请完成以下步骤

  1. 修改您的config.yaml文件以指定镜像。例如

    singleuser:
      image:
        # You should replace the "latest" tag with a fixed version from:
        # https://hub.docker.com/r/jupyter/datascience-notebook/tags/
        # Inspect the Dockerfile at:
        # https://github.com/jupyter/docker-stacks/tree/HEAD/datascience-notebook/Dockerfile
        name: jupyter/datascience-notebook
        tag: latest
      # `cmd: null` allows the custom CMD of the Jupyter docker-stacks to be used
      # which performs further customization on startup.
      cmd: null
    

    注意

    容器镜像名称不能超过 63 个字符。

    始终使用显式的tag,例如特定提交。避免使用latest,因为它可能会导致用户在发布新版本镜像时出现几分钟的延迟、混乱或故障。

  2. 按照应用更改中列出的说明应用更改。

    如果您已配置prePuller.hook.enabled,则集群中的所有节点将在升级集线器之前拉取镜像,以允许用户使用该镜像。镜像拉取可能需要几分钟才能完成,具体取决于镜像的大小。

  3. 如果您已登录,请从 JupyterHub 控制面板重新启动服务器。

注意

如果您希望用户从多个 Docker 镜像中选择环境,请参阅使用多个配置文件让用户选择他们的环境.

选择用户界面#

JupyterLab 是 Jupyter 的新用户界面,旨在取代经典的笔记本用户界面 (UI)。如果同时安装了两种界面,用户已经可以在 URL 中互换/tree/lab来在经典 UI 和 JupyterLab 之间切换。使用 JupyterHub 1.x 及更早版本的部署默认使用经典 UI,而 JupyterHub 2.0 使 JupyterLab 成为默认界面。

为了为用户选择默认启动的用户界面,需要设置两个自定义项

  1. 首选的默认用户界面 (UI)

  2. 要启动的服务器程序

Jupyter 服务器主要有两种实现方式(大多数部署不会看到区别,但某些服务器扩展可能会出现问题。如果不能确定,新应用程序应选择 jupyter_server

  1. 现代的 jupyter server,当您使用 jupyter lab 或其他最近的 Jupyter 应用程序时启动,以及

  2. 传统的“经典”笔记本服务器 (jupyter notebook)

通常,默认 UI 在 config.yaml 中通过以下方式选择

singleuser:
  defaultUrl: ...

默认服务器通过以下方式选择

singleuser:
  extraEnv:
    JUPYTERHUB_SINGLEUSER_APP: "..."

具体来说,使用以下选项之一选择现代服务器

# this is the default with JupyterHub 2.0
singleuser:
  extraEnv:
    JUPYTERHUB_SINGLEUSER_APP: "jupyter_server.serverapp.ServerApp"

或选择经典笔记本服务器

# the default with JupyterHub 1.x
singleuser:
  extraEnv:
    JUPYTERHUB_SINGLEUSER_APP: "notebook.notebookapp.NotebookApp"

只有在配置与默认配置不同时才需要上述配置。JupyterHub 2.0 将默认服务器从 NotebookApp 更改为 ServerApp,因此我们在每个示例中明确进行选择,以便相同的配置在 JupyterHub 1.x 和 2.x 中产生相同的结果。这样,您的选择将在升级过程中保留。

默认使用 JupyterLab#

注意

这是 JupyterHub 2.0 和 Helm 图表 2.0 中的默认设置。

您可以在 config.yaml 中使用以下配置将 JupyterLab 作为默认 UI

singleuser:
  defaultUrl: "/lab"
  extraEnv:
    JUPYTERHUB_SINGLEUSER_APP: "jupyter_server.serverapp.ServerApp"

您还可以升级到较新的服务器实现,将 JupyterLab 设为默认 UI。这可能有助于需要坚持使用旧 UI 的用户,这些用户可能使用在新的服务器上无法正常工作的扩展。

singleuser:
  defaultUrl: "/lab"
  extraEnv:
    JUPYTERHUB_SINGLEUSER_APP: "notebook.notebookapp.NotebookApp"

注意

您需要 jupyterlab 包(可通过 pipconda 安装)才能使此功能正常工作。jupyter/docker-stacks 存储库 中的所有镜像都预先安装了此包。

默认使用经典笔记本#

注意

这是 JupyterHub 1.x 和 helm 图表 1.x 中的默认设置。

如果您还没有准备好升级到 JupyterLab,尤其是对于那些依赖于没有 JupyterLab 等效项的自定义笔记本扩展的用户,您可以始终坚持使用传统的笔记本服务器 (jupyter notebook)

# the default with JupyterHub 1.x
singleuser:
  extraEnv:
    JUPYTERHUB_SINGLEUSER_APP: "notebook.notebookapp.NotebookApp"

这将启动与以前完全相同的服务器和 UI。

如果您安装了 nbclassic 包,您也可以默认使用经典 UI,在新的服务器上运行:这可能是支持经典和新环境中用户的最佳方法。

singleuser:
  defaultUrl: /tree/
  extraEnv:
    JUPYTERHUB_SINGLEUSER_APP: "jupyter_server.serverapp.ServerApp"

替代界面#

还有更多 Jupyter 服务器扩展提供替代的 UI 选择,这些选择可与 JupyterHub 一起使用。

例如,retrolab 是一个不同的笔记本界面,基于 JupyterLab 构建,但对于来自经典 Jupyter UI 的用户来说可能更舒适。

要安装此类扩展

  1. 在用户容器镜像中安装该包 (pip install retrolabconda install retrolab)

  2. 配置默认 URL,并确保使用 ServerApp

singleuser:
  defaultUrl: /retro/
  extraEnv:
    JUPYTERHUB_SINGLEUSER_APP: "jupyter_server.serverapp.ServerApp"

自定义现有 Docker 镜像#

如果您在镜像中缺少希望所有用户都拥有的内容,建议您在 jupyter/docker-stacks 中的现有 Docker 镜像之上构建一个新镜像。

以下是一个基于minimal-notebook 镜像的 Dockerfile 示例。此文件可以构建为 Docker 镜像,并推送到 镜像注册表,最后在 config.yaml 中配置,供 Helm 图表使用。

FROM jupyter/minimal-notebook:latest
# Replace `latest` with an image tag from to ensure reproducible builds:
# https://hub.docker.com/r/jupyter/minimal-notebook/tags/
# Inspect the Dockerfile at:
# https://github.com/jupyter/docker-stacks/tree/HEAD/minimal-notebook/Dockerfile

# install additional package...
RUN pip install --no-cache-dir astropy

# set the default command of the image,
# if you want to launch more complex startup than the default `juptyerhub-singleuser`.
# To launch an image's custom CMD instead of the default `jupyterhub-singleuser`
# set `singleuser.cmd: null` in your config.yaml.

注意

如果您使用的是私有镜像仓库,您可能需要设置镜像凭据。有关此的更多详细信息,请参见:ref:helm-chart-configuration-reference

设置环境变量#

影响用户环境的一种方法是设置环境变量。虽然您可以在构建自己的 Docker 镜像时在其中设置它们,但通常通过在config.yaml中提供的值配置您的 Helm 图表更容易。

要进行设置,请编辑您的config.yaml应用更改。例如,此代码片段将环境变量EDITOR设置为值vim

singleuser:
  extraEnv:
    EDITOR: "vim"

您可以在config.yaml文件中设置任意数量的静态环境变量。

用户可以通过多种方式在代码中读取环境变量。例如,在 Python 中,以下代码读取环境变量的值

import os
my_value = os.environ["MY_ENVIRONMENT_VARIABLE"]

关于用户存储和向其中添加文件#

了解用户存储的设置方式至关重要。默认情况下,每个用户将在硬盘驱动器上获得 10GB 的空间,该空间将在其服务器重启之间持续存在。此硬盘驱动器将被挂载到其主目录。实际上,这意味着用户写入主目录 (/home/jovyan) 的所有内容都将保留,而其他所有内容将在服务器重启之间重置。

服务器可以通过剔除关闭。默认情况下,JupyterHub 的剔除服务配置为剔除已闲置一小时的用户服务器。请注意,JupyterLab 会自动保存文件,只要文件在用户的主目录中,就不会丢失任何工作。

注意

在 Kubernetes 中,持久卷 (PV) 代表硬盘驱动器。KubeSpawner 将创建一个持久卷声明,该声明从云请求 PV。默认情况下,删除 PVC 将导致云删除 PV。

Docker 镜像的 $HOME 目录将对用户隐藏。要使这些内容对用户可见,您必须预先填充用户的文件系统。为此,您将在config.yaml中包含每次用户启动服务器时运行的命令。以下模式可用于config.yaml

singleuser:
  lifecycleHooks:
    postStart:
      exec:
        command: ["cp", "-a", "src", "target"]

命令的每个元素都需要在列表中作为单独的项目。请注意,此命令将在用户正在运行的容器的$HOME位置运行,这意味着将文件相对于./放置的命令将导致用户在其主目录中看到这些文件。您可以使用wget之类的命令将文件放置在您喜欢的位置。

填充笔记本用户主目录的一种简单方法是将所需文件添加到容器的/tmp目录,然后使用postStart钩子将它们复制到/home/jovyan。此示例显示了使用多个命令。

singleuser:
  lifecycleHooks:
    postStart:
      exec:
        command:
          - "sh"
          - "-c"
          - >
            cp -r /tmp/foo /home/jovyan;
            cp -r /tmp/bar /home/jovyan

请记住,每次用户启动服务器时都会运行命令。因此,我们建议使用nbgitpuller将您的用户文件夹与 git 存储库同步。

使用nbgitpuller同步文件夹#

我们建议使用工具nbgitpuller在每次用户启动服务器时将用户文件系统中的文件夹与git存储库同步。此同步也可以通过让用户访问类似https://your-domain.com/hub/user-redirect/git-pull?repo=https://github.com/data-8/materials-fa18的链接来触发(例如,作为替代启动 URL)。

要使用 nbgitpuller,首先确保您已在 Docker 镜像中安装它。完成此操作后,您就可以从 JupyterHub 内部访问 nbgitpuller CLI。您可以使用以下配置在 postStart 钩子中运行它

singleuser:
  lifecycleHooks:
    postStart:
      exec:
        command:
          [
            "gitpuller",
            "https://github.com/data-8/materials-fa17",
            "master",
            "materials-fa",
          ]

每次用户登录时,这将把存储库的主分支同步到名为 $HOME/materials-fa 的文件夹。有关使用此工具的更多信息,请参阅nbgitpuller 文档

警告

如果用户的存储库自上次同步以来发生了更改,nbgitpuller 将尝试自动解决合并冲突。在生产环境中使用此工具之前,您应该熟悉nbgitpuller 合并行为

允许用户为笔记本创建自己的 conda 环境#

有时您希望用户能够创建自己的 conda 环境。默认情况下,在 JupyterHub 会话中创建的任何环境都不会跨会话持久化。要解决此问题,请执行以下步骤

  1. 确保在根环境中安装了 nb_conda_kernels 包(例如,请参阅使用 repo2docker 构建 Docker 镜像)。

  2. 配置 Anaconda 将用户环境安装到 $HOME 内的文件夹中。

    在所有用户的 home 文件夹中创建一个名为 .condarc 的文件,并确保以下行在其中

    envs_dirs:
      - /home/jovyan/my-conda-envs/
    

上面的文本将导致 Anaconda 将新环境安装到此文件夹,该文件夹将在会话之间持久化。

这些环境应该在笔记本中使用,因此一个典型的用例

  1. 创建一个至少包含一个内核的环境,例如,对于 Python,它是 conda create -n myenv ipykernel scipy

  2. 现在此环境应该在内核列表中可用

使用多个配置文件让用户选择他们的环境#

您可以为多个用户环境创建配置,并让用户在登录到 JupyterHub 后从这些配置中进行选择。这可以通过创建多个**配置文件**来完成,每个配置文件都附加有一组配置选项,这些选项会覆盖您的 JupyterHub 的默认配置(在您的 Helm Chart 中指定)。这可以用于让用户在多个 Docker 镜像之间进行选择,选择他们希望其作业运行的硬件,或配置默认界面,例如 Jupyter Lab 与 RStudio。

每个配置都是KubeSpawner的一组选项,它定义了 Kubernetes 如何启动新的用户服务器 pod。传递给 profileList 配置的任何配置选项都将覆盖 KubeSpawner 中的默认值(或您在 helm 图表中其他地方添加的任何配置)。

配置文件存储在 singleuser.profileList 下,并定义为具有特定配置选项的配置文件列表。以下是一个示例

singleuser:
  profileList:
    - display_name: "Name to be displayed to users"
      description: "Longer description for users."
      # Configuration unique to this profile
      kubespawner_override:
        your_config: "Your value"
      # Defines the default profile - only use for one profile
      default: true

上面的配置将在用户启动新服务器时显示一个包含有关此配置文件信息的屏幕。

以下是一个使用四个配置文件的示例,让用户选择他们想要使用的环境。

singleuser:
  # Defines the default image
  image:
    name: jupyter/minimal-notebook
    tag: 2343e33dec46
  profileList:
    - display_name: "Minimal environment"
      description: "To avoid too much bells and whistles: Python."
      default: true
    - display_name: "Datascience environment"
      description: "If you want the additional bells and whistles: Python, R, and Julia."
      kubespawner_override:
        image: jupyter/datascience-notebook:2343e33dec46
    - display_name: "Spark environment"
      description: "The Jupyter Stacks spark image!"
      kubespawner_override:
        image: jupyter/all-spark-notebook:2343e33dec46
    - display_name: "Learning Data Science"
      description: "Datascience Environment with Sample Notebooks"
      kubespawner_override:
        image: jupyter/datascience-notebook:2343e33dec46
        lifecycle_hooks:
          postStart:
            exec:
              command:
                - "sh"
                - "-c"
                - >
                  gitpuller https://github.com/data-8/materials-fa17 master materials-fa;

这允许用户从三个配置文件中进行选择,每个配置文件都有自己的环境(由上面的配置中的每个 Docker 镜像定义)。

上面的示例中的“学习数据科学”环境覆盖了 postStart 生命周期钩子。请注意,在使用 kubespawner_override 时,值必须符合KubeSpawner 配置的格式。例如,在覆盖 kubespawner_override 中的生命周期钩子时,配置用于 lifecycle_hooks(snake_case)而不是 lifecycleHooks(camelCase),这是它在 singleuser 配置部分下直接使用的方式。可以在此 github 问题中找到对此的进一步解释。

用户相关的配置文件选项#

还可以根据用户配置向用户显示的配置文件选择。您可以通过定义一个自定义的**预启动钩子**来完成此操作,该钩子根据用户身份填充配置文件列表。有关此工作原理的一些示例,请参阅此讨论帖子

注意

您还可以控制用于配置文件选择页面的 HTML,方法是使用 Kubespawner profile_form_template 配置。有关更多信息,请参阅Kubespawner 配置参考

设置启动命令#

最终,单用户服务器应该启动 jupyterhub-singleuser 命令。但是,镜像可能具有执行此操作的自定义 CMD,并包含一些准备步骤、添加额外的命令行参数或启动自定义包装器命令等。

注意

如果您的镜像在启动时有环境准备工作,最好在镜像的 ENTRYPOINT 中完成,而不是在 CMD 中完成,这样覆盖命令就不会跳过您的准备工作。

默认情况下,zero-to-jupyterhub 将启动 jupyterhub-singleuser 命令。如果您有一个镜像(例如 jupyter/scipy-notebook 和其他 Jupyter Docker 堆栈)定义了包含启动自定义设置并最终启动 jupyterhub-singleuser 的 CMD,您可以选择通过设置来启动镜像的默认 CMD。

singleuser:
  cmd: null

或者,您可以将显式自定义命令指定为字符串或字符串列表。

singleuser:
  cmd:
    - /usr/local/bin/custom-command
    - "--flag"
    - "--other-flag"

注意

Docker 有 ENTRYPOINTCMD,k8s 称之为 commandargs。zero-to-jupyterhub 始终尊重镜像的 ENTRYPOINT,设置 singleuser.cmd 仅覆盖 CMD。

禁用特定的 JupyterLab 扩展#

有时您希望在 JupyterHub 上默认情况下暂时禁用 JupyterLab 扩展,而无需重新构建 Docker 镜像。这可以通过 singleuser.extraFiles 和 JupyterLab 的 page_config.json 很容易实现。

JupyterLab 的 page_config.json 允许您通过在运行 jupyter --paths 时列出的任何目录中的 labconfig 目录下放置 JSON 文件来设置页面配置。我们只需使用 singleuser.extraFiles 来提供此文件!

singleuser:
  extraFiles:
    lab-config:
      mountPath: /etc/jupyter/labconfig/page_config.json
      data:
        disabledExtensions:
          jupyterlab-link-share: true

这将禁用 link-share labextension,无论是在 JupyterLab 还是 RetroLab 中。您可以使用 jupyter labextension list 找到扩展的名称及其当前状态。

jovyan@jupyter-yuvipanda:~$ jupyter labextension list
JupyterLab v3.2.4
/opt/conda/share/jupyter/labextensions
        jupyterlab-plotly v5.4.0 enabled OK
        jupyter-matplotlib v0.9.0 enabled OK
        jupyterlab-link-share v0.2.4 disabled OK (python, jupyterlab-link-share)
        @jupyter-widgets/jupyterlab-manager v3.0.1 enabled OK (python, jupyterlab_widgets)
        @jupyter-server/resource-usage v0.6.0 enabled OK (python, jupyter-resource-usage)
        @retrolab/lab-extension v0.3.13 enabled OK

如果同一个镜像在多个 Hub 之间共享,并且您希望某些 Hub 禁用某些扩展,这将非常有用。