Kubeflow 部署采坑记录

时间:2022-07-22
本文章向大家介绍Kubeflow 部署采坑记录,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

Kubeflow = Kubernetes + Machine Learing + Flow

1 Overview

Kubeflow 是在 K8S 集群上跑机器学习任务的工具集,提供了 Tensorflow, Pytorch 等等机器/深度学习的计算框架,同时构建容器工作流 Argo 的集成,称为 Pipeline。关于其部署,最新版本的本地部署有很多问题,Github 上的 issue 大多数都是与部署有关的,所以如果不是在 GCP 上部署,会可能碰到各种各样的问题。

之所以对 GCP 支持这么好,是因为 Kubeflow 是 Google 内部机器学习工作流的开源版本,但是投入的核心开发者不多,版本更新和问题修复只有几个人在做。

部署之前,请先了解几个关于 ksonnet 的概念。

  1. registry: ksonnet 的模板仓库,可以是离线也可以是线上,只要能访问即可
  2. env: registry 注册在 env 下,通过 env 切换部署模板的仓库
  3. pkg: registry 里放着的是模板,里面包含了 protoypes 和 library
  4. prototype: 本文统一叫组件,可以配置不同的 param
  5. library: 包含了 k8s 的 Api 信息,不同版本的 k8s 的 Api 不同
  6. param: 用于填充模板的参数
  7. componet: 填充了参数的模板,本文统一叫组件

2 Deploy

Kubeflow 的官方文档提供了各种平台的部署方案。

https://www.kubeflow.org/docs/started/

部署方面,Kubeflow 利用了 Ksonnet,他是一个方便管理 K8S yaml 的工具。

https://ksonnet.io/

因为光用 Kubeflow 提供的部署脚本,遇到问题,还是得用 ks 命令看看的,所以有必要熟悉一下(后面会结合例子稍微讲下)。

2.1 本地部署

首先需要搞清楚,利用脚本一键部署的组件有哪些,需要花点时间去了解各个组件,否则排错的时候,根本无从下手。

# ks component list
COMPONENT           TYPE    我补充的信息,未必准确
=========           ====    ========== ==== ====
ambassador          jsonnet Kubeflow 的认证统一网关和路由
application         jsonnet 组件太多了,这个是做集成的 CRD
argo                jsonnet 容器任务调度
centraldashboard    jsonnet Kubeflow 的入口 UI
jupyter             jsonnet jupyter
jupyter-web-app     jsonnet jupyter hub
katib               jsonnet 用于深度学习调参的组件
metacontroller      jsonnet 也是一个内部的 CRD
notebook-controller jsonnet hub 里可以增加多个 notebook,也是一个 CRD
notebooks           jsonnet jupyter nootbook
openvino            jsonnet 
pipeline            jsonnet pipeline 集成 
profiles            jsonnet 用户权限和认证方面的组件
pytorch-operator    jsonnet 一个深度学习的框架
spartakus           jsonnet
tensorboard         jsonnet 
tf-job-operator     jsonnet tensorflow 任务的 CRD

这么多组件部署起来是非常麻烦的,官方给力一个脚本,但是光有脚本不够用的,出问题,还是得看看脚本内容,简单说一下结构。

必须确保版本下载正确,否则排错又是一推问题…

下载完就有三个文件夹。重点看看脚本文件夹。部署关键在两个脚本,kfctl.sh/util.sh。

因为脚本实在太长了,而且 gcp/aws/minkube 所有平台都混合一起的,重点还是要看关于 ks 的部分,因为部署的核心是用到的是 kssonet。

关于 ksonset,上图是非常经典的,模板是一个缺了一些部分的圆柱,比如 yaml 中的 image,meta.name 之类的参数,第二部分是这几个参数的抽象化,通过 kssonet 就把最终的圆柱补齐了,最后结合成一个完成的 yaml 文件,可以用 kubectl apply -f xxx.yaml,或者用 kssonet 的命令 ks apply -c <组件>

通过 grep 把关键的 ks 相关的命令抓出来。

# 运行这个命令,找到 ks 相关的命令 cat util.sh| grep "ks"
# All deployments should call this function to create a common ksonnet app.
# Create the ksonnet app
# 初始化 ks 项目的目录,注意 ${KS_INIT_EXTRA_ARGS} 后面还会提到
eval ks init $(basename "${KUBEFLOW_KS_DIR}") --skip-default-registries ${KS_INIT_EXTRA_ARGS}
# 也是非常重要的,先删除默认的环境,这里 default 代理了 ks 的 registry
ks env rm default
# 注册 registry,后面的部分会跟前面几条一起描述
ks registry add kubeflow "${KUBEFLOW_REPO}/kubeflow"
# 从这里开始是安装各种 ks 组件模板,还没多大用处,必须 generate
ks pkg install kubeflow/argo
ks pkg install kubeflow/pipeline
ks pkg install kubeflow/common
ks pkg install kubeflow/examples
ks pkg install kubeflow/jupyter
ks pkg install kubeflow/katib
ks pkg install kubeflow/mpi-job
ks pkg install kubeflow/pytorch-job
ks pkg install kubeflow/seldon
ks pkg install kubeflow/tf-serving
ks pkg install kubeflow/openvino
ks pkg install kubeflow/tensorboard
ks pkg install kubeflow/tf-training
ks pkg install kubeflow/metacontroller
ks pkg install kubeflow/profiles
ks pkg install kubeflow/application
ks pkg install kubeflow/modeldb
# generate 命令是用来把参数填充到模板里的,构成前面说的完成的 yaml 
# 注意这些组件不能一一对应前面的模板的,因为有些组件里包含了几个模板的参数
ks generate pytorch-operator pytorch-operator
ks generate ambassador ambassador
ks generate openvino openvino
ks generate jupyter jupyter
ks generate notebook-controller notebook-controller
ks generate jupyter-web-app jupyter-web-app
ks generate centraldashboard centraldashboard
ks generate tf-job-operator tf-job-operator
ks generate tensorboard tensorboard
ks generate metacontroller metacontroller
ks generate profiles profiles
ks generate notebooks notebooks
ks generate argo argo
ks generate pipeline pipeline
ks generate katib katib
# cd ks_app
# ks component rm spartakus
# generate 命令还可以带参数的
ks generate spartakus spartakus --usageId=${usageId} --reportUsage=true
ks generate application application

