自定义用户环境#
此页面包含用于增强用户体验的常见方法的说明。有关所有可配置 Helm chart 选项的列表,请参阅配置参考。
用户环境是用户登录 JupyterHub 时存在的一组软件包、环境变量和各种文件。用户还可能看到提供执行专门任务界面的不同工具,例如 JupyterLab、RStudio、RISE 等。
从 Dockerfile 构建的 Docker 镜像将为您提供给用户的环境奠定基础。例如,该镜像将决定哪些 Linux 软件 (curl, vim ...)、编程语言 (Julia, Python, R, ...) 和开发环境 (JupyterLab, RStudio, ...) 可供使用。
要开始自定义用户环境,请参阅以下主题。
选择并使用现有的 Docker 镜像#
此 chart 使用一个最小化的默认单用户镜像,用于快速测试。您将需要为实际使用选择不同的镜像或构建自己的镜像。
Jupyter 项目维护着 jupyter/docker-stacks 仓库,其中包含可直接使用的 Docker 镜像。每个镜像都包含一组常用的科学和数据科学库及工具。他们还提供了关于如何选择合适镜像的优秀文档。
例如,要使用包含数据科学有用工具和库的 datascience-notebook 镜像,请完成以下步骤:
修改您的
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
,例如特定的 commit。避免使用latest
,因为当镜像的新版本发布时,可能会给用户带来几分钟的延迟、困惑或故障。按照应用更改中列出的说明应用更改。
如果您配置了 prePuller.hook.enabled,集群中的所有节点将在 Hub 升级之前拉取镜像,以便用户使用该镜像。镜像拉取可能需要几分钟才能完成,具体取决于镜像的大小。
如果您已登录,请从 JupyterHub 控制面板重新启动您的服务器。
注意
如果您希望用户从多个 Docker 镜像中选择环境,请参阅使用多个配置文件让用户选择其环境。
选择用户界面#
JupyterLab 是 Jupyter 的新用户界面,旨在取代经典的 notebook 用户界面 (UI)。如果两者都已安装,用户已经可以在 URL 中互换 /tree
和 /lab
来在经典 UI 和 JupyterLab 之间切换。使用 JupyterHub 1.x 及更早版本的部署默认使用经典 UI,而 JupyterHub 2.0 则将 JupyterLab 作为默认设置。
要选择默认启动的用户界面,需要设置两个自定义项:
首选的默认用户界面 (UI)
要启动的服务器程序
主要有两种 Jupyter 服务器实现(大多数部署不会看到差异,但对于某些服务器扩展可能会出现问题。如果不确定,新应用程序应选择 jupyter_server
。):
现代的
jupyter server
,当您使用jupyter lab
或其他近期 Jupyter 应用程序时启动,以及“经典”的旧版 notebook 服务器 (
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"
或经典 notebook 服务器:
# 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 chart 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
包(可通过 pip
或 conda
安装)才能使其工作。jupyter/docker-stacks 仓库中的所有镜像都预装了它。
默认使用经典 notebook#
注意
这是 JupyterHub 1.x 和 helm chart 1.x 中的默认设置。
如果您还没准备好升级到 JupyterLab,特别是对于那些依赖于在 JupyterLab 中没有等效品的自定义 notebook 扩展的用户,您可以始终坚持使用旧版的 notebook 服务器 (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"
替代界面#
还有更多提供备选 UI 选择的 Jupyter 服务器扩展,可以与 JupyterHub 一起使用。
例如,retrolab 是一个不同的 notebook 界面,它构建在 JupyterLab 之上,但对于来自经典 Jupyter UI 的用户来说可能更舒适。
要安装这样的扩展:
在您的用户容器镜像中安装该软件包(
pip install retrolab
或conda install retrolab
)。配置默认 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 chart 使用。
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 chart 通常更容易。
要进行此设置,请编辑您的 config.yaml 并应用更改。例如,此代码片段将环境变量 EDITOR
设置为值 vim
:
singleuser:
extraEnv:
EDITOR: "vim"
您可以在 config.yaml 文件中设置任意数量的静态环境变量。
用户可以通过各种方式在他们的代码中读取环境变量。例如,在 Python 中,以下代码读取一个环境变量的值:
import os
my_value = os.environ["MY_ENVIRONMENT_VARIABLE"]
关于用户存储及向其中添加文件#
理解用户存储的基本设置方式非常重要。默认情况下,每个用户将获得一个 10GB 的硬盘空间,该空间在其服务器重启之间保持持久。这个硬盘将被挂载到他们的主目录。实际上,这意味着用户写入主目录(/home/jovyan
)的所有内容都将保留下来,而其他所有内容都将在服务器重启之间被重置。
服务器可以通过淘汰(culling)来关闭。默认情况下,JupyterHub 的淘汰服务配置为淘汰已闲置一小时的用户服务器。请注意,JupyterLab 会自动保存文件,只要文件位于用户的主目录内,工作就不会丢失。
注意
在 Kubernetes 中,持久卷(PersistentVolume) (PV) 代表硬盘。KubeSpawner 将创建一个持久卷声明(PersistentVolumeClaim),向云端请求一个 PV。默认情况下,删除 PVC 将导致云端删除 PV。
Docker 镜像的 $HOME 目录将对用户隐藏。为了让用户看到这些内容,您必须预填充用户的文件系统。为此,您可以在 config.yaml
中包含一些命令,这些命令将在每次用户启动服务器时运行。可以在 config.yaml 中使用以下模式:
singleuser:
lifecycleHooks:
postStart:
exec:
command: ["cp", "-a", "src", "target"]
命令的每个元素都需要是列表中的一个单独项。请注意,此命令将从用户正在运行的容器的 $HOME
位置运行,这意味着相对于 ./
放置文件的命令将导致用户在其主目录中看到这些文件。您可以使用像 wget
这样的命令将文件放置到您喜欢的位置。
填充 notebook 用户主目录的一个简单方法是将所需文件添加到容器的 /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",
]
这将在每次用户登录时,将仓库的 master 分支同步到名为 $HOME/materials-fa
的文件夹中。有关使用此工具的更多信息,请参阅 nbgitpuller 文档。
警告
如果自上次同步以来,您的用户仓库发生了变化,nbgitpuller
将尝试自动解决合并冲突。在生产环境中使用该工具之前,您应该熟悉 nbgitpuller 的合并行为。
允许用户为 notebook 创建自己的 conda
环境#
有时您希望用户能够创建自己的 conda
环境。默认情况下,在 JupyterHub会话中创建的任何环境都不会在会话之间持久存在。要解决此问题,请执行以下步骤:
确保在根环境中安装了
nb_conda_kernels
包(例如,参见使用 repo2docker 构建 Docker 镜像)配置 Anaconda 将用户环境安装到
$HOME
内的文件夹中。为所有用户在主文件夹中创建一个名为
.condarc
的文件,并确保其中包含以下几行:envs_dirs: - /home/jovyan/my-conda-envs/
上述文本将使 Anaconda 将新环境安装到此文件夹,该文件夹将在会话之间保持持久。
这些环境应该在 notebook 中使用,因此一个典型的用例是:
创建一个至少包含一个内核的环境,例如,对于 Python,命令是
conda create -n myenv ipykernel scipy
现在这个环境应该可以在内核列表中找到
使用多个配置文件让用户选择其环境#
您可以为多个用户环境创建配置,并让用户在登录到您的 JupyterHub 后从中进行选择。这是通过创建多个配置文件(profiles)来实现的,每个配置文件都附加了一组配置选项,这些选项会覆盖您的 JupyterHub 的默认配置(在您的 Helm Chart 中指定)。这可以用来让用户在多个 Docker 镜像之间进行选择,选择他们希望其作业运行的硬件,或者配置默认界面,如 Jupyter Lab 与 RStudio。
每个配置都是一组用于 KubeSpawner 的选项,它定义了 Kubernetes 应如何启动新的用户服务器 pod。传递给 profileList
配置的任何配置选项都将覆盖 KubeSpawner 中的默认值(或您在 helm chart 其他地方添加的任何配置)。
配置文件存储在 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
(蛇形命名法),而不是 lifecycleHooks
(驼峰命名法),后者是直接在 singleuser
配置部分下使用的。关于这一点的进一步解释可以在这个 github issue 中找到。
依赖于用户的配置文件选项#
根据用户身份配置向用户呈现的配置文件选项也是可能的。您可以通过定义一个自定义的 pre-spawn 钩子来做到这一点,该钩子根据用户身份填充配置文件列表。有关其工作原理的一些示例,请参阅这篇 discourse 帖子。
注意
您还可以通过使用 Kubespawner 的 profile_form_template
配置来控制用于配置文件选择页面的 HTML。更多信息请参阅 Kubespawner 配置参考。
设置要启动的命令#
最终,单用户服务器应该启动 jupyterhub-singleuser
命令。但是,镜像可能会有一个自定义的 CMD 来执行此操作,其中可能包含一些准备步骤、添加额外的命令行参数或启动一个自定义的包装命令等。
注意
如果您的镜像在启动时有环境准备步骤,最好在镜像的 ENTRYPOINT 中完成,而不是在 CMD 中,这样覆盖命令时就不会跳过您的准备步骤。
默认情况下,zero-to-jupyterhub 将启动 jupyterhub-singleuser
命令。如果您有一个镜像(例如 jupyter/scipy-notebook
和其他 Jupyter Docker stacks)定义了一个带有启动自定义并最终启动 jupyterhub-singleuser
的 CMD,您可以选择启动镜像的默认 CMD,方法是设置:
singleuser:
cmd: null
或者,您可以将明确的自定义命令指定为字符串或字符串列表:
singleuser:
cmd:
- /usr/local/bin/custom-command
- "--flag"
- "--other-flag"
注意
Docker 有 ENTRYPOINT
和 CMD
,k8s 称之为 command
和 args
。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 禁用某些扩展,这将非常有用。