在最近的一段时间,主要投入到“分布式机器学习平台” 的技术选型和搭建过程,今天对前段时间的工作进行下总结。
这项工作主要的主要出发点有两点,第一是将现有的服务器资源充分利用,达到分布式训练,提高训练速度。第二是将原有基于Spark的计算集群整合到k8s上,统一集群架构,统一使用容器来进行管理。
本篇文章主要记录了第一部分工作完成的过程和相关经验,第二部分的工作可以查看博主的另一篇文章:。
K8s是google开源的容器编排系统,在云原生架构中处于Pass层面,能够管理容器的整个生命周期。随着时间的发展,其优势地位逐渐显现,已经有逐渐成为统一容器编排领域的趋势。而且,一开始k8s主要被用于微服务领域,利用k8s来管理容器,而微服务运行在容器中,这样的架构方便服务弹性伸缩,带来了很多好处。现在,k8s越来越被作为一种底层设施,负责支撑无状态应用、有状态应用、大数据应用等多种类型的服务。
在分布式机器学习方面,有很多种方式,包括“数据并行”,“模型并行”等等,Pytorch、Tensorflow等框架其本身提供了分布式训练的能力,但是这种分布式只是在计算层次,我们需要手动构建“多机多卡”等分布式训练环境,保证各个节点之间能够进行通讯,所以,我们还需要“控制、调度”的能力。
Spark、K8s都能够支持GPU的管理,而且提供应用分布式调度的能力。现有的平台架构大多基于k8s,而且在k8s生态中,kubeflow是被很多厂商采用的分布式机器学习套件。
kubeflow是在k8s之上运行的一组服务,对k8s有很强的依赖性。因此,在选择k8s版本时,首先要根据kubeflow的版本要求,选择合适的k8s版本。
yum install "kernel-devel-uname-r == $(uname -r)"
集群搭建中主要参考下面这篇博客: https://juejin.im/post/5e550b3ff265da57570476db
在微服务架构下,单个服务承载一定的功能,服务与服务之间相互依赖,需要进行通讯。如何控制服务于服务之间的通讯的方式?同时所有的服务构成服务集群,如何将服务集群暴露出来,供用户访问?istio给出了解决方案。
https://istio.io/latest/docs/ops/common-problems/validation/
在Istio中集成了grafana、kiali、promtheus等多种套件,能够很好的监控整个微服务集群。在kubeflow中会使用istio的相关功能,在kubeflow 安装资源清单kfctl_k8s_istio.v1.0.2.yaml 中,使用istio 1.1.3的版本,该版本太低。笔者想采用较高的版本,但是istio的版本和kubeflow的版本适配也是很大的问题,经过采坑和实践后,推荐搭建使用isito 1.4.3的版本配合kfctl_k8s_istio.v1.0.2.yaml。
安装步骤
curl -L https://git.io/getLatestIstio | ISTIO_VERSION=0.3.6 sh -
通过ISTIO_VERSION 可以指定下载安装的istio的版本
istioctl manifest apply \
--set profile=demo \
--set values.kiali.enabled=true \
--set "values.kiali.dashboard.jaegerURL=http://jaeger-query:16686" \
--set "values.kiali.dashboard.grafanaURL=http://grafana:3000"
在kubeflow的安装中,可以参考官网指导进行,但是由于国内镜像的限制会有很大的问题。
kfctl build -V -f ${CONFIG_URI}
grep 'Always' -rl . | xargs sed -i "s/Always/IfNotPresent/g"
#!/usr/bin/env bash
echo ""
echo "=========================================================="
echo "pull kubeflow v1.0 images from dockerhub ..."
echo "=========================================================="
echo ""
# registry.cn-hangzhou.aliyuncs.com/smartliby
gcr_imgs=(
"smartliby/kfserving-controller:0.2.2,gcr.io/kfserving/kfserving-controller:0.2.2"
"smartliby/api-server:0.2.0,gcr.io/ml-pipeline/api-server:0.2.0"
"smartliby/kfam:v1.0.0-gf3e09203,gcr.io/kubeflow-images-public/kfam:v1.0.0-gf3e09203"
"smartliby/ingress-setup:latest,gcr.io/kubeflow-images-public/ingress-setup:latest"
"smartliby/application:1.0-beta,gcr.io/kubeflow-images-public/kubernetes-sigs/application:1.0-beta"
"smartliby/centraldashboard:v1.0.0-g3ec0de71,gcr.io/kubeflow-images-public/centraldashboard:v1.0.0-g3ec0de71"
"smartliby/jupyter-web-app:v1.0.0-g2bd63238,gcr.io/kubeflow-images-public/jupyter-web-app:v1.0.0-g2bd63238"
"smartliby/katib-controller:v0.8.0,gcr.io/kubeflow-images-public/katib/v1alpha3/katib-controller:v0.8.0"
"smartliby/katib-db-manager:v0.8.0,gcr.io/kubeflow-images-public/katib/v1alpha3/katib-db-manager:v0.8.0"
"smartliby/katib-ui:v0.8.0,gcr.io/kubeflow-images-public/katib/v1alpha3/katib-ui:v0.8.0"
"smartliby/kube-rbac-proxy:v0.4.0,gcr.io/kubebuilder/kube-rbac-proxy:v0.4.0"
"smartliby/metacontroller:v0.3.0,gcr.io/metacontroller/metacontroller:v0.3.0"
"smartliby/metadata:v0.1.11,gcr.io/kubeflow-images-public/metadata:v0.1.11"
"smartliby/envoy:metadata-grpc,gcr.io/ml-pipeline/envoy:metadata-grpc"
"smartliby/ml_metadata_store_server:v0.21.1,gcr.io/tfx-oss-public/ml_metadata_store_server:v0.21.1"
"smartliby/metadata-frontend:v0.1.8,gcr.io/kubeflow-images-public/metadata-frontend:v0.1.8"
"smartliby/visualization-server:0.2.0,gcr.io/ml-pipeline/visualization-server:0.2.0"
"smartliby/persistenceagent:0.2.0,gcr.io/ml-pipeline/persistenceagent:0.2.0"
"smartliby/scheduledworkflow:0.2.0,gcr.io/ml-pipeline/scheduledworkflow:0.2.0"
"smartliby/frontend:0.2.0,gcr.io/ml-pipeline/frontend:0.2.0"
"smartliby/viewer-crd-controller:0.2.0,gcr.io/ml-pipeline/viewer-crd-controller:0.2.0"
"smartliby/notebook-controller:v1.0.0-gcd65ce25,gcr.io/kubeflow-images-public/notebook-controller:v1.0.0-gcd65ce25"
"smartliby/profile-controller:v1.0.0-ge50a8531,gcr.io/kubeflow-images-public/profile-controller:v1.0.0-ge50a8531"
"smartliby/pytorch-operator:v1.0.0-g047cf0f,gcr.io/kubeflow-images-public/pytorch-operator:v1.0.0-g047cf0f"
"smartliby/spark-operator:v1beta2-1.0.0-2.4.4,gcr.io/spark-operator/spark-operator:v1beta2-1.0.0-2.4.4"
"smartliby/spartakus-amd64:v1.1.0,gcr.io/google_containers/spartakus-amd64:v1.1.0"
"smartliby/tf_operator:v1.0.0-g92389064,gcr.io/kubeflow-images-public/tf_operator:v1.0.0-g92389064"
"smartliby/admission-webhook:v1.0.0-gaf96e4e3,gcr.io/kubeflow-images-public/admission-webhook:v1.0.0-gaf96e4e3"
"smartliby/kfam:v1.0.0-gf3e09203,gcr.io/kubeflow-images-public/kfam:v1.0.0-gf3e09203"
"smartliby/api-server:0.2.0,gcr.io/ml-pipeline/api-server:0.2.0"
)
for img in ${gcr_imgs[@]}
do
img_array=(${img//,/ })
# 拉取镜像
docker pull ${img_array[0]}
# 添加Tag
image_name=${img_array[1]}
image_name=${image_name%@*}
docker tag ${img_array[0]} ${image_name}
# 输出
#docker save ${image_name} > /data/k8s_img/kubeflow/${image_name##*/}.tar
# 输入
# microk8s.ctr --namespace k8s.io image import /data/k8s_img/kubeflow/${image_name##*/}.tar
# 删除Tag
docker rmi ${img_array[0]}
done
echo ""
echo "=========================================================="
echo "pull kubeflow v1.0 images from dockerhub finished."
echo "=========================================================="
echo ""
部署istio
istio部署完成后,修改kubeflow的资源文件,注释掉istio有关的安装资源。
kubectl delete validatingwebhookconfigurations istio-galle
curl -H "Content-Type: application/json" \
-X PUT \
--data-binary @temp.json \
http://127.0.0.1:8080/api/v1/namespaces//finalize