20、Kubernetes 上的机器学习与高级应用模式

Kubernetes 上的机器学习与高级应用模式

1. Kubernetes 上的机器学习

在 Kubernetes 上运行机器学习工作负载时,有几个关键方面需要考虑。

1.1 数据存储

检查点和保存数据应集中在单个位置,并且需要支持 ReadWriteMany。ReadWriteMany 意味着该卷可以被多个节点以读写方式挂载。使用 Kubernetes 持久卷时,需要根据自身需求确定最佳的存储平台,Kubernetes 文档列出了支持 ReadWriteMany 的卷插件。

1.2 网络

机器学习工作流的训练阶段对网络影响较大,尤其是在进行分布式训练时。以 TensorFlow 的分布式架构为例,有两个离散阶段会产生大量网络流量:参数服务器向工作节点分发变量,以及工作节点将梯度应用回参数服务器。数据交换的时间直接影响模型训练时间,所以在合理范围内,网络速度越快越好。如今大多数公共云和服务器支持 1Gbps、10Gbps 甚至 40Gbps 的网卡,通常只有在低带宽情况下,网络带宽才会成为问题。如果需要高网络带宽,也可以考虑 InfiniBand。

除了原始网络带宽,将数据从内核传输到网络也可能成为问题。一些开源项目利用远程直接内存访问(RDMA)来加速网络流量,无需修改工作节点或应用代码。RDMA 允许网络中的计算机在不使用处理器、缓存或操作系统的情况下交换主内存中的数据。例如,开源项目 Freeflow 宣称在容器网络覆盖方面具有高性能。

1.3 专用协议

在 Kubernetes 上使用机器学习时,还可以考虑一些专用协议。这些协议通常是特定于供应商的,但它们都旨在通过消除架构中容易成为瓶颈的部分(如参数服务器)来解决分布式训练的扩展问题。这些协议通常允许多个节点上的 GPU 直接交换信息,而无需涉及节点的 CPU 和操作系统。以下是一些值得研究的协议:
- 消息传递接口(MPI) :是一种标准化的便携式 API,用于在分布式进程之间传输数据。
- NVIDIA 集体通信库(NCCL) :是一个拓扑感知的多 GPU 通信原语库。

1.4 数据科学家关注的工具

对于数据科学家来说,有一些流行的工具可以让他们轻松利用 Kubernetes 进行机器学习,而无需成为 Kubernetes 专家:
- Kubeflow :是 Kubernetes 的机器学习工具包,它原生支持 Kubernetes,并附带了完成机器学习工作流所需的多个工具,如 Jupyter Notebooks、管道和 Kubernetes 原生控制器,使数据科学家能够充分利用 Kubernetes 作为机器学习平台。
- Polyaxon :是一个用于管理机器学习工作流的工具,支持许多流行的库,可在任何 Kubernetes 集群上运行,有商业版和开源版。
- Pachyderm :是一个企业级的数据科学平台,拥有一套丰富的工具,用于数据集准备、生命周期管理和版本控制,还能构建机器学习管道,有可部署到任何 Kubernetes 集群的商业版。

1.5 最佳实践

