Kubeflow Notebooks:ML 实验变得更容易 - 第 2 部分
机器学习是一个非常迭代的过程,您可能需要做大量的实验。在本文中,我将向您介绍 Kubeflow Notebooks,这是一种在 Kubernetes 集群中运行开发环境的方法,以及如何为您自己的用例扩展 Kubeflow Notebooks 的默认功能以及它如何在后台工作。
系列上一篇文章
- Kubeflow:Kubernetes 上的机器学习 - 第 1 部分
在上一篇文章中,我们已经了解了 Kubeflow 和中央仪表板的基础知识。这一次,我们将在此基础上讨论 Kubeflow Notebooks。
Kubeflow 笔记本
Kubeflow Notebooks 提供了一种在 Kubernetes 集群中运行基于 Web 的开发环境的方法,方法是在 Pod 中运行它们。
这种设置有多个优点:
-
可以创建 Notebook 容器并直接在集群中运行,而不是在本地进行
-
您可以使用预配置或自定义映像来创建环境,这样您就可以专注于手头的任务,而不是环境或安装问题
-
您可以通过 Kubeflow Notebooks 轻松利用扩展的强大功能,在本文中,我们还将在后面的文章中了解 Kubeflow 整流罩等
-
对 JupyterLab、RStudio 和 VS Code 的开箱即用支持,但是您可以使用任何其他 IDE
-
最后,Kubeflow 的基于角色的访问控制功能使轻松安全的笔记本共享变得足够容易
创建笔记本服务器
在详细讨论 Kubeflow Notebooks 的任何特定组件之前,让我们先从高层次上了解如何创建 Kubeflow Notebook 服务器并在您的 Notebook 服务器中运行一些示例代码。单个 Kubeflow Notebook 服务器可以包含多个笔记本,您可能希望根据需要在机器学习生命周期的不同阶段拥有多个 Notebook 服务器。
笔记本服务器的结构
使用 UI 创建 Kubeflow Notebook 服务器非常简单,您可以指定:
-
笔记本及其所属工作区的名称。
-
Notebook Server 的 docker 映像,这是我们的容器将运行的映像,您可以将其理解为指定您希望环境包含的内容的一种方式。这也可以根据您的需要进行定制,我们将在本文的专门部分中看到更多相关信息。
-
笔记本服务器尝试请求的 CPU 和 RAM。
-
指定您的笔记本 pod 中是否需要 GPU,Kubeflow 可以通过Kubernetes 文档中所示的限制来实现这一点。
-
要作为 PVC 卷安装在您的主文件夹上的工作区卷。
-
一个或多个数据卷作为 PVC 卷挂载。我们还将更详细地讨论这一点。
-
配置是一种将通用数据(环境变量、卷)注入笔记本的方法。 Kubeflow 基于 Kubernetes PodPreset(现已弃用)创建了 PodDefault 控制器,您可以使用它来实现此目的。您可以创建 PodDefault 清单,这些清单描述了要在创建时注入到 Pod 中的其他运行时要求(即卷、volumeMounts、环境变量)。
-
正如您可能已经猜到的,您还可以为笔记本服务器指定关联和污染配置。
-
笔记本还允许您启用共享内存。如果您使用类似
torch.multiprocessing或torch.Tensor.share_memory_()之类的东西,则它们在很大程度上依赖于共享内存的使用。
现在让我们创建一个笔记本服务器,将图像设置为kubeflownotebookswg/jupyter-tensorflow-full:v1.6.0-rc.1,其中包含 TensorFlow 2.5.3 和其他一些常用库,稍后我们将看到如何自定义这些图像。单击“启动”会使用这些设置创建一个新的笔记本 CRD,您应该很快会看到一个提示,允许您连接到笔记本服务器。
连接到笔记本服务器
运行示例笔记本
让我们首先尝试在 Notebook 服务器中调整一个简单的 TensorFlow 示例,您当然可以运行任何您想要的笔记本。
git clone https://github.com/kubesimplify/kubeflow-series
cd kubeflow-series/2
如果您想知道为什么新机器安装了 Git,那是因为默认的 Kubeflow 映像包含许多您需要预先安装的实用程序。现在您可以尝试调整tensorflow-example.ipynb,其中包含使用 Keras 的 TensorFlow 2 的一些简单模型训练代码。
事实上,您也可以使用 Jupyter Lab Extensions,我们将在后面的文章中讨论 KALE 和 Elyra 等扩展。
使用张量板
在机器学习中,要改进某些东西,您通常需要能够衡量它。 TensorBoard 是一种工具,用于提供机器学习工作流程中所需的测量和可视化。它可以跟踪实验指标,如损失和准确性、可视化模型图、将嵌入投影到低维空间等等。
让我们看一个将 TensorBoard 与 Kubeflow 结合使用的示例。
您现在应该运行tensorboard.ipynb,这是一个 TensorFlow 示例,但您可能已经猜到,您也可以将 TensorBoard 与任何其他框架一起使用。如果您在运行此示例时注意到我们创建了一个logs目录来存储我们的 TensorBoard 日志。
您现在可以创建一个 TensorBoard 实例并使用我们为 Notebook 实例拥有的 PVC 来获取 TensorBoard 日志,在我的例子中,它看起来像这样:
创建张量板
瞧,你有它,TensorBoard 启动并运行,它也会自动从你的训练日志中重新加载。
TensorBoard 主页
创建笔记本服务器时会发生什么?
我们已经创建了一个 Notebook Server,作为下一步,了解 Kubeflow 如何设法创建一个新的 Notebook Server 将非常有帮助。
每当您创建一个新的 Kubeflow Notebook 服务器时,您实际上是在创建一个 Kubernetes StatefulSet。您在 Notebook 服务器中运行的任何代码都运行子 Kubernetes pod。
简而言之,StatefulSet 是一个控制器,可帮助您部署和扩展 Kubernetes pod 组。 StatefulSet 控制器还为每个 Pod 实例实例化和管理 PersistentVolumeClaims,我们将在下一节中详细介绍。当您想要并行运行多个相同类型的 Pod 时,通常使用 StatefulSet,但每个 Pod 都需要具有特定的身份。
Kubeflow 中的笔记本服务器
我认为当你创建一个 notebook 时查看 Kubernetes 事件日志将是一个有趣的练习,它现在应该更有意义,因为你已经知道它是如何工作的。以下是创建笔记本时发生的事件片段:
statefulset/kubeflow-series-part2 create Pod kubeflow-series-part2-0 in StatefulSet kubeflow-series-part2successful
notebook/kubeflow-series-part2 Reissued from statefulset/kubeflow-series-part2: create Pod kubeflow-series-part2-0in StatefulSet kubeflow-series-part2 successful
persistentvolumeclaim/kubeflow-series-part2-volume External provisioner is provisioning volume for claim "kubeflow-user-example-com/kubeflow-series-part2-volume"
persistentvolumeclaim/kubeflow-series-part2-volume waiting for a volume to be created, either by external provisioner "csi.civo.com" or manually created by system administrator
persistentvolumeclaim/kubeflow-series-part2-volume Successfully provisioned volume pvc-a75855d7-4c2d-4479-a61c-e071e3cb8eaa
pod/kubeflow-series-part2-0 Successfully assigned kubeflow-user-example-com/kubeflow-series-part2-0 to k3s-kubeflow-e183-917191-node-pool-7e46-n66x1
notebook/kubeflow-series-part2 Reissued from pod/kubeflow-series-part2-0: Successfully assigned kubeflow-user-example-com/kubeflow-series-part2-0 to k3s-kubeflow-e183-917191-node-pool-7e46-n66x1
pod/kubeflow-series-part2-0 AttachVolume.Attach succeeded for volume "pvc-a75855d7-4c2d-4479-a61c-e071e3cb8eaa"
notebook/kubeflow-series-part2 Reissued from pod/kubeflow-series-part2-0: AttachVolume.Attach succeeded for volume "pvc-a75855d7-4c2d-4479-a61c-e071e3cb8eaa"
pod/kubeflow-series-part2-0 Container image "docker.io/istio/proxyv2:1.14.1" already present on machine
pod/kubeflow-series-part2-0 Created container istio-init
notebook/kubeflow-series-part2 Reissued from pod/kubeflow-series-part2-0: Created container istio-init
pod/kubeflow-series-part2-0 Started container istio-init
notebook/kubeflow-series-part2 Reissued from pod/kubeflow-series-part2-0: Started container istio-init
pod/kubeflow-series-part2-0 Pulling image "kubeflownotebookswg/jupyter-scipy:v1.6.0-rc.1"
notebook/kubeflow-series-part2 Reissued from pod/kubeflow-series-part2-0: Pulling image "kubeflownotebookswg/jupyter-scipy:v1.6.0-rc.1"
pod/kubeflow-series-part2-0 Successfully pulled image "kubeflownotebookswg/jupyter-scipy:v1.6.0-rc.1" in 34.013384426s
notebook/kubeflow-series-part2 Reissued from pod/kubeflow-series-part2-0: Successfully pulled image "kubeflownotebookswg/jupyter-scipy:v1.6.0-rc.1" in 34.013384426s
pod/kubeflow-series-part2-0 Created container kubeflow-series-part2
notebook/kubeflow-series-part2 Reissued from pod/kubeflow-series-part2-0: Created container kubeflow-series-part2
pod/kubeflow-series-part2-0 Started container kubeflow-series-part2
pod/kubeflow-series-part2-0 Container image "docker.io/istio/proxyv2:1.14.1" already present on machine
notebook/kubeflow-series-part2 Reissued from pod/kubeflow-series-part2-0: Started container kubeflow-series-part2
notebook/kubeflow-series-part2 Reissued from pod/kubeflow-series-part2-0: Container image "docker.io/istio/proxyv2:1.14.1" already present on machine
pod/kubeflow-series-part2-0 Created container istio-proxy
notebook/kubeflow-series-part2 Reissued from pod/kubeflow-series-part2-0: Created container istio-proxy
pod/kubeflow-series-part2-0 Started container istio-proxy
notebook/kubeflow-series-part2 Reissued from pod/kubeflow-series-part2-0: Started container istio-proxy
当您创建单个笔记本服务器时确实会发生很多事情,但鉴于我们已经知道的情况,让我特别提请您注意这些日志行:
statefulset/kubeflow-series-part2 create Pod kubeflow-series-part2-0 in StatefulSet kubeflow-series-part2successful
...
persistentvolumeclaim/kubeflow-series-part2-volume Successfully provisioned volume pvc-a75855d7-4c2d-4479-a61c-e071e3cb8eaa
...
pod/kubeflow-series-part2-0 AttachVolume.Attach succeeded for volume "pvc-a75855d7-4c2d-4479-a61c-e071e3cb8eaa"
...
pod/kubeflow-series-part2-0 Pulling image "kubeflownotebookswg/jupyter-scipy:v1.6.0-rc.1"
...
pod/kubeflow-series-part2-0 Successfully pulled image "kubeflownotebookswg/jupyter-scipy:v1.6.0-rc.1" in 34.013384426s
notebook/kubeflow-series-part2 Reissued from pod/kubeflow-series-part2-0: Successfully pulled image "kubeflownotebookswg/jupyter-scipy:v1.6.0-rc.1" in 34.013384426s
pod/kubeflow-series-part2-0 Created container kubeflow-series-part2
pod/kubeflow-series-part2-0 Started container kubeflow-series-part2
...
这段经过编辑的日志更容易解释,这告诉我们有关笔记本服务器创建过程的信息:
-
Kubeflow 首先创建一个 StatefulSet,其中创建了我们的 Notebook Server 的 pod
-
为我们的 Notebook Server
kubeflow-series-part2-0创建了一个 pod,这是我们的代码运行的地方 -
一个专用的持久卷声明(我们稍后会详细讨论)附加到这个 pod,这是我们使用笔记本服务器时的主目录所在的位置
-
我们的 Notebook Server 使用我们放入的镜像,在本例中为
kubeflownotebookswg/jupyter-scipy:v1.6.0-rc.1并在 pod 中启动一个容器
笔记本服务器可以附加到专用持久卷声明和共享持久卷声明。专用持久卷声明充当您的主目录,默认情况下您将在其中运行您的实验或存储工件。而共享持久卷声明安装在所有笔记本服务器上,可用于共享数据集。在下一节中,我们将更深入地了解 Kubernetes Notebooks 中持久性卷声明究竟解决了什么问题。
笔记本服务器的存储卷
StatefulSet 为每个 pod 分配唯一标识符,并允许您轻松地在持久数据卷中存储和跟踪数据,但是,这是一个完全独立的实体,并且具有独立于 pod 的生命周期。持久卷是集群资源,类似于集群内的节点。这从存储的使用方式中提取了很多关于如何提供存储的细节,它从主存储中检索分析所需的数据并根据需要写回更改
持久数据卷通过持久卷声明连接到特定 pod,这些声明允许用户使用抽象存储资源。在该实例中,您删除笔记本服务器,数据仍保留在分配给该 pod 的持久数据卷中,如果创建新的笔记本服务器,它将能够从相同的持久数据卷访问相同的数据。
笔记本服务器和存储
它(持久卷声明)类似于 Pod。 Pod 消耗节点资源,PVC 消耗 PV 资源。 Pod 可以请求特定级别的资源(CPU 和内存)。声明可以请求特定的大小和访问模式(例如,可以挂载 ReadWriteOnce、ReadOnlyMany 或 ReadWriteMany
kubernetes.io
要设置共享存储卷,我们首先需要创建一个 KubernetesStorageClass,理想情况下,您希望您的存储类提供动态配置。下面是一个根据 Kubernetes 文档改编的创建 Portworx 卷的简单示例:
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: portworx-io-priority-high
provisioner: kubernetes.io/portworx-volume
parameters:
repl: "1"
snap_interval: "70"
priority_io: "high"
一旦创建了一个 StorageClass(许多云通常也提供默认存储类,您可以以相同的方式使用),我们可以在使用“添加新卷”选项创建笔记本服务器时配置持久卷声明,这是一个示例如何使用 UI 做到这一点:
使用 UI 创建一个新卷
或者您也可以使用 YAML 规范定义这些:
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: shared-claim
namespace: kubeflow-user-example-com
annotations:
volume.beta.kubernetes.io/storage-class: portworx-io-priority-high
spec:
accessModes:
- ReadWriteMany
resources:
requests:
storage: 8Gi
Kubeflow 还允许您使用 Kubeflow UI 轻松管理卷:
使用 Kubeflow UI 管理卷
正如我之前展示的,除了共享存储卷之外,笔记本服务器也将具有专用卷。
自定义您的笔记本服务器
在上一节中,我们讨论了创建笔记本服务器以及如何为笔记本服务器使用预构建的映像。但是,您可能已经观察到您不受预构建图像的限制,您还可以指定您自己想要使用的自定义图像。让我们看看如何为 Kubeflow Notebooks 创建图像。
Kubeflow Notebooks 原生支持三种类型的笔记本,JupyterLab、RStudio 和 Visual Studio Code,但是您可以在自定义映像中使用任何其他基于 Web 的 IDE。您可以在此处](https://github.com/kubeflow/kubeflow/tree/master/components/example-notebook-servers)找到预先构建的笔记本图像[列表,以及可以在此处上扩展的基本笔记本服务器。
Kubeflow 文档提供了自定义镜像需要能够与 Kubeflow Notebooks 一起运行的完整列表。要让 Kubeflow Notebooks 使用容器镜像,该镜像必须:
-
在端口
8888上公开一个 HTTP 接口: -
kubeflow 在运行时使用我们期望容器正在监听的 URL 路径设置环境变量
NB_PREFIX -
kubeflow 使用 IFrame,因此请确保您的应用程序在 HTTP 响应标头中设置
Access-Control-Allow-Origin: * -
以名为
jovyan的用户身份运行:
*jovyan的主目录应该是/home/jovyan
*jovyan的UID应该是1000
-
以安装在
/home/jovyan的空 PVC 成功启动: -
kubeflow 在
/home/jovyan挂载一个 PVC 以在 Pod 重启时保持状态
下面是在 Jupyter 基础映像之上构建映像的示例,但有 2 个附加包:tensorflow和fast-transformer:
FROM public.ecr.aws/j1r0q0g6/notebooks/notebook-servers/jupyter:v1.5.0
RUN python3 -m pip install \
tensorflow==2.5.3 \
fast-transformer==0.2.0
然后,您可以构建此映像并使用任何工具推送它,这里我们将使用 Docker:
TAG=0.1.0
docker build \
-t jupyter-tensorflow-example:${TAG} \
--f jupyter-tensorflow-example.Dockerfile .
docker push ...
建议在任何基础映像之上构建,但您不限于这样做。让我们看看如何在不使用任何基础镜像的情况下创建镜像。这是另一个示例,它实现了获得相同的 2 个包但不使用基本图像:
FROM ubuntu:22.04
RUN apt-get update && apt-get install -y \
python3 \
python3-pip
RUN python3 -m pip --no-cache-dir install --upgrade \
"pip<20.3" \
setuptools
RUN python3 -m pip install --no-cache-dir \
jupyter \
tensorflow==2.5.3 \
fast-transformer==0.2.0
RUN apt-get install -y --no-install-recommends \
git \
libgl1-mesa-glx
EXPOSE 8888
ENV NB_PREFIX /
CMD ["bash","-c", "jupyter notebook --notebook-dir=/home/jovyan --ip=0.0.0.0 --no-browser --allow-root --port=8888 --NotebookApp.token='' --NotebookApp.password='' --NotebookApp.allow_origin='*' --NotebookApp.base_url=${NB_PREFIX}"]
以同样的方式,如前所述,您可以构建此映像并使用任何工具推送它。
使用您自己的图像
完成此操作后,您可以在创建新笔记本服务器时轻松使用此映像,如图所示。
Kubeflow 如何支持协作?
在 Kubeflow Notebooks 的上下文中,Kubeflow 还支持基于角色的访问控制,以实现对 Notebooks 的细粒度访问。 Notebook Server 是 Kubeflow 命名空间的一部分。因此,即使 Kubernetes 没有根深蒂固的多租户,Kubeflow Notebooks 也可以通过命名空间和基于角色的访问控制来实现多用户隔离,并且开箱即用。
由于 Kubeflow Notebook Server 基于容器镜像,因此它附带了 Kubeflow Notebooks 实例所需的库、框架和工具。您可以根据需要轻松创建多个不同的笔记本服务器,例如:对于训练,您可以拥有 TensorFlow GPU 图像,同时使用具有不同库的基于 CPU 的图像来分析数据集。
这是一张取自kubeflow.org的精彩图表,显示了 Kubeflow 中的多租户:

笔记本服务帐号
当您创建一个新笔记本时,Kubeflow 默认为该笔记本 pod 分配default-editorKubernetes ServiceAccount。为了更好地理解这对您作为用户意味着什么,您可以运行:
kubectl describe clusterrole kubeflow-edit
因为default-editor角色绑定到kubeflow-editClusterRole。
如果您看到此命令的输出,我们会看到在 Notebook Pod 中运行代码时,您绑定了具有高权限的default-editorKubernetes ServiceAccount,您也可以在笔记本中提交 Kubernetes 资源。这使您可以与 Kubeflow 架构的其余部分进行很好的集成。
结论
谢谢你一直陪我到最后。我希望您对 Kubeflow Notebooks 及其工作原理有所了解,并且喜欢阅读本文。如果您学到了新知识或喜欢阅读本文,请分享它,以便其他人可以看到。在那之前,我们下一篇文章见!
我们将在本系列的下一篇文章中继续我们在本文中讨论的内容,我们将更深入地了解 Kubeflow Pipelines,在那之前,再见!
你也可以在 Twitter@rishit_dagli上找到我,我在推特上发布了有关机器学习和开源的信息。
在Hashnode、Twitter和Linkedin上关注 Kubesimplify。加入我们的Discord服务器与我们一起学习。
更多推荐
所有评论(0)