所用工具#

JupyterHub 旨在与云计算和容器技术领域的许多工具相连接。本页将更详细地描述这些工具,以提供更多背景信息。

云计算提供商#

这是实际运行计算任务的实体。通常指公司、大学服务器或其他托管可远程访问的计算资源的组织。JupyterHub 将在这些计算资源上运行,这意味着如果用户与您的 JupyterHub 交互,他们也将在这些资源上进行操作。

它们提供以下内容:

  • 计算能力

  • 磁盘空间

  • 网络(内部和外部)

  • 创建、调整大小和删除集群

其中一些组织是公司(例如,Google),但 JupyterHub 也能很好地与大学集群或自定义集群部署配合使用。对于本材料,任何安装了 Kubernetes 的集群都可以与 JupyterHub 一起工作。

有关在云提供商处设置账户服务的更多信息,请参见此处

容器技术#

容器技术本质上是将运行某个软件所需的所有组件打包在一起。实现这一目标的方法有很多,但我们将重点关注一种名为 Docker 的技术。以下是 Docker 的主要概念:

容器镜像#

容器镜像包含运行代码所需的依赖项。这包括一切,甚至操作系统本身。它还包括代码运行所需的文件系统等,其中可能包含数据等。容器也是可移植的,这意味着您可以在几乎任何机器上精确地重现运行代码的计算环境。

在 Docker 中,镜像被描述为层,即依赖关系的层。例如,假设您想构建一个运行 scikit-learn 的容器。它依赖于 Python,所以您有两个层:一个用于 Python,另一个继承 Python 层并添加 scikit-learn 这个额外的部分。此外,那个基础 Python 层需要一个操作系统来运行,所以现在您有三个层:ubuntu -> python -> scikit-learn。您明白了吧。这样做的好处是,您可以在不同镜像之间共享基础层。这意味着,如果您有许多不同的镜像都需要 ubuntu,您就不需要保存许多 ubuntu 的副本。

镜像可以从许多东西创建。如果您使用 Docker,基本方法是使用 Dockerfile。这本质上是一系列指令,告诉 Docker 如何创建镜像。它可能会告诉 Docker 您想在镜像中包含哪些基础层,以及镜像中需要的其他一些依赖项。可以把它想象成一个告诉 Docker 如何创建镜像的食谱。

容器#

您可以“运行”一个容器镜像,它会为您创建一个容器。容器是容器镜像的一个具体实例化。这意味着它真实存在于计算机上。它是一个自包含的计算环境,根据容器镜像内的层构建而成。然而,因为它现在正在计算机上运行,它可以做其他有用的事情,比如与其他 Docker 容器通信或通过互联网进行交流。

Kubernetes#

Kubernetes 是一种在云基础设施上运行的服务。它为您的集群部署机制提供了一个单一的接触点,并允许用户指定他们需要的计算需求(例如,需要多少台机器、每台机器多少个 CPU、多少 RAM)。然后,它处理集群上的资源,并确保这些资源始终可用。如果出现问题,Kubernetes 会尝试自动将其恢复。

Kubernetes 只能管理它被赋予的计算资源。这意味着它通常不能自行创建新资源(磁盘空间除外)。

以下各节描述了与 JupyterHub 最相关的 Kubernetes 对象。

进程#

进程是在机器上运行的任何程序。例如,Jupyter Notebook 会创建几个进程来处理代码的执行和在浏览器中的显示。这在技术上不是一个 Kubernetes 对象,因为任何计算机上都有进程在运行,但 Kubernetes 会跟踪正在运行的进程,以确保在需要时它们能保持运行。

Pod#

Pod 本质上是一组一起运行的一个或多个容器的集合。您可以将它们视为将多个容器组合在一起以实现某个目标的方式。

例如,假设您想创建一个对全世界开放的 Web 服务器,但您也需要身份验证,以便只有特定用户组可以访问。您可以使用一个包含两个容器的 Pod。

  • 一个用于身份验证。它的容器镜像中会指定类似 Apache 的东西,并连接到外部世界。

  • 另一个从身份验证容器接收信息,并对其进行一些高级处理(也许它运行一个 Python 进程)。

这很有用,因为它让您可以将您想要运行的服务的组件进行划分,这使得管理更容易,并保持系统更稳定。

有关 Pod 的更多信息,请参阅 Kubernetes 关于 Pod 的文档

Deployment(部署)#

Deployment 是 Kubernetes 上 Pod 的集合。它让 Kubernetes 确切地知道哪些容器和哪些机器需要一直运行。例如,如果您有两个 Pod:一个用于上述的身份验证,另一个用于管理数据库,您可以在一个 Deployment 中同时指定它们。