为了实现机器学习工作负载的最佳性能,可考虑以下最佳实践:
- 智能调度和自动扩展 :由于机器学习工作流的大多数阶段本质上是批处理,建议使用集群自动扩展器。GPU 硬件成本高昂,不应在其闲置时付费。可以使用污点和容忍度或特定时间的集群自动扩展器来批量安排作业在特定时间运行,使集群在需要时按需扩展。对于污点和容忍度,上游惯例是将扩展资源作为键来标记节点,例如,具有 NVIDIA GPU 的节点应标记为:Key: nvidia.com/gpu,Effect: NoSchedule。使用这种方法还可以利用 ExtendedResourceToleration 准入控制器,它会自动为请求扩展资源的 Pod 添加适当的容忍度,用户无需手动添加。
- 平衡模型训练 :模型训练需要精细平衡,某一区域的加速往往会导致其他区域出现瓶颈,这需要持续观察和调整。一般建议让 GPU 成为瓶颈,因为它是最昂贵的资源,要保持 GPU 饱和。时刻留意瓶颈,并设置监控来跟踪 GPU、CPU、网络和存储的利用率。
- 混合工作负载集群 :用于运行日常业务服务的集群也可用于机器学习。鉴于机器学习工作负载的高性能要求,建议使用一个单独的节点池,并标记为仅接受机器学习工作负载,以保护集群其他部分不受影响。此外,应考虑多个支持 GPU 的节点池,每个节点池具有不同的性能特征以适应不同的工作负载类型,同时建议在机器学习节点池上启用节点自动扩展。只有在充分了解机器学习工作负载对集群的性能影响后,才使用混合模式集群。
- 分布式训练的线性扩展 :实现分布式模型训练的线性扩展是理想目标,但大多数库在分布式时难以实现线性扩展。很多工作正在致力于改善扩展问题,但要理解其中的成本,因为这并非简单地增加硬件就能解决。根据经验,瓶颈通常来自模型本身而非基础设施。在指责模型之前,重要的是审查 GPU、CPU、网络和存储的利用率。像 Horovod 这样的开源工具旨在改进分布式训练框架,提供更好的模型扩展。

以下是一个简单的表格总结上述要点:
| 方面 | 要点 |
| ---- | ---- |
| 数据存储 | 集中存储,支持 ReadWriteMany,选择合适存储平台 |
| 网络 | 分布式训练影响大,考虑带宽和 RDMA |
| 专用协议 | MPI、NCCL 等 |
| 数据科学家工具 | Kubeflow、Polyaxon、Pachyderm |
| 最佳实践 | 智能调度、平衡训练、混合集群、线性扩展 |

2. 构建 Kubernetes 上的高级应用模式

Kubernetes 虽然简化了分布式应用的部署和操作,但对于应用开发来说仍有一定难度。因此,在许多环境中,开发高级抽象以提供更友好的开发原语是有意义的。

2.1 开发高级抽象的方法

开发 Kubernetes 上的高级原语有两种基本方法:
- 将 Kubernetes 封装为实现细节 :采用这种方法,使用平台的开发者基本不会意识到他们是在 Kubernetes 之上运行,而是将自己视为所提供平台的使用者,Kubernetes 成为实现细节。例如,构建机器学习管道时,数据科学家可能不熟悉 Kubernetes,为了让他们专注于领域工作,构建一个完整的抽象层是有意义的。
- 利用 Kubernetes 的可扩展性 :Kubernetes 服务器 API 非常灵活,可以动态向 Kubernetes API 添加任意新资源。新的高级资源与内置的 Kubernetes 对象共存,用户使用内置工具与所有 Kubernetes 资源(包括内置资源和扩展资源)进行交互。这种扩展模型使 Kubernetes 仍然是开发者的核心,但增加了功能并降低了复杂性。

选择哪种方法取决于构建抽象层的目标。如果构建一个完全隔离、集成的环境,且用户不太可能需要突破限制,同时易用性很重要,那么第一种方法是不错的选择。而在构建高级开发抽象(如轻松部署 Java 应用)时,扩展 Kubernetes 比封装它更好,原因有二:一是应用开发领域非常广泛,难以预见开发者的所有需求;二是为了持续利用 Kubernetes 的工具生态系统。

2.2 扩展 Kubernetes

