自定义用户资源#

注意

有关您可以配置的所有 Helm chart 选项的列表,请参阅配置参考

用户资源包括 JupyterHub 提供给用户的 CPU、RAM 和存储。其中大部分可以通过修改 Helm chart 来控制。有关如何将您的修改部署到 JupyterHub 的信息,请参阅应用配置更改

由于 JupyterHub 可以为许多不同类型的用户提供服务,JupyterHub 的管理者和管理员必须能够灵活地**分配用户资源**,如内存或计算资源。例如,Hub 可能既要服务于有大量资源需求的高级用户,也要服务于资源需求更初级的入门用户。自定义 Hub 资源以满足这两个用户群体的能力,可以改善所有 Hub 用户的体验。

设置用户内存和 CPU 的保证/限制#

JupyterHub 上的每个用户都会获得一部分内存和 CPU 以供使用。有两种方式可以指定用户可使用的资源量:资源*保证*(guarantees)和资源*限制*(limits)。

资源*保证*意味着所有用户在任何时候都*至少*拥有这些可用资源,但如果系统中有更多可用资源,他们也可能被分配更多。例如,如果用户被*保证*拥有 1G 的 RAM,那么在其他用户未使用这些资源的情况下,用户实际上可以使用超过 1G 的 RAM。

资源*限制*则对可用资源设置了一个硬性上限。在上面的例子中,如果设置了 1G 的内存限制,那将意味着无论机器上其他资源的使用情况如何,用户最多只能使用 1G 的 RAM。

默认情况下,每个用户被*保证* 1G 的 RAM。所有用户*至少*拥有 1G,但如果有可用资源,他们实际上可以使用更多。您可以通过修改 config.yaml 文件,轻松更改这些资源的数量,以及它们是*保证*还是*限制*。这通过以下结构完成。

singleuser:
  memory:
    limit: 1G
    guarantee: 1G

这会将内存限制和保证都设置为 1G。Kubernetes 将确保每个用户始终能够访问 1G 的 RAM,而请求更多 RAM 的操作将会失败(您的内核通常会崩溃)。您可以将限制设置得高于保证值,以允许一些用户在非常短的时间内使用更多的 RAM(例如,在运行一个消耗大量内存的短暂函数时)。

同样,您可以如下限制 CPU

singleuser:
  cpu:
    limit: .5
    guarantee: .5

这将限制您的用户最多使用 0.5 个 CPU(即半个 CPU 核心),并同时为他们保证相同的数量。

注意

修改您的 config.yaml 文件后,请记得应用更改

设置用户 GPU 的保证/限制#

可以为您的用户分配 GPU。这对于深度学习等可以利用 GPU 的较重工作负载非常有用。

例如,要创建一个分配一个 NVIDIA GPU 的配置文件

singleuser:
  profileList:
    - display_name: "GPU Server"
      description: "Spawns a notebook server with access to a GPU"
      kubespawner_override:
        extra_resource_limits:
          nvidia.com/gpu: "1"

这假设您的 Kubernetes 节点中至少有一个挂载了兼容的 GPU。具体操作方法因您的基础架构提供商而异。以下是一些帮助您入门的链接:

您还需要按照此处的说明部署 k8s-device-plugin。

要检查您的 GPU 是否可由 Kubernetes 调度,您可以运行以下命令

kubectl get nodes -o=custom-columns=NAME:.metadata.name,GPUs:.status.capacity.'nvidia\.com/gpu'

修改用户共享内存大小#

增加运行深度学习等工作负载的 pod 的共享内存(SHM)分配也是有益的。这是像 PyTorch 的 DataLoader 这样的函数正常运行所必需的。

以下配置将通过在 /dev/shm 挂载一个 tmpfs(ramdisk)来增加 SHM 分配,取代默认的 64MB 分配。

singleuser:
  storage:
    extraVolumes:
      - name: shm-volume
        emptyDir:
          medium: Memory
    extraVolumeMounts:
      - name: shm-volume
        mountPath: /dev/shm

shm-volume 将在用户的 pod 创建时创建,并在 pod 销毁后销毁。

关于 SHM 分配的一些重要说明

  • pod 的 SHM 使用量将计入其内存限制

  • 当超过内存限制时,pod 将被驱逐

修改用户存储类型和大小#

有关如何修改用户可访问的存储类型和大小的信息,请参阅自定义用户存储

扩展和收缩集群的大小#

您可以轻松地扩大或缩小集群的规模,以满足使用需求或在集群不使用时节省成本。当您有可预测的使用高峰时,这特别有用。例如,如果您正在组织并举办一个研讨会,调整集群大小可以让您在活动前节省成本并准备好 JupyterHub。例如

  • 研讨会前一周:您可以创建集群,完成所有设置,然后将集群大小调整为零个节点以节省成本。

  • 研讨会当天:您可以将集群扩展到适合研讨会的规模。这个工作流程还能帮助您避免在研讨会当天手忙脚乱地设置集群和 JupyterHub。

  • 研讨会结束后:可以删除集群。

以下各节介绍了如何在各种云平台上调整集群大小。

Google Cloud Platform#

