背景
完整的机器学习流程通常包括数据收集、特征提取、模型训练、上线运行等多个步骤,其中,机器学习模型在整个过程中扮演了十分重要的角色。在实际应用中,模型数据通常需要频繁更新和快速迭代,这就要求在应用版本保持不变的情况下,完成对数据的独立升级,且升级过程中业务需要持续提供服务,保证服务的可用性。本文通过对云原生数据交付平台 Kuda(https://github.com/kuda-io/kuda)进行介绍,并展示了模型分发的整个过程,为机器学习场景在云原生架构升级过程中的数据管理问题提供了一站式解决方案。
Kuda 介绍
什么是 Kuda
Kuda (Kubernetes+data) 是云原生的数据交付平台,为数据驱动型应用提供数据分发、滚动更新、版本管理等核心能力,实现对数据全生命周期的一站式管理。
该项目具有以下特点:
业务无侵入: 将数据交付能力下沉到基础设施层,实现与业务层的解耦,无需对现有业务进行改造,提升业务的迭代效率。
数据全生命周期管理: 提供对数据的交付使用、状态跟踪、查询展示等多方面的管理能力,贯穿数据的整个生命周期。
灵活对接多种工作负载: 支持与任意类型的 Kubernetes 工作负载进行集成,即插即用,平台独立部署和维护。
支持多种数据源: 原生支持 HDFS、Minio、Ceph 等数据源,预留数据源的扩展接口,方便快速集成。
适用于多种场景: 满足 AI、大数据等多种业务场景的需求,支持模型、配置、可执行文件等不同类型的数据交付。
核心功能
Kuda 的分层架构如下图所示。Kuda 的平台组件建立在 Kubernetes 基础之上,目前包括 Controller Manager、Webhook、Runtime,后面我们会详细介绍各组件的职责和实现机制;在组件层之上,描述了 Kuda 的核心功能和特点,包括数据管理、支持对接的数据源和工作负载等;最上层则列出了模型、配置等数据交付的业务场景。
Kuda 提供的功能具体可分为以下 4 个方面。
数据全生命周期管理: Kuda 提供数据下载、变更通知、状态跟踪和数据清理功能,贯穿了数据的整个生命周期,解决了有状态应用的管理问题。
多版本管理: 用于解决数据独立升级的问题,通过对每份数据多个版本的统一管理,实现数据粒度的独立升级,同时保证数据升级过程中可灰度、可回滚、可观察,满足生产环境下的使用要求。
元数据管理: 该功能是为了解决数据碎片化分布的问题,一方面,由平台记录各项数据的名称、命名空间、版本、路径等详细的元数据信息,方便数据的查询统计;另一方面,维护各项数据和业务实例、机器节点之间的映射关系,将这些信息作为数据清理的依据。
亲和性调度: 为了降低数据重复下载带来的资源开销,Kuda 基于数据在不同节点的分布情况,将应用实例优先调度到有数据的节点,这种亲和性调度策略可以保证相同应用的不同实例尽可能调度到同一机器节点,使得节点上的各个实例可以共用同一份数据,降低了对磁盘、带宽等资源的浪费。
技术架构
Kuda 目前主要包括 Controller Manager、Webhook、Runtime 三个组件,整体技术架构如下图所示。
Controller Manager 基于 Kubernetes Operator 机制设计,遵循声明式、最终一致性的设计理念,具体包括 DataSet Controller 和 Data Controller 两部分。Webhook 组件用于 Sidecar 容器的自动注入。这种自动注入的设计具有业务无侵入的优势,将数据处理能力从业务层下沉到基础设施层,使得平台组件可以独立维护,提高了业务的迭代效率。Runtime 提供了数据下载、变更通知、版本回收、数据上报等核心能力,该组件以 sidecar 的形式与业务部署在一起,并针对不同阶段提供了 sidecar 与业务容器之间的交互机制,以更好的协调两者之间的关系。
Kuda 安装
在准备好的 Kubernetes 集群上,执行以下命令即可快速完成安装:
kubectl apply -f https://raw.githubusercontent.com/kuda-io/kuda/master/install/kuda.yaml
复制代码
安装完成后,检查各个组件是否正常运行:
$ kubectl get all -n kuda-system
NAME READY STATUS RESTARTS AGE
pod/kuda-controller-manager-754b654b75-5q25s 2/2 Running 0 52s
pod/kuda-webhook-59df7dc545-275cn 1/1 Running 0 51s
pod/kuda-webhook-init-7hkwl 0/1 Completed 0 51s
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/kuda-controller-manager-metrics-service ClusterIP 10.96.27.64 <none> 8443/TCP 53s
service/kuda-webhook ClusterIP 10.96.180.222 <none> 443/TCP 53s
NAME READY UP-TO-DATE AVAILABLE AGE
deployment.apps/kuda-controller-manager 1/1 1 1 53s
deployment.apps/kuda-webhook 1/1 1 1 52s
NAME DESIRED CURRENT READY AGE
replicaset.apps/kuda-controller-manager-754b654b75 1 1 1 53s
replicaset.apps/kuda-webhook-59df7dc545 1 1 1 52s
NAME COMPLETIONS DURATION AGE
job.batch/kuda-webhook-init 1/1 6s 52s
复制代码
模型分发实践
1、安装 HDFS 存储组件
kubectl apply -f https://raw.githubusercontent.com/kuda-io/kuda/master/install/addons/hdfs.yaml
复制代码
2、准备模型文件 half_plus_two 并上传到 HDFS:
# 下载 serving 项目并进入模型数据的目录
$ git clone https://github.com/tensorflow/serving
$ cd serving/tensorflow_serving/servables/tensorflow/testdata
# 设置 hdfs 实例的名称
$ export HDFS_POD=$(kubectl get pod -n kuda-system -l app=hdfs -o jsonpath={.items..metadata.name})
# 将本地模型文件拷贝到容器中
$ kubectl cp saved_model_half_plus_two_2_versions -n kuda-system $HDFS_POD:/opt/hadoop
# 在 hdfs 服务端创建目录
$ kubectl exec -n kuda-system $HDFS_POD -- hadoop fs -mkdir -p /kuda/models
# 将模型数据上传到 hdfs 服务端
$ kubectl exec -n kuda-system $HDFS_POD -- hadoop fs -put /opt/hadoop/saved_model_half_plus_two_2_versions /kuda/models/saved_model_half_plus_two
复制代码
3、提交 DataSet 内容
$ cat <<EOF | kubectl apply -f -
apiVersion: data.kuda.io/v1alpha1
kind: DataSet
metadata:
name: dataset-serving
spec:
template:
dataItems:
- name: half_plus_two
namespace: kuda-io
remotePath: /kuda/models/saved_model_half_plus_two/00000123
localPath: /models/half_plus_two/00000123
version: "00000123"
dataSourceType: hdfs
dataSources:
hdfs:
addresses: ["hdfs-service.kuda-system:8020"]
userName: root
workloadSelector:
app: "serving"
EOF
复制代码
4、创建 Tensorflow Serving 应用
$ cat <<EOF | kubectl apply -f -
apiVersion: apps/v1
kind: Deployment
metadata:
name: serving-deployment
labels:
app: serving
spec:
replicas: 1
selector:
matchLabels:
app: serving
template:
metadata:
labels:
app: serving
spec:
containers:
- name: serving
image: tensorflow/serving
ports:
- containerPort: 8501
env:
- name: MODEL_NAME
value: half_plus_two
- name: MODEL_BASE_PATH
value: /kuda/data/models
EOF
复制代码
5、检查数据下发状态
$ kubectl get dataset
NAME DATAITEMS READY AGE
dataset-serving 1 1/1 37s
$ kubectl get data
NAME READY AGE
dataset-serving-cb7b558cf-6sn59 1/1 26s
复制代码
已上说明模型数据已经成功下发。
6、验证 serving 服务执行下面的命令验证 serving 服务是否正常工作:
$ export SERVING_POD_IP=$(kubectl get pod -l app=serving -o jsonpath={.items..status.podIP})
$ kubectl run debug -i --rm --quiet=true --restart=Never --image=curlimages/curl -- curl -d '{"instances": [1.0, 2.0, 5.0]}' -X POST -s http://$SERVING_POD_IP:8501/v1/models/half_plus_two:predict
{
"predictions": [2.5, 3.0, 4.5
]
}
复制代码
总结
作为云原生的数据交付平台,Kuda(https://github.com/kuda-io/kuda) 为数据驱动型应用提供了数据分发、滚动更新、版本管理等核心能力,具有业务无侵入、数据全生命周期管理、支持对接多种工作负载和数据源等技术优势。本文展示了 Kuda 在 AI 场景下的模型分发实践,今后将围绕数据交付打造更加丰富的平台能力,探索更多场景下的落地实践。
评论