扩展 Kubernetes 有几个关键技术点:
- 扩展 Kubernetes 集群
- Sidecar 容器 :Sidecar 容器在服务网格中很流行,它与主应用容器一起运行,提供与主应用解耦的额外功能,通常由单独的团队维护。例如,在服务网格中,Sidecar 可以为容器化应用提供透明的相互传输层安全(mTLS)认证。
- 准入控制器 :准入控制器是拦截器,在 Kubernetes API 请求存储到集群的后备存储之前读取这些请求。可以使用它们来验证或修改 API 对象。在 Sidecar 的上下文中,可以使用它们自动向集群中创建的所有 Pod 添加 Sidecar,开发者无需了解 Sidecar 即可受益。此外,准入控制器还可用于验证开发者提交给 Kubernetes 的对象,例如实现一个 Kubernetes 代码检查器,确保开发者提交遵循最佳实践的 Pod 和其他资源。同时,应提供一个逃生舱口(如特殊注释),以便高级用户在必要时可以选择不遵循检查规则。
- 自定义资源定义(CRDs) :CRDs 是向现有 Kubernetes 集群动态添加新资源的方式。例如,可以使用 CRDs 向 Kubernetes 集群添加新的 ReplicatedService 资源。当开发者创建 ReplicatedService 实例时,它会在 Kubernetes 中创建相应的 Deployment 和 Service 资源,因此 ReplicatedService 是一个方便的开发者抽象。CRDs 通常由部署在集群中的控制循环来管理。

以下是扩展 Kubernetes 集群的流程 mermaid 图:

graph LR
    A[Kubernetes 集群] --> B[Sidecar 容器]
    A --> C[准入控制器]
    A --> D[自定义资源定义]
    B --> E[提供额外功能]
    C --> F[验证/修改 API 对象]
    D --> G[添加新资源]
  • 扩展 Kubernetes 用户体验 :默认情况下,Kubernetes 工具对自定义资源和其他扩展不太了解,处理方式不够友好。扩展 Kubernetes 命令行可以提供增强的用户体验。kubectl 是访问 Kubernetes 的常用命令行工具,它具有可扩展性。kubectl 插件是名称类似 kubectl - foo 的二进制文件,当在命令行中调用 kubectl foo … 时,调用会路由到插件二进制文件。使用 kubectl 插件,可以定义深入理解新添加资源的新体验,同时利用 kubectl 工具的熟悉性,无需教开发者使用新工具集,也可以随着开发者 Kubernetes 知识的提升逐步引入 Kubernetes 原生概念。
2.3 构建平台时的设计考虑

构建平台时,有两个重要的设计考虑:
- 支持导出为容器镜像 :许多平台设计允许用户仅提供代码(如函数即服务中的函数)或原生包(如 Java 中的 JAR 文件),而不是完整的容器镜像,平台负责应用的容器化。但当开发者遇到编程环境的限制时,这种方法会带来问题。如果平台支持将编程环境导出为通用容器,开发者就无需从头学习容器知识,而是可以基于现有的工作容器镜像进行小调整,这种渐进式的学习方式可以平滑从高级平台到低级基础设施的过渡,提高平台的实用性。
- 支持现有的服务和服务发现机制 :平台通常会与其他系统互连,任何实际应用都会跨越所构建的平台、低级 Kubernetes 应用以及其他平台。因此,构建的任何平台都必须使用和暴露 Kubernetes 中服务和服务发现的核心原语,不要为了改进而重新发明轮子。

综上所述,在 Kubernetes 上进行机器学习和构建高级应用模式需要综合考虑多个方面,遵循最佳实践和设计原则,以实现高效、灵活的开发和部署。

Kubernetes 上的机器学习与高级应用模式

3. 设计考虑的补充说明

在构建基于 Kubernetes 的平台时,上述提到的两个设计考虑有着重要的实际意义,下面进一步展开说明。

3.1 支持导出为容器镜像的优势

为了更清晰地展现支持导出为容器镜像的好处,我们来看一个具体的示例。假设一个开发者使用某平台进行 Python 应用开发,平台默认提供的 Python 运行时版本为 3.8。但开发者在开发过程中遇到了一个只有在 Python 3.9 版本才能解决的库兼容性问题。

  • 不支持导出容器镜像的情况 :开发者不得不从头开始学习如何构建一个包含 Python 3.9 的容器镜像,这涉及到了解容器的基础概念、Dockerfile 的编写、镜像构建和推送等一系列复杂的操作,极大地增加了开发成本和时间。
  • 支持导出容器镜像的情况 :开发者可以直接从平台导出当前应用的容器镜像,该镜像已经包含了应用的代码和 Python 3.8 运行时。然后,开发者只需在这个基础上修改 Dockerfile,将 Python 版本更新为 3.9,重新构建镜像即可。这样,开发者可以在熟悉的环境下进行小范围的修改,而无需从头学习容器技术。