使用 resize 命令,并通过命令行选项 --num-nodes 提供新的集群大小(即节点数)

gcloud container clusters resize \
    <YOUR-CLUSTER-NAME> \
    --num-nodes <NEW-SIZE> \
    --zone <YOUR-CLUSTER-ZONE>

要显示集群的名称、区域或当前大小,请使用以下命令

gcloud container clusters list

调整集群大小后,由于服务正在添加或移除节点,可能需要几分钟才能报告新的集群大小。您可以使用 kubectl get node 来报告集群中所有节点当前的 Ready/NotReady 状态,从而找到当前“就绪”节点的真实数量。

Microsoft Azure Platform#

使用 scale 命令,并通过命令行选项 --node-count 提供新的集群大小(即节点数)

az aks scale \
    --name <YOUR-CLUSTER-NAME> \
    --node-count <NEW-SIZE> \
    --resource-group <YOUR-RESOURCE-GROUP>

要显示集群的详细信息,请使用以下命令

az aks show --name <YOUR-CLUSTER-NAME> --resource-group <YOUR-RESOURCE-GROUP>

新的集群节点可能需要一些时间才能就绪。您可以使用 kubectl get node 来报告集群中所有节点当前的 Ready/NotReady 状态。

Amazon Web Services Elastic Kubernetes Service (EKS)#

AWS EKS 是亚马逊的一项服务,提供由 AWS 管理的 Kubernetes 控制平面和一套命令行工具 eksctl,用于创建和管理 Kubernetes 集群。这只是使用 AWS 基础设施部署 Kubernetes 的一种方式,但以下内容假设您已经

  1. 在 EKS 上部署了一个 Kubernetes 集群

  2. eksctl 命令行工具已安装并配置为指向您的 EKS 集群。

要使用 eksctl 命令行工具扩展现有的节点组

eksctl scale nodegroup \
  -n <NODEGROUP-NAME> \
  --nodes <DESIRED-NUMBER-OF-NODES>\
  --nodes-max <MAX-NUMBER-OF-NODES>\
  --nodes-min <MIN-NUMBER-OF-NODES>\
  --cluster=<YOUR-CLUSTER-NAME>

如果您已经设置了集群自动伸缩器,您还可以使用 eksctl 命令行工具创建一个自动伸缩的节点组。

eksctl create nodegroup \
  --cluster <YOUR-CLUSTER-NAME> \
  --name <NODEGROUP-NAME> \
  --node-type <EC2-INSTANCE-TYPE(S)> \
  --nodes-max <MAX-NUMBER-OF-NODES>\
  --nodes-min <MIN-NUMBER-OF-NODES>\
  --ssh-access \
  --ssh-public-key <PATH-TO-KEYPAIR-WITH-EKS-PERMISSIONS> \
  --node-zones <OPTIONALLY-SPECIFY-AVAILABILIYT-ZONE-FOR-NODES> \
  --tags "k8s.io/cluster-autoscaler/node-template/taint/<some-taint-key>=<some-taint-value>:<some-taint-effect>, k8s.io/cluster-autoscaler/node-template/label/<some-node-label-key>=<some-node-label-value>,k8s.io/cluster-autoscaler/<YOUR-CLUSTER-NAME>=true,k8s.io/cluster-autoscaler/enabled=true" \
  --node-labels "<some-node-label-key>=<some-node-label-value>,failure-domain.beta.kubernetes.io/zone=<AVAILABILITY-ZONE>,failure-domain.beta.kubernetes.io/region=<AVAILABILITY-REGION>"

必须应用标签 k8s.io/cluster-autoscaler/<YOUR-CLUSTER-NAME>=<any-value-only-key-matters>k8s.io/cluster-autoscaler/enabled=true,AWS 集群自动伸缩器才能对节点组进行自动伸缩。

对于将用作 nodeSelector 的每个 node-labels,都必须添加一个相应的 tag;对于形式为 <some-node-label-key>=<some-node-label-value>node-labels,这些标签的形式应为 k8s.io/cluster-autoscaler/node-template/label/<some-node-label-key>=<some-node-label-value>

也可以使用形式为 k8s.io/cluster-autoscaler/node-template/taint/<some-taint-key>=<some-taint-value>:<some-taint-effect> 的标签为节点组中的节点应用污点(Taints)。

最后,可以使用 node-labels 设置 AWS 区域(例如 eu-west-1)和可用区(例如 eu-west-1a):failure-domain.beta.kubernetes.io/region=<AVAILABILITY-REGION>failure-domain.beta.kubernetes.io/zone=<AVAILABILITY-ZONE>;和/或使用 --node-zones 标志。当 singleUser pod 可能被调度到不同可用区的节点时,设置可用区非常有用;在使用任何不支持跨可用区挂载的 persistentVolume 存储后端(包括 AWS EKS 中的默认 gp2 存储)时,这种情况是有问题的。在这些情况下,PV 是在用户 pod 首次被调度的节点的可用区中创建的,如果将来同一个用户 pod 被调度到不同的可用区,就会发生错误。通过控制 nodegroups 部署的区域和/或在 values.yaml 中引用的自定义 StorageClass 中为卷指定可用区,可以避免这种情况。