DLRover makes the distributed training of large AI models easy, stable, fast and green. It can automatically train the Deep Learning model on the distributed cluster. It helps model developers to focus on model arichtecture, without taking care of any engineering stuff, say, hardware acceleration, distributed running, etc. Now, it provides automated operation and maintenance for deep learning training jobs on K8s/Ray.
蚂蚁开源的(大模型)分布式训练框架|系统;在k8s上实现模型训练的故障恢复、节点状态检测、弹性调度、Async Flash checkpoint 等功能,“实现PyTorch分布式训练的自动容错和弹性”。
从这里可以看出,DLRover和蚂蚁内部的ElasticDL 关系甚大,极有可能是ElasticDL的升级、扩展后“改头换面”。
当然具体实现功能如何,经过实测,后文会有补充说明。
准备一个K8S集群,node 全部ready,最好去掉污点。
可以使用minikube ,不过不推荐!
建议本地安装Docker+K8S;这方面文章很多就不赘述了。
$ kubectl get nodes
NAME STATUS ROLES AGE VERSION
docker-desktop Ready control-plane - v1.28.2
一般选择containerd+kubeadm+kubelet;
$ kubectl get nodes
NAME STATUS ROLES AGE VERSION
node1 Ready <none> - v1.28.2
node2 Ready <none> - v1.28.2
node3 Ready <none> - v1.28.2
node4 Ready <none> - v1.28.2
安装Elasticjob 需要非常小心,坑不少。
git clone git@github.com:intelligent-machine-learning/dlrover.git
这里有些许不同,注意本地MAC OS与GPU节点的差异;
本地MAC OS由于存储空间有限,训练测试任务比较简单,能使用DLRover即可;而生产环境或者GPU集群中,往往是复杂、大规模的分布式训练,功能作用的不同导致在CRDs的安装、Docker Image 等都有些许区别,请往下看:
仅安装基础CRDs,也是测试DLRover后续需要使用到的elasticjobs.elastic.iml.github.io和scaleplans.elastic.iml.github.io;
cd dlrover
kubectl apply -f dlrover/go/operator/config/crd/bases
kubectl -n dlrover apply -f dlrover/go/operator/config/manifests/bases/default-role.yaml
这里注意目录path,DLRover的文档中的path很多地方都不对,注意矫正。
(多说一句,不知是蚂蚁内部脱敏还是Infra团队太忙,文档中的细节比较差,在部署过程中很多地方需要自己脑补、修正,部分地方已经merge PR不过不保证没有疏漏:-)
前面都是比较简单的无脑执行CMD,接下来的就是较为复杂,往往第一次部署会踩坑。
如果直接按照github文档执行以下命令大概率会出现这些现象;
make deploy IMG=easydl/elasticjob-controller:master
$ make deploy IMG=easydl/elasticjob-controller:master
test -s /root/dlrover-0.3.1/dlrover/go/operator/bin/kustomize || { [ -s /root/install_kustomize.sh ] && bash /root/install_kustomize.sh || curl -s "https://raw.githubusercontent.com/kubernetes-sigs/kustomize/master/hack/install_kustomize.sh" | bash -s -- 3.8.7 /root/dlrover-0.3.1/dlrover/go/operator/bin; }
看到以上错误不要慌,按照以下流程走避免这些坑。
install_kustomize.sh打开虽然看着很长,内容很多,其实就是简单的检查kustomize是否已经安装,没有就安装kustomize;当然默认版本是3.8.7,这里的另一个问题是shell指定的3.8.7 版本并不存在,所以需要修改,安装最新版(v5.3)即可。
所以操作步骤变更为手动安装kustomize_v5.3;
前往github release下载对应版本的包,比如本地是MAC M3下载Kustomize_v5.3.0_darwin_arm64.tar.gz即可;
解压到指定目录,这里非常重要;
tar -xf Kustomize_v5.3.0_darwin_arm64.tar.gz -C /dlrover/dlrover/go/operator/bin/
因为install_kustomize.sh检查的路径是/dlrover/dlrover/go/operator/bin/,所以我们必须把kustomize安装到这个路径下!
执行命令检查安装是否成功:
kustomize version
回过头来,继续执行make deploy IMG=easydl/elasticjob-controller:master,会发现很快便成功了;
$ kubectl -n dlrover get crd
NAME CREATED AT
elasticjobs.elastic.iml.github.io -
scaleplans.elastic.iml.github.io -
$ kubectl -n dlrover get deployment
NAME READY UP-TO-DATE AVAILABLE AGE
dlrover-controller-manager 1/1 1 1 -
到此DLRover的本地部署工作完成了;接下来就是开始执行训练任务,测试DLRover的功能;未完待续哈。
相较于本地MAC OS,GPU集群上部署往往更为复杂;
首先下载kustomize release包(注意操作系统与软件包的对应关系,最新版即可比如v5.3),并上传到master节点;
clone DLRover代码到节点;
git clone git@github.com:intelligent-machine-learning/dlrover.git
进入代码目录(注意目录path);
cd dlrover/dlrover/go/operator/
make deploy IMG=easydl/elasticjob-controller:master
这里会有报错(参考前面本地部署的deploy Elasticjob章节);所以需要手动安装kustomize;解压kustomize安装包到dlrover/dlrover/go/operator/bin并检查安装;
tar -xf kustomize.gz -C /dlrover/dlrover/go/operator/bin
kustomize version
把CRD的权限给到DLRover Master Manager;
kubectl -n dlrover apply -f config/manifests/bases/default-role.yaml
GPU 集群的部署方式与本地存在差异,前往egistry.cn-hangzhou.aliyuncs.com拉取的CRD非常多,耗时非常长,比如统计下来达到97个;核心的其实是2个elasticjobs.elastic.iml.github.io和scaleplans.elastic.iml.github.io。
$ kubectl -n dlrover get crd |wc -l
97
可以通过kubectl 进行针对性检查(非常有必要):
kubectl -n dlrover get crd elasticjobs.elastic.iml.github.io
kubectl -n dlrover get crd scaleplans.elastic.iml.github.io
$ kubectl -n dlrover get deployment
NAME READY UP-TO-DATE AVAILABLE AGE
dlrover-controller-manager 1/1 1 1 -
到此DLRover的部署工作完成了;接下来就是开始执行训练任务,测试DLRover的功能;
启动chao test job,模拟训练任务;
$ kubectl -n dlrover apply -f examples/pytorch/mnist/chaos_test_job.yaml
$ kubectl -n dlrover get pods
NAME READY STATUS RESTARTS AGE
chaos-test-edljob-worker-0 0/1 ContainerCreating 0 2m32s
chaos-test-edljob-worker-1 0/1 ContainerCreating 0 2m32s
chaos-test-edljob-worker-2 0/1 ContainerCreating 0 2m32s
chaos-test-edljob-worker-3 0/1 ContainerCreating 0 2m32s
dlrover-controller-manager-68c984bdc9-vkwbh 2/2 Running 0 17m
elasticjob-chaos-test-dlrover-master 1/1 Running 0 3m27s
等待几分钟,等全部ready后kubelet -n dlrover delete pod 会发现DLRover会把训练任务重新拉起。
需要注意的是在apply chaos_test_job.yaml 后,pod由于长时间没有ready;此时delete ContainerCreating的pod;会发现pod直接进入error;但是DLRover感知到POD Error,随时拉起新的POD,此时集群中POD个数会由4->5;而且error pod会在相当长的时间内存在,直到手动delete。
如果kubectl -n dlrover log 会发现DLRover的动态组网在等待新的POD加入;
[2024-01-16 08:03:46,459] [ERROR] [training.py:842:run] Network check needs at least 4 nodes.
动态组网相关原理参考DLRover Doc,下面的原图:
这里逻辑目前看来似乎存在bug,如果旧节点长时间Err status,DLRover并不会主动清理,但是会拉起新的节点(因为组网最小集合不满足),于是发生失败的节点越多,新加入的节点越多,节点越多,失败的概率增大;类似网络拥塞。
夜深了,后续有时间再增加对DLRover的Async Flash checkpoint 等功能的测试吧。
虽然DLRover 的developer_guide 中要求Go 1.17 or later;但是在部署过程中发现,至少需要1.18,比如本文部署时选择了Go 1.21;
如果GO version存在问题,在deploy elasticjob的过程中会发现如下问题:
如果go version < 1.17
# sigs.k8s.io/json/internal/golang/encoding/json
/root/go/pkg/mod/sigs.k8s.io/json@v0.0.0-20211208200746-9f7c6b3444d2/internal/golang/encoding/json/encode.go:1249:12: sf.IsExported undefined (type reflect.StructField has no field or method IsExported)
/root/go/pkg/mod/sigs.k8s.io/json@v0.0.0-20211208200746-9f7c6b3444d2/internal/golang/encoding/json/encode.go:1255:18: sf.IsExported undefined (type reflect.StructField has no field or method IsExported)
note: module requires Go 1.17
# golang.org/x/net/http2
/root/go/pkg/mod/golang.org/x/net@v0.0.0-20220722155237-a158d28d115b/http2/transport.go:416:45: undefined: os.ErrDeadlineExceeded
note: module requires Go 1.17
# sigs.k8s.io/controller-tools/pkg/loader
/root/go/pkg/mod/sigs.k8s.io/controller-tools@v0.9.2/pkg/loader/loader.go:487:5: undefined: os.DirEntry
/root/go/pkg/mod/sigs.k8s.io/controller-tools@v0.9.2/pkg/loader/loader.go:545:14: undefined: filepath.WalkDir
note: module requires Go 1.17
手动安装到大于1.17版本,否则如下
$ make deploy IMG=easydl/elasticjob-controller:master
dlrover/dlrover/go/operator/bin/controller-gen rbac:roleName=manager-role crd webhook paths="./..." output:crd:artifacts:config=config/crd/bases
api/v1alpha1/groupversion_info.go:24:2: zip: not a valid zip file
pkg/common/resource.go:29:2: zip: not a valid zip file
pkg/controllers/elasticjob_controller.go:31:2: zip: not a valid zip file
pkg/controllers/elasticjob_controller.go:32:2: zip: not a valid zip file
pkg/controllers/scaleplan_controller.go:33:2: zip: not a valid zip file
pkg/controllers/elasticjob_controller.go:34:2: zip: not a valid zip file
pkg/controllers/scaleplan_controller.go:35:2: zip: not a valid zip file
main.go:29:2: zip: not a valid zip file
main.go:25:2: zip: not a valid zip file
main.go:31:2: zip: not a valid zip file
main.go:32:2: zip: not a valid zip file
Error: not all generators ran successfully
$ make deploy IMG=easydl/elasticjob-controller:master
...
Error: err: exit status 1: stderr: go: updates to go.mod needed; to update it:
go mod tidy
...
$ go mod tidy
go mod tidy: go.mod file indicates go 1.18, but maximum supported version is 1.17
手动安装1.18版本以上的GO,比如Go1.21
由于大模型相关的从业人员大多是Python好手,对Go了解甚少,所以补充Go 的安装及配置;
前往https://golang.google.cn/dl/ 下载对应的版本包;解压到/usr/share/bin下;
tar -xf go.gz -C /usr/share/bin
# 检查go 是否正确安装比如go path 、version等
go env
配置环境变量
export GOPATH=$HOME/go
export PATH=$PATH:$GOPATH/bin
最好配置到shell 配置文件(如 ~/.bashrc 或 ~/.zshrc)中;
source ~/.bashrc
或者
source ~/.zshrc
使之生效;
安装go之后,需要配置go proxy,以免执行go get等操作时前往外网拉取包导致网络不通|缓慢 timeout甚至fail;
一般使用七牛云即可;
echo 'export GOPROXY=https://goproxy.cn,direct' >> ~/.bashrc
source ~/.bashrc
https://github.com/intelligent-machine-learning/dlrover