以下是一个简单的 Dockerfile 修改示例:

# 原始 Dockerfile
FROM python:3.8
COPY . /app
WORKDIR /app
RUN pip install -r requirements.txt
CMD ["python", "app.py"]

# 修改后的 Dockerfile
FROM python:3.9
COPY . /app
WORKDIR /app
RUN pip install -r requirements.txt
CMD ["python", "app.py"]
3.2 支持现有服务和服务发现机制的必要性

考虑一个企业级应用场景,企业内部既有基于 Kubernetes 构建的新应用,也有一些遗留的数据库和服务。新应用需要与这些遗留系统进行交互,同时也需要与其他基于 Kubernetes 的微服务进行通信。

  • 不支持现有机制的情况 :如果平台重新发明了服务和服务发现机制,那么新应用在与遗留系统和其他 Kubernetes 微服务通信时,需要额外的适配层来进行转换,这增加了系统的复杂性和维护成本。
  • 支持现有机制的情况 :平台直接使用 Kubernetes 的服务和服务发现机制,新应用可以无缝地与遗留系统和其他微服务进行通信。例如,通过 Kubernetes 的 Service 对象,新应用可以轻松地发现和访问其他服务,而无需关心这些服务的具体部署位置。

以下是一个使用 Kubernetes Service 进行服务发现的简单示例:

apiVersion: v1
kind: Service
metadata:
  name: my-service
spec:
  selector:
    app: my-app
  ports:
    - protocol: TCP
      port: 80
      targetPort: 8080
4. 总结与建议

通过前面的介绍,我们可以总结出在 Kubernetes 上进行机器学习和构建高级应用模式的关键要点。

类别 要点总结
机器学习 关注数据存储、网络、专用协议,利用适合数据科学家的工具,遵循最佳实践进行智能调度、平衡训练、合理使用混合集群和追求分布式训练的线性扩展
高级应用模式 选择合适的开发高级抽象方法,扩展 Kubernetes 集群和用户体验,遵循支持导出容器镜像和现有服务发现机制的设计原则

为了更好地在 Kubernetes 上开展工作,我们给出以下建议:
- 对于机器学习工作负载
- 在选择存储平台时,仔细研究支持 ReadWriteMany 的卷插件,确保数据的高效存储和访问。
- 持续监控网络带宽和利用率,根据实际情况选择合适的网络技术,如 RDMA 或 InfiniBand。
- 合理使用数据科学家工具,如 Kubeflow、Polyaxon 和 Pachyderm,提高开发效率。
- 严格遵循最佳实践,特别是智能调度和自动扩展,避免资源浪费。
- 对于构建高级应用模式
- 根据具体需求选择合适的开发高级抽象方法,充分利用 Kubernetes 的可扩展性。
- 在扩展 Kubernetes 时,合理使用 Sidecar 容器、准入控制器和自定义资源定义,提高系统的灵活性和可维护性。
- 始终遵循支持导出容器镜像和现有服务发现机制的设计原则,确保平台的兼容性和实用性。

通过遵循这些建议,开发者可以在 Kubernetes 上更高效地进行机器学习和构建高级应用模式,实现业务的快速发展和创新。

下面是一个简单的 mermaid 流程图,展示了在 Kubernetes 上开展工作的整体流程:

graph LR
    A[确定工作类型] --> B{机器学习 or 高级应用模式}
    B -- 机器学习 --> C[考虑数据存储、网络等因素]
    C --> D[选择合适工具和遵循最佳实践]
    B -- 高级应用模式 --> E[选择开发抽象方法]
    E --> F[扩展 Kubernetes]
    F --> G[遵循设计原则]
    D --> H[开展机器学习工作]
    G --> I[构建高级应用模式]

综上所述,Kubernetes 为机器学习和高级应用模式的构建提供了强大的支持,但需要开发者全面了解相关知识和技术,合理运用各种工具和方法,才能实现高效、灵活的开发和部署。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符  | 博主筛选后可见
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值