Kubernetes 将确保这两个 Pod 都处于活动状态,如果其中一个出现故障,它会尝试重新创建它。它通过持续检查 Pod 的当前状态,然后将其与 Deployment 的原始规范进行比较来实现这一点。如果当前状态与 Deployment 规范之间存在差异,Kubernetes 将尝试进行更改,直到当前状态与规范匹配。

有关 Deployment 的更多信息,请参阅 Kubernetes 关于 Deployment 的文档

注意

用户通常不直接“创建”Deployment,而是通过发送给 Kubernetes 的一组指令来生成它们。我们将在“Helm”一节中介绍这一点。

Service(服务)#

Service 是一种引用 Deployment 的稳定方式。Kubernetes 的核心是智能地处理动态且快速变化的计算环境。这意味着运行您的 Pod 的虚拟机可能会改变,IP 地址会不同等等。但是您不希望每次发生这种情况时都必须重新定位自己。Kubernetes Service 在后端跟踪所有这些变化,并提供一个单一的地址来管理您的 Deployment。

有关 Service 的更多信息,请参阅 Kubernetes 关于 Service 的文档

Namespace(命名空间)#

最后,Namespace 定义了 Kubernetes 中对象的集合。它通常是我们迄今为止讨论过的分组中“最高级别”的。例如,一个 Namespace 可以是运行在 JupyterHub 上的一个班级。

有关 Namespace 的更多信息,请参阅 Kubernetes 关于 Namespace 的文档

Persistent Volume Claim(持久卷声明)#

Persistent Volume Claim 是一种拥有持久存储的方式,而无需绑定到某一台特定的计算机或机器上。Kubernetes 的核心在于灵活性,这意味着我们不希望仅仅因为我们的文件已经存在于某个操作系统上,就将自己锁定在该操作系统上。Persistent Volume Claim 通过知道如何在不同磁盘类型(例如,AWS 与 Google 磁盘)之间转换文件来帮助解决这个问题。

有关 Persistent Volume Claim 的更多信息,请参阅 Kubernetes 关于持久卷的文档

Helm#

Helm 是一种使用标准模板指定 Kubernetes 对象的方式。

Chart#

Helm 通过结构化信息的模板来控制 Kubernetes,这些模板指定了一些计算需求。这些模板被称为“Chart”或“Helm Chart”。它们包含 Kubernetes 生成以下对象所需的所有必要信息:

  • 一个 Deployment 对象

  • 一个 Service 对象

  • 一个用于 Deployment 的 Persistent Volume 对象

  • 上述组件的集合

它们可以安装到一个 Namespace 中,这会使 Kubernetes 开始将上述对象部署到该 Namespace 中。

Chart 既有名称也有版本,这意味着您可以轻松地更新它们并基于它们进行构建。有社区维护的 Chart可供使用,在本指南中,我们使用一个 Chart 来安装和升级 JupyterHub。在我们的例子中,Helm Chart 是一个名为 config.yaml 的文件。

Release(发布)#

Release 基本上是 Helm Chart 在特定 Namespace 中的一个具体实例化。如果您想升级您的 Kubernetes 部署(例如,通过更改每个用户应获得的 RAM 大小),您可以更改 Helm Chart,然后将其重新部署到您的 Kubernetes 集群中。这将生成一个新版本的 Release。

JupyterHub#

JupyterHub 是一种利用上述组件来提供用户可以远程访问的计算环境的方式。它作为两个 Kubernetes Deployment 存在,即 Proxy 和 Hub,每个都有一个 Pod。每个 Deployment 完成一些任务,这些任务共同构成了 JupyterHub。最后,JupyterHub 的输出是一个用户 Pod,它指定了单个用户将操作的计算环境。所以,JupyterHub 本质上是以下各项的集合:

  • 包含 JupyterHub 机制的 Pod

  • 一群不断被创建或销毁的用户 Pod

下面我们将描述主要的 JupyterHub Pod。

Proxy Pod#

这是面向用户的 Pod。它提供了人们访问 JupyterHub 的 IP 地址。当一个新用户访问此 Pod 时,它将决定是:

  • 将该用户发送到 Hub Pod,Hub Pod 将为该用户创建一个容器,或者

  • 如果该用户的容器已经存在,则直接将他们发送到该容器。

关于用户身份的信息以 Cookie 的形式存储在用户的计算机上。Proxy Pod 就是通过这种方式知道用户是否已经有一个正在运行的容器。

Hub Pod#

接收来自 Proxy Pod 的流量。它有 3 个主要运行的进程:

  1. 一个身份验证器,用于验证用户账户。它还包含一个进程。

  2. 一个“KubeSpawner”,它与 Kubernetes API 通信,并告诉它在用户 Pod 不存在时为其生成一个。KubeSpawner 会告诉 Kubernetes 为新用户创建一个 Pod,然后它会告诉 Proxy Pod 该用户的 Pod 已经创建。

  3. 一个管理面板,其中包含有关谁创建了 Pod 以及集群上的使用情况等信息。