全栈工程师开发手册 (作者:栾鹏)
一站式云原生机器学习平台
前言:cube是开源的云原生机器学习平台,目前包含特征平台,支持在/离线特征;数据源管理,支持结构数据和媒体标注数据管理;在线开发,在线的vscode/jupyter代码开发;在线镜像调试,支持免dockerfile,增量构建;任务流编排,在线拖拉拽;开放的模板框架,支持tf/pytorch/spark/ray/horovod/kaldi等分布式训练任务;task的单节点debug,分布式任务的批量优先级调度,聚合日志;任务运行资源监控,报警;定时调度,支持补录,忽略,重试,依赖,并发限制,定时任务算力的智能修正;nni,katib,ray的超参搜索;多集群多资源组,算力统筹,联邦调度;tf/pytorch/onnx模型的推理服务,serverless流量管控,tensorrt gpu推理加速,依据gpu利用率/qps等指标的 hpa能力,虚拟化gpu,虚拟显存等服务化能力。 目前开源到github:https://github.com/tencentmusic/cube-studio
TME机器学习平台基于kubeflow做开源改造和产品化,先来看看技术层面kubeflow对机器学习的各个技术环节的附能
先简单介绍一下各组件的功能。下面以大项目背景为例简介的,可以在下面的部署中了解更细致的组件内容。
cube机器学习平台的目前架构
机器的配置没有强制要求,只要安装上docker即可,但是在k8s部署后,kubelet启动时会依据机器的dns和host配置将解析带入k8s,所以需要在启动前初始化好集群业务需要用到的dns/host配置。另外大量功能依赖分布式存储,我们需要在开机时配置自动挂载。可以手动添加个开机自启动脚本,这样就不怕重启机器带来的机器差异问题。
Ceph: ceph目前测试写入50M-60M/s,读取100M,多用户读写相互干扰
Cfs:cfs/nfs速度均在100M,稍强于ceph,不过同样存在多用户相互干扰的情况,
Cos:cos无法直接以路径请示挂载到自建k8s中,需要wget一步,则与先从ceph拉取到容器中无异。
目前,我们部署在idc环境自建的k8s集群中,目前选择ceph。
建议部署docker 19.03以上的版本,部署docker,我们要修改docker的配置,主要包括docker的数据挂载目录(因为默认安装目录在/var/lib/docker/一般磁盘比较小,公司的外挂盘一般在/data/home下面)和私有仓库(公司的docker.oa.com:8080需要添加私有屏蔽,csighub.tencentyun.com 需要 添加host 9.149.109.34)。
echo "9.149.109.34 csighub.tencentyun.com" >> /etc/hosts
cat /usr/lib/systemd/system/docker.service
...
ExecStart=/usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock --graph /data/home/docker
...
首先需要找运维同学安装机器gpu卡对应的驱动,然后需要让你的docker能识别并应用gpu驱动。
如果你的docker是19.03以后的版本,并且只在docker中使用而不在k8s中使用,可以只安装nvidia-container-runtime 或者 只安装nvidia-container-toolkit,然后重启docker,就可以在docker run时通过添加参数–gpus 来应用gpu卡了。
如果你的docker是19.03以前的版本,或者19.03以后的版本并需要在k8s中使用gpu,那需要安装nvidia docker2,因为k8s还没有支持docker的–gpu参数。安装nvidia docker2以后,修改docker 默认runtime。重启docker,这样就能在docker或者k8s中使用gpu了。
cat /etc/docker/daemon.json
{
"insecure-registries":["docker.oa.com:8080","9.134.36.249:80"],
"default-runtime": "nvidia",
"runtimes": {
"nvidia": {
"path": "/usr/bin/nvidia-container-runtime",
"runtimeArgs": []
}
}
}
Kubeflow利用Kubernetes的优势:
机器环境配置好以后,我们就可以来部署k8s机器了。下面是k8s的一个架构。
需要特别注意的是,我们需要做一些专门的处理,
1、我们需要pod和service的网段,服务公司安全规范
2、修改node port范围,因为公司能开放的端口有限,所以做好把node port范围放大一些。
3、修改api-server的启动参数,因为我们会启动数字优先级调度,所以需要修改。如果无此需求可以不修改
4、controller的集群网段和service网段需要错开,所以有可能我们需要自己做网段分割,需要服务公司的ip安全策略
5、kubelet 的 cluster_dns_server 的地址要写死,而且要符合上面的网段范围。
6、修改kubelet的自动回收策略,根据自己的机器的磁盘容器来修改,这样就 不会随意进行镜像回收。因为我们在内网部署,可能有些镜像是无法自动拉取的。所以有时需要减少没必要的镜像清理,进而减少手动拉取镜像并tag的操作。
7、修改kubelet的主机目录绑定,因为rancher是容器化部署,在k8s中使用挂载子目录的时候,实际是挂载到kubelet所在环境下,如果这个目录没有通过kubelet挂载到主机上,那么主机pv的子目录就没办法使用了。
我们需要修改的api-server、controller、kubelet的启动参数如下
kube-api:
service_node_port_range: 10-32767
service_cluster_ip_range: 172.16.0.0/17
extra_args:
enable-admission-plugins: "NamespaceLifecycle,LimitRanger,ServiceAccount,DefaultStorageClass,DefaultTolerationSeconds,MutatingAdmissionWebhook,ValidatingAdmissionWebhook,ResourceQuota,NodeRestriction,TaintNodesByCondition,PersistentVolumeClaimResize"
kube-controller:
cluster_cidr: 172.16.128.0/17
service_cluster_ip_range: 172.16.0.0/17
kubelet:
cluster_dns_server: 172.16.0.10
extra_args:
image-gc-high-threshold: 90
image-gc-low-threshold: 85
extra_binds:
- '/data/home:/data/home'
- '/data/k8s:/data/k8s'
- '/mnt/ceph_fuse:/mnt/ceph_fuse'
除了需要了解k8s官方资源,例如pod,service,sa,rbac,sts,deployment外,另外我们需要特别了解k8s的自定义资源CustomResourceDefinition。简称CRD。这个在机器学习平台中使用非常频繁,下面列举用到的常用的部分crd。
Kubeflow自定义资源类型 | 组 | 是否命名空间内 | kind | 说明 |
---|---|---|---|---|
experiments | kubeflow.org | TRUE | Experiment | pipline中的实验 |
notebooks | kubeflow.org | TRUE | Notebook | jupyterhub项目组 |
poddefaults | kubeflow.org | TRUE | PodDefault | |
profiles | kubeflow.org | FALSE | Profile | 多用户 |
pytorchjobs | kubeflow.org | TRUE | PyTorchJob | pytorch分布式训练 |
scheduledworkflows | kubeflow.org | TRUE | ScheduledWorkflow | pipline中的定时调度 |
suggestions | kubeflow.org | TRUE | Suggestion | katib的建议器 |
tfjobs | kubeflow.org | TRUE | TFJob tf分布式训练 | |
trials | kubeflow.org | TRUE | Trial | katib每个参数的运行 |
viewers | kubeflow.org | TRUE | Viewer | Viewer |
Argo自定义资源类型: | 组 | 是否命名空间内 | kind | 说明 |
---|---|---|---|---|
clusterworkflowtemplates | argoproj.io | FALSE | ClusterWorkflowTemplate | argo的定时调度模板 |
cronworkflows | argoproj.io | TRUE | CronWorkflow | argo的定时调度 |
workflows | argoproj.io | TRUE | Workflow | argo的workflow |
workflowtemplates | argoproj.io | TRUE | WorkflowTemplate | argo的模板 |
knative自定义资源 | 组 | 是否命名空间内 | kind | 说明 |
---|---|---|---|---|
podautoscalers | autoscaling.internal.knative.dev | TRUE | PodAutoscaler 弹性伸缩 | |
images | caching.internal.knative.dev | TRUE | Image | 指定时间戳创建时间的指定镜像 |
ingresses | networking.internal.knative.dev | TRUE | Ingress | k8s ingress网关 |
serverlessservices | networking.internal.knative.dev | TRUE | ServerlessService | server less的服务 |
configurations | serving.knative.dev | TRUE | Configuration | 版本和流量代理配置 |
revisions | serving.knative.dev | TRUE | Revision | 业务版本管理 |
routes | serving.knative.dev | TRUE | Route | 业务流量路由 |
services | serving.knative.dev TRUE | Service | 业务对外服务 |
此外还有istio、knative、prometheus项目组的各种自定义资源。
kubeflow机器学习平台组部署方案已经同步到https://github.com/tencentmusic/cube-studio。
git上部署方案总体是基于kubeflow1.2版本的。在idc部署kubeflow,以及周边项目,可能会遇到下面的这些问题。
在idc网络我们可以使用csighub的仓库,但是前提是镜像名要包含csighub的服务器地址。部分镜像不知道在哪里去改配置,所以我们整理了一个脚本镜像清单和拉取tag脚本pull_image.sh。包含了rancher的组件,kubeflow的组件,rfk的组件,prometheus的组件,链路跟踪的组件。因为这些都是开源项目,往往不太方便去修改镜像名。在初始化机器时,都会被执行这样的脚本,满足开源项目的基本镜像环境。
对于我们自定义的镜像,都可以使用csig的仓库,配置上仓库地址和拉取策略就可以。
在项目中部分离线镜像的拉取策略是Always,但是镜像本身我们是通过上面的方式离线拉取的,在线拉取是无法访问远程仓库的,所以git项目中,已经将这部分修改为IfNotPresent。对于自定义的可以拉取的镜像,自己随意配置。
我们知道镜像名由名称和tag构成,但是可以重复的推送同一个tag的镜像,这样仓库中的镜像就会被覆盖。但是每次推送到 镜像都会有一个唯一的sha256的编码。docker本身提供通过指定镜像的指定sha256来进行拉取,这样push覆盖也不会拉取覆盖,但是这总方式必须要Always拉取。git中将这部分镜像tag成新的镜像版本,并且修改拉取处的镜像名,使用新tag版本。然后再用上面的方法使用本地已存在的镜像。
部分组件中需要具有拉取镜像的功能,csighub的访问需要域名解析。也已经在需要的部署中添加了对应的host配置。
kubeflow官方开源的部署方案是使用kustomize来完成。并且封装了组件kfctl,来实现一键部署。
kubeflow开源框架的架构如下图所示
各组件的功能已经在上面做了介绍,全部组件可以参考:https://www.kubeflow.org/docs/guides/components/components/
但是在kubeflow 1.2的版本中集成的各个组件可能并不是最新的。部分组件没有相互依赖关系,可以独立升级。
在上面的全局部署中屏蔽了pipeline的部署,因为kubeflow部署方案中携带的pipeline版本太低。pipeline独立部署升级也已经同步到git的“升级pipeline”文件夹中。
同样kubeflow全部部署中的katib版本也较低,在全局部署中已经屏蔽了katib的部署,可以单独部署和升级katib。已经同步到git的“升级katib”文件夹中
在官方的kubeflow部署方案中并没有集成xgbjob的部署,在git中“升级xgboost-operator”文件夹中包含了xgb分布式job的支持。
官方开源的各个项目中,kubeflow组件的命名空间都在kubeflow,组件创建的业务容器也在kubeflow命名空间,非常不方便管理。git中已经对这些进行了拆分,kubeflow的控制容器保留在kubeflow命名空间,业务的pipeline和训练容器保留在pipeline命名空间,业务的超参搜索容器在katib命名空间,业务的notebook容器在jupyter命名空间,相关的配置文件,需要新增的部署脚本也都已经添加到git中
kubeflow下的istio本身支持对接多种监控系统,并没有固定使用哪一种,我们这里提供下我们使用的监控系统。
指标监控,使用prometheus框架。部署开源到github.com/tencentmusic/cube-studio
日志监控,使用EFK框架。部署开源到github.com/tencentmusic/cube-studio
链路监控,使用zipkin框架。部署开源到github.com/tencentmusic/cube-studio