真正通过 yaml 来创建 K8S 的资源的是在 kfctl.sh 脚本中,先通过同样的方法找出 ks 相关的命令。

# 运行命令 cat kfctl.sh| grep "ks"
# 这里指定 application 需要包括的组件
# 上面提到了 applicaiton 是一个 crd,因为 kubeflow 
# 的组件太多了,所以要有个工具统一管理
ks param set application components '['$KUBEFLOW_COMPONENTS']'
#
#
#
# 下面是脚本里最后关键的步骤,请注意!!
#
#
#
# ks show 可以结合组件生成 yaml 文件
ks show default -c metacontroller -c application > default.yaml
# 然后可以看到,即使是这么复杂的 Kubeflow,依然是通过 kubectl apply 来构建
# 所以有需要的话,一定要看看 default.yaml 文件
# default 文件内容非常多,不同版本,应该在5000~9000行
kubectl apply --validate=false -f default.yaml

P.S. ks 命令没有全部列出,如需要 debug 来需要仔细看看脚本

2.2 init 过程

通过脚本 init

./kfctl.sh init myapp

init 完之后,还要 check 版本的问题。

2.2 generate 过程

# 注意目录
cd myapp
../kfctl.sh generate all

generate 之后,也同样 Check 版本信息。

2.3 apply 过程

# 注意目录
../kfctl.sh apply all

2.4 部署成功

查看 pod 情况。

查看 svc 情况。

访问 UI。

kubectl port-forward svc/ambassador 8003:80 -n kubeflow

查看 Pipeline。

运行一个 Pipeline 的 DAG。

查看 tf-job-dashboard。

提交一个 tf-job。通过官方提供的组件 example,里面有几个例子。可以通过以下方法安装这几个组件。

# 注意需要目录在前面生成的 ks_app
ks generate tf-job-simple-v1beta2 tf-job-simple-v1beta2
ks apply default -c tf-job-simple-v1beta2

这样就提交了几个任务了,本质上也是通过 ks 生成 yaml,然后 ks apply 就相当于 kubectl apply 了。

2.5 删除

# 注意目录
../kfctl.sh delete all

3 必须要注意的问题

  1. 一定要确认下载/安装 Kubeflow 的过程中,Kubeflow 的版本问题,因为其版本前后有比较大的差别!
  2. 生成模板的时候,需要注意 K8S 的版本!可以在脚本中指定,见附录。

如果不打算部署整套 Kubeflow,可以只部署 Jupyter,tf-operator 等等。

4 部署失败的原因

  1. 如果需要完整部署,需要创建多个 K8S 资源,需要较多的资源,本地不一定能部署起来,GCP 建议需要 16 核
  2. 版本问题,包括 K8S 版本,ksonnet 版本,镜像版本等等
  3. 离线问题,原则上,只要部署好 K8S 脚本,image 都在本地,部署脚本已经获取,是不需要联网部署的

常见问题包括 Github 无法访问,需要下载 K8S 的 swagger.json 文件等等。

完整部署一套 Kubeflow 代价太大,一是官方文档整理的逻辑不够清晰,更新不及时,二是包含太多组件了,如果对某些组件不熟悉,出问题了是很不好排查的。部署的话,最好是通过各云厂商的来部署,相对而言,Kubeflow 对各厂商的部署脚本的问题,处理起来比本地用户会更积极一些。当然了,在 GCP 上,体验应该是最好的。

附录

# ks 需要读取到 .kube/config 文件
# init 需要确定 ks registry,离线安装需要 k8s 的 swagger.json
eval ks init $(basename "${KUBEFLOW_KS_DIR}") --skip-default-registries --api-spec=file:/tmp/swagger.json
# 
# 可以指定 server,确定 k8s 的版本
ks env add default --server=https://shmix1.k8s.so.db --api-spec=file:/tmp/swagger.json
#
# 注意每次运行脚本的信息
++ ks env describe default
+ O='name: default
kubernetesversion: v1.14.3
path: default
destination:
  server: https://kubernetes.docker.internal:6443
  namespace: kubeflow
targets: []
libraries: {}'
#
#
# 完整部署脚本
#
#
export KUBEFLOW_VERSION=v0.5.0
curl https://raw.githubusercontent.com/kubeflow/kubeflow/${KUBEFLOW_VERSION}/scripts/download.sh | sh
cd scripts
./kfctl.sh init myapp
cd myapp
../kfctl.sh generate all
../kfctl.sh apply all