• 【MindSpore易点通机器人-04】MLOps 环境搭建过程


    作者:王磊
    更多精彩分享,欢迎访问和关注:https://www.zhihu.com/people/wldandan

    在上一篇【MindSpore易点通机器人-03】迭代0的准备工作,我们从整体上概述了MindSpore易点通机器人项目开始前需要在迭代0的准备工作,本篇将会为大家讲述迭代0中具体的MLOps 环境搭建过程。整体的MLOps流水线设计如下图,包含持续训练流水线和CI/CD流水线。相关代码请参考MindSpore易点通机器人代码仓

    实际的技术选型上,我们基于Jenkins构建CI/CD流水线,基于Argo构建持续训练流水线。同时,我们把Jenkins和Argo都运行在K8S上来保证可用性和弹性。下文将为大家介绍如何在本地使用Minikube完成机器人项目的MLOps流水线的搭建,并在本地运行起来。

    具体的过程如下:

    1. 安装配置WSL+Ubuntu+Docker;
    2. 基于Minikube运行K8S;
    3. 基于K8S+Jenkins构建CI/CD流水线;
    4. 基于K8S+Argo持续训练流水线。

    1. 安装配置WSL+Ubuntu+Docker

    因为团队大部分人的开发环境都是Windows,所以需要选择WSL+Linux+Docker的方式。这里我们没有采用Docker Desktop+WSL Backend,而是利用Distord让Docker在Ubuntu上直接运行,相关的安装配置文档可以参考如何不安装Docker Desktop在WSL下运行Docker这篇文章。

    2. 基于Minikube运行K8S

    Minikube是一个单机安装配置K8S集群的工具,它支持多平台(Mac/Linux/Windows)。Minikube可以将K8S集群安装配置在单个Docker容器或者VM(hyper-v/VMWare等)中,过程也非常简单。首先在Ubuntu中安装Minikube:

    1. curl -LO https://storage.googleapis.com/minikube/releases/latest/minikube-linux-amd64
    2. sudo install minikube-linux-amd64 /usr/local/bin/minikube

    然后执行minikube start ,因为在第一步中我们已经配置好了Docker,Minikube在启动时会默认使用Docker作为VM,然后在容器中启动K8S集群。启动完成后在Ubuntu上使用docker ps只能看到一个容器:

    1. CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
    2. 699a71fee349 kicbase/stable:v0.0.30 "/usr/local/bin/entr…" 2 weeks ago Up 2 hours 127.0.0.1:49157->22/tcp, 127.0.0.1:49156->2376/tcp, 127.0.0.1:49155->5000/tcp, 127.0.0.1:49154->8443/tcp, 127.0.0.1:49153->32443/tcp minikube

    如果我们执行docker exec -it 699a71fee349进入容器后再执行docker ps,就能发现K8S集群的服务了:

    1. CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
    2. af45f3caa0d9 99a3486be4f2 "kube-scheduler --au…" 2 hours ago Up 2 hours k8s_kube-scheduler_kube-scheduler-minikube_kube-system_be132fe5c6572cb34d93f5e05ce2a540_1
    3. e648e7d30a7d Error 404 (Not Found)!!1 "/pause" 2 hours ago Up 2 hours k8s_POD_kube-apiserver-minikube_kube-system_cd6e47233d36a9715b0ab9632f871843_1
    4. e26d9e92c4e3 k8s.gcr.io/pause:3.6 "/pause" 2 hours ago Up 2 hours k8s_POD_kube-scheduler-minikube_kube-system_be132fe5c6572cb34d93f5e05ce2a540_1
    5. e658bf17922d Error 404 (Not Found)!!1 "/pause" 2 hours ago Up 2 hours k8s_POD_kube-controller-manager-minikube_kube-system_b965983ec05322d0973594a01d5e8245_1
    6. 1f85a9bae877 Error 404 (Not Found)!!1 "/pause" 2 hours ago Up 2 hours k8s_POD_etcd-minikube_kube-system_9d3d310935e5fabe942511eec3e2cd0c_1
    7. ....

    从容器中退出,安装kubectl之后就在Ubuntu上使用Kubectl管理集群了:

    1. curl -LO "https://dl.k8s.io/$(curl -L -s https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl.sha256"
    2. sudo install -o root -g root -m 0755 kubectl /usr/local/bin/kubectl

    执行kubectl get nodes,查询K8S管理的节点。

    1. ~$ kubectl get nodes
    2. NAME STATUS ROLES AGE VERSION
    3. minikube Ready control-plane,master 19d v1.23.3

    如果关注Kubernetes的界面,使用minikube dashboard就可以启动K8S的管理界面,并在Windows上通过浏览器访问 http://127.0.0.1:44185/api/v1/namespaces/kubernetes-dashboard/services/http:kubernetes-dashboard:/proxy/

    使用Minikube可以让我们在本地拥有一个和生产环境一样功能的K8S集群,但这种方式同样带来了网络的复杂性,如下图,Ubuntu运行在Hyper-v的虚机中,在K8S部署的服务运行在Ubuntu的Docker容器的容器中(Docker in Docker)。所以,如果要在Windows的浏览器上访问K8S中运行的服务,需要先通过kubectl port-forward完成Ubuntu VM和Minikube容器的端口映射,然后再使用minikube tunnel完成VM到Windows的端口映射。

    3. 基于K8S+Jenkins构建CI/CD流水线

    Jenkins是一个经久不衰的持续集成工具,它的插件生态比较强大。我们构建基于Jenkins+Kubernetes的CI/CD流水线要达到的目的如下:

    1. 基于K8S实现Jenkins的弹性部署;
    2. 基于Jenkins插件实现CI任务在K8S上的运行;
    3. 基于Pipeline as Code实现Jenkins的流水线配置管理(持续集成任务+持续部署任务)。

    基于K8S实现Jenkins的弹性部署

    MindSpore易点通机器人的代码仓已经给出了在K8S上部署Jenkins的配置文件,这里要设置成LoadBalancer类型。

    1. ---
    2. apiVersion: v1
    3. kind: Service
    4. metadata:
    5. name: jenkins
    6. spec:
    7. type: LoadBalancer
    8. selector:
    9. name: jenkins
    10. ports:
    11. -
    12. name: http
    13. port: 8080
    14. targetPort: 8080
    15. protocol: TCP

    再用kubectl create -n jenkins创建Jenkins的namespace,通过kubectl apply -f jenkins.yaml -n jenkins完成部署,然后用kubectl apply -f service-account.yaml -n jenkins完成API调用的授权。

    在配置文件中我们指定了对外暴露的端口是8080,所以可以用kubectl port-forward svc jenkins/jenkins 8080:8080 -n jenkins完成端口映射,再执行minikube tunnel就可以在浏览器中使用127.0.0.1:8080打开Jenkins界面了,初始密码可以在pod启动的日志中获得。

    基于Jenkins插件实现CI任务在K8S上的运行

    完成Jenkins在K8S上的部署后,需要在Jenkins中安装kubernetes插件,配置节点类型为K8S集群。从插件管理中先安装kubernetes插件,然后在节点管理中选择配置集群
    首先配置K8S集群的信息,因为在一个K8S集群,服务间都可以通过主机名的方式相互访问,所以“Kubernetes地址”配置只需要输入https://kubernetes.defaults,同时补充配置“Kubernetes命名空间”为jenkins,如下图所示。

    同理,对于“Jenkins地址”,只需要填入http://jenkins.jenkins:8080

    另一个要配置是pod模板,既任务运行的pod的基础镜像及相关信息配置。要同时运行Java和Python,所以在dockerhub找了一个Java和Python都有的镜像,如下图所示,保存后即可完成配置。

    基于Pipeline as Code实现Jenkins的流水线配置管理

    我们的最后一步是基于Jenkins的流水线即代码功能完成CI/CD流水线搭建,按照设计,它应该包含如下任务:

    • 持续集成流水线
      • 代码检查:数据处理代码、模型代码、推理代码以及脚本代码规范检查任务
      • 单元测试:数据处理逻辑、模型代码逻辑、推理代码逻辑的单元测试任务
      • API测试:推理接口功能测试
      • 训练触发:如果修改了训练代码,触发Argo的训练流水线
    • 部署

    使用Jenkins流水线即代码功能,对应的配置如下:

    1. pipeline {
    2. agent {
    3. kubernetes {
    4. containerTemplate {
    5. name 'python'
    6. image 'bitnami/java:1.8'
    7. command 'sleep'
    8. args 'infinity'
    9. }
    10. defaultContainer 'python'
    11. }
    12. }
    13. stages {
    14. stage('Code Check ') {
    15. steps("Code Check") {
    16. echo 'checking python code.'
    17. }
    18. }
    19. stage('Unit Testing') {
    20. steps("Unit Testing") {
    21. echo "running unit tests"
    22. }
    23. }
    24. stage('API Testing') {
    25. steps {
    26. echo 'running inference API Testing'
    27. }
    28. }
    29. stage('Training Trigger') {
    30. when {
    31. changeset "src/train/*.py"
    32. }
    33. steps("trigger training") {
    34. echo 'trigger new round of training'
    35. }
    36. }
    37. }
    38. }

    部署流水线的pipeline脚本如下:

    1. pipeline {
    2. agent any
    3. stages {
    4. stage('Packaging') {
    5. steps("Packaging") {
    6. echo 'packaging with model and inference code'
    7. }
    8. }
    9. stage('Continuous Deployment') {
    10. steps("deploying") {
    11. echo 'deploy new version of model'
    12. }
    13. }
    14. }
    15. }

    配置文件中每个step先置空,是为了方便调试。在Jenkins基于上面的配置文件创建一个流水线后的测试结果如下:

    4. 基于K8S+Argo持续训练流水线

    Argo是一个基于K8S的开源的工作流管理工具,也支持机器学习的工作流。MindSpore DX Sig已经在先前的社区机器人项目中使用了该工具,所以这里我们复用了工具和配置。Argo Workflow的安装配置如下:

    1. 在K8S上安装Argo;
    2. 基于Argo Workflow 配置机器学习流水线;
    3. 运行机器学习流水线。

    1. 在K8S上安装Argo

    首先,我们执行kubectl create -n argo为Argo创建新的命名空间。然后,基于配置文件,执行kubect apply -f install.yml -n argo完成安装。最后,执行kubect apply -f manifests/create_serviceaccount.yaml -n argo完成权限配置。

    和前面的Jenkins配置类似,Argo Server需要设置为LoadBalancer类型。

    1. apiVersion: v1
    2. kind: Service
    3. metadata:
    4. name: argo-server
    5. spec:
    6. ports:
    7. - name: web
    8. port: 2746
    9. targetPort: 2746
    10. type: LoadBalancer
    11. sessionAffinity: None
    12. externalTrafficPolicy: Cluster
    13. selector:
    14. app: argo-server

    执行kubectl get svc -n argo可以看到:

    1. ~$ kubectl get svc -n argo
    2. NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
    3. argo-server LoadBalancer 10.97.145.232 127.0.0.1 2746:30001/TCP 19d
    4. workflow-controller-metrics ClusterIP 10.99.196.47 <none> 9090/TCP 19d

    如果要在Windows的浏览器上访问Argo的Web界面,则还需要把argo-server的端口暴露出来,同上使用kubectl port-forward svc/argo-server 2746:2746 -n argo完成端口映射。然后浏览器上访问https://127.0.0.1:2746,通过下面的脚本获得密码,登录后就可以正常使用Argo的Web管理界面了。

    1. #!/bin/bash
    2. SECRET=$(kubectl get sa argo-server -n argo -o=jsonpath='{.secrets[0].name}')
    3. ARGO_TOKEN="Bearer $(kubectl get secret $SECRET -n argo -o=jsonpath='{.data.token}' | base64 --decode)"
    4. echo $ARGO_TOKEN

    2. 基于Argo Workflow 配置机器学习流水线

    我们期望训练的工作流可以完成以下任务:

    1. 数据处理
    2. 训练
    3. 评估
      1. 质量评估:基于测试集数据评估模型,预测性能需要高于基线值
      2. 可解释性评估
      3. 可靠性评估
    4. 总结

    基于工作流的设计以及Argo工作流语法,可以得出基础的配置:

    1. apiVersion: Page Not Found
    2. kind: Workflow
    3. metadata:
    4. generateName: robot-train-eval-
    5. spec:
    6. serviceAccountName: robot-sa
    7. entrypoint: robot-controller
    8. onExit: summary
    9. templates:
    10. - name: robot-controller
    11. steps:
    12. - - name: data-process
    13. template: process
    14. - - name: robot-train
    15. template: train
    16. - - name: robot-eval
    17. template: eval
    18. - name: robot-interpretability
    19. template: interpretability
    20. - name: robot-reliability
    21. template: reliability
    22. - - name: summary
    23. template: summary

    而后,展开每个任务需要的配置,如训练的配置代码:

    1. - name: train
    2. container:
    3. image: ubuntu
    4. imagePullPolicy: Always
    5. env:
    6. - name: IS_TRAIN
    7. value: "True"
    8. - name: NUM_STEPS
    9. value: "10"
    10. command: ['echo']
    11. args: ["trainning"]
    12. ...

    把每个阶段的任务汇总在一起就完成了整个的工作流。接下来,我们尝试使用Argo运行下训练流水线。

    3. 运行机器学习流水线

    可以使用Argo CLI的客户端完成工作流任务的提交,首先安装客户端:

    1. #!/bin/bash
    2. # Download the binary
    3. curl -sLO https://github.com/argoproj/argo-workflows/releases/download/v3.3.5/argo-linux-amd64.gz
    4. # Unzip
    5. gunzip argo-linux-amd64.gz
    6. # Make binary executable
    7. chmod +x argo-linux-amd64
    8. # Move binary to path
    9. mv ./argo-linux-amd64 /usr/local/bin/argo

    然后通过argo cli提交工作流argo submit -n robot --watch robot-train-eval.yaml,执行结果如下,和我们期望的流水线步骤一致。

    总结

    本篇文章总结了如何在本地完成MLOps环境的搭建,基于Minikube、Argo等工具可以让我们很好的在本地展开开发验证工作,不用依赖复杂的基础设施,也不用有额外的开销。在配置文件中和脚本中,我们没有加真实的实现,是为了先打通流程,然后再将调试好内容逐步补充进去,始终都可以从端到端的角度来完成验证。

    说明:严禁转载本文内容,否则视为侵权。

  • 相关阅读:
    pytorch 多GPU训练总结(DataParallel的使用)
    面向对象基础
    图形系统开发实战课程:进阶篇(上)——6.图形交互操作:拾取
    PLC模拟量输入 模拟量转换FC S_ITR (CODESYS平台)
    【NodeJs-5天学习】第二天篇② —— 网络编程(TCP、HTTP、Web应用服务)
    家庭记账的最简单方法
    关于C语言编译环境
    go的面向对象学习
    运营干货:虾皮店铺装修怎么做?
    c++中的重载
  • 原文地址:https://blog.csdn.net/Kenji_Shinji/article/details/126478004