Kubeflow--Pipeline及Argo实现原理速析

本文解析了Argo如何在Kubernetes上实现容器间的信息传递,重点介绍了KubeFlow Pipeline如何在Argo基础上增强流程管理和用户体验。讨论了Argo的局限性和KubeFlow的改进策略,包括扩展性、生产级可靠性和安全措施。

原文地址:

KubeFlow-Pipeline及Argo实现原理速析_容器_华为云开发者社区_InfoQ精选文章

摘要

Argo是一个开源原生容器工作流引擎 用于在Kubernetes上开发和运行应用程序。Argo Workflow流程引擎,可以编排容器流程来执行业务逻辑,在20年4月进入CNCF孵化器组。

KubeFlow的Pileline子项目,由Google开源,其全面依赖Argo作为底层实现,并增强持久层来补充流程管理能力,同时通过Python-SDK来简化流程的编写。

Argo 流程引擎

Argo的步骤间可以传递信息,即下一步(容器)可以获取上一步(容器)的结果。结果传递有 2 种:

  • 文件:上一步容器新生成的文件,会直接出现在下一步容器里面
  • 信息:上一步的执行结果信息(如某文件内容),下一步也可以拿到

下面我们就来解读一下,Argo 怎么实现“信息”在容器间的传递的,以及它和其他的流程引擎实现传递的区别。

文件怎么从上一个容器跑到下一个容器里

Argo流程,可以指定2个步骤之间,传递结果文件(Artifact)。即假设流程为:A->B,那么 A 容器跑完,B 容器可以取得上一个容器的输出文件。

如下:A 容器生成一个 /tmp/hello_world.txt 文件,Argo 将这个文件,放到了 B 容器里面,并重命名为 /tmp/message 文件。

注意:流程上的每个步骤,都对应执行一个容器。 在 A 跑完后容器就退出了,然后才跑的 B(这时候已经没有 A 容器在运行了)。

所以 Argo 怎么把一个文件从 A 容器“拷贝”到 B 容器里面的?

容器间通过共享存储?(NO)

一般容器间共享文件,首先想到的都是:咱使用共享存储呀,大家都挂载同一个 PVC 不就行了。

 确实共享存储可以实现容器共享文件,但是这里 Argo 需要:

(1)任意指定文件传递。(2)传递后文件可以改名字。

这2个条件是共享Volume做不到的,毕竟容器挂载目录得提前设定好,然后文件名大家看到的也是一样。所以显然文件传递,不是通过共享PVC挂载实现的。

(PS:不过 Argo 也在考虑这种实现方式,毕竟共享目录不需要任何额外 IO,透传效率更高。见:Volume-based artifact passing system · Issue #1349 · argoproj/argo-workflows · GitHub

通过管理面中转?(YES)

 没有共享目录,那中转文件,只能是通过先取出来,再塞回去的方式喽。实际上 Argo 也确实这么做的,只是实现上还有些约束。

  1. “临时中转仓库”需要引入第三方软件(Minio)
  2. 文件不能太大
  3. 需要在用户容器侧,增加“代理”帮忙上传&下载文件

中转文件具体实现(docker cp)

现在我们打开Argo看看具体怎么实现的。因为你要取一个容器里面的文件,或者把一个文件放入容器,也不容器实现。

  1.  小滑头Argo居然给用户容器设置了一个SideCar容器,通过这个SideCar去读取用户的文件,然后上传到临时仓库
  2. 一个 Pod 里面的两个 Container,文件系统也是独立的,并不能直接取到另一个 Container 的文件。所以Sidecar容器为了取另一个容器里的文件,又把主机上面的docker.sock挂载进了。这样就相当于拿到Root权限,可以任意cp主机上任意容器里面的文件。

事实上,Sidecar里面取文件的实现是:

docker cp -a 023ce:/tmp/hello_world.txt - | gzip > /argo/outputs/artifacts/hello-art.tgz

感觉稍微有点暴力。

中转实现的其他方式

实际上,通过 sidecar 容器提权到 root 权限,然后从用户的容器里面 copy 任意文件(即 docker cp 命令),只是 Argo 默认的实现。毕竟它自己也发现这样做安全上有点说不过去。

所以呢,它也留了其他方式去 copy 用户容器里面的文件。比如:kubectl 也是可以 cp 容器里面的文件的嘛。其他方式可参见:argo-workflows/workflow-executors.md at master · argoproj/argo-workflows · GitHub

下一步容器怎么拿到上一步容器的结果

Argo 流程,2 个步骤之间,除了传递文件,还可以传递结果信息(Information)。如:A->B,那么 A 容器跑完,B 容器可以取得上一个容器的一些 Information(不是整个文件)。

一般流程引擎透传信息,都是中转:

 不过显然 Argo 自己没有存储 Information 的临时仓库,所以它得找个地方记录这些临时待中转的 information(虽然 Argo 找了 Minio 这个对象存储用来暂存中转文件,但是显然这货只能存文件,没有存 Metadata 元数据功能)。 这里Argo又找了Pod里面的Annotation字段,当做临时中转仓库。先把信息记这里,下一步容器想要,就来这里取

 相信这里应该是有更好的实现方式的,这种把信息记录到 Annotation 的做法,约束比较大的(特别是 ETCD 的单个对象不能超过 1M 大小)。

 可以考虑使用单独的 Configmap 来中转也可以。

Kubeflow-Pipeline项目

KubeFlow-Pipeline 项目(简称 KFP),是 Kubeflow 社区开源的一个工作流项目,用于管理、部署端到端的机器学习工作流。KFP 提供了一个流程管理方案,方便将机器学习中的应用代码按照流水线的方式编排部署,形成可重复的工作流。

为什么要在Argo之上重新开发一套?

部署一套 Argo 很简单,启动一个 K8s-Controller 就行。可是部署一套 Kubeflow-Pipeline 系统就复杂多了,总共下来有 8 个组件。那是 Argo 什么地方不足,需要新开发一套 KFP,并搞这么复杂呢?主要的原因还在于 Argo 是基于K8s云原生这套理念,即ETCD充当“数据库”来运行的,导致约束比较大。

像:流程模板,历史执行记录,这些大量的信息很明显需要一个持久化层(数据库)来记录,单纯依赖 ETCD 会有单条记录不能超过 1M,总记录大小不能超过 8G 的约束。

所以一个完整的流程引擎,包含一个数据库也都是很常规的。因此KFP在这一层做了较大的增强。

另外,在ML的领域的用户界面层,KFP也做了较多的用户体验改进。包括可以查看每一步的训练输出结果,直接通过UI进行可视化的图形展示

​​​​​​Visualize Results in the Pipelines UI | Kubeflow

Kubeflow-Pipeline 后续演进点

参见: ml-pipeline memory leak and no HPA support · Issue #3550 · kubeflow/pipelines · GitHub

Dag 引擎组件的水平扩展(HPA)是其重要的一个特性,也是要成为一个成熟引擎所必要的能力。

当前 KFP 在稳定性以及组件的水平扩展上都还有待改进,因此商业使用还需要一段时间,这将是 KFP 未来的一个重要目标。

同时,使用权限过于高的 Sidecar 容器作为其实现步骤之间元数据传递的途径,也会是 KFP 生产级使用的一道门槛。或许在权限控制方面,KFP 需要思考一下其他规避途径,至少需要稍微增强一下。

概括一下:(1)水平扩展(HPA),(2)生产级可靠性,(3)安全增强

流程引擎核心 & 分层

DAG核心

一个 DAG 流程引擎,核心代码也就 7 行大概能实现了:

例如下图示例:遍历发现步骤 D 没有依赖其他步骤,那么本次可以执行 D 步骤。

所以一般程序员一周时间总能开发一个“还能用”的流程引擎。但是完整的流程引擎却并不轻松

世界上为什么有这么多的流程引擎

DAG 基础核心非常简单,同时,各个领域想要做的事情却迥然不同。即使一个简单的步骤,大数据步骤说:“这一步要执行的 SQL 语句是 xxx”,而 K8s 任务步骤却说:“这一步执行需要的 Docker 镜像是 yyy”。

所以,各种各样的流程引擎就自然的出现了。

举几个例子:

  • AWS:Cloudformation 编排,Batch 服务,SageMaker-ML Pipeline,Data Pipeline
  • Azure:Pipeline 服务,ML Pipeline,Data Factory
  • Aliyun:函数 Pipeline 服务,ROS 资源编排,Batch 服务,PAI-Studio
  • 大数据领域:Oozie,AirFlow
  • 软件部署:Puppet,Chef,Ansible
  • 基因分析:DNAnexus,NextFlow,Cromwell

每个领域总能找出一两个流程引擎,来控制谁先干活谁后干活。

总结一下:

(1)DAG 引擎核心很小

(2)各领域步骤的描述方式不一样

这就是为什么各个领域,总会有一个自己的流程引擎,而不像 K8s 能一统容器平台一样,出现一个能一统江湖的流程引擎。

DAG 引擎分层架构

成熟的流程引擎,应该有如下4层架构:

 第一层:用户交互层。如:模板语法规则,Console 界面等

 第二层: API 持久化层。如:模板记录,历史执行记录等

 第三层:引擎实例层。如:能否水平扩容,流程是否有优先级等

 第四层:驱动层。如:一个步骤能干什么活。跑一个容器还是跑一个Spark任务。

基本比较成熟的引擎都符合这种架构,例如 AirFlow 流程引擎,华为云的应用编排(AOS)引擎,数据湖工厂(DLF)引擎等都是如此。

目前 Argo 以及 Kubeflow-Pipeline 在引擎核心组件的水平扩展上,也即第三层引擎能力层稍有不足。同时其驱动层,目前也只能对接 K8s(即只能跑容器任务)。在选型的时候需要考虑进去。

<think>好的,我现在需要帮助用户解决他们遇到的Kubernetes配置问题。用户提供的配置片段中使用了subPath,但运行时出现了“no such file or directory”的错误。我需要仔细分可能的原因,并给出解决方案。 首先,回顾用户提供的配置: ``` volumeMounts: - mountPath: /archives/admin name: kubeflow-archives subPath: admin volumes: - name: kubeflow-archives persistentVolumeClaim: claimName: kubeflow-archives ``` 这里,用户将名为kubeflow-archives的PVC挂载到容器的/archives/admin路径,并指定了subPath为admin。错误提示是系统找不到/data/k8s/kubeflow/pipeline/archives这个路径,但用户配置中的挂载路径是/archives/admin,这似乎不一致。我需要考虑这个路径差异的可能原因。 接下来,可能的原因有几个方面: 1. **subPath与PVC根目录结构不匹配**:subPath指定的子目录admin在PVC对应的存储中不存在。例如,如果PVC挂载到节点的/data/k8s/kubeflow/pipeline,而PVC中没有创建admin子目录,那么容器内挂载时就会报错。 2. **节点上的路径权限问题**:即使admin子目录存在,也可能因为权限问题导致容器无法访问该目录。需要检查目录的权限和所有者是否正确。 3. **Volume挂载路径冲突**:如果其他容器或Pod已经挂载了相同的路径,可能会导致冲突,但这种情况可能不太常见,不过也需要考虑。 4. **配置中的路径错误**:用户提到的错误信息中的路径是/data/k8s/kubeflow/pipeline/archives,而配置中的挂载路径是/archives/admin,可能存在配置中的路径与实际节点路径之间的映射问题。例如,可能PVC实际挂载到节点的路径是/data/k8s/kubeflow/pipeline,而subPath应该相对于该路径。如果PVC的根目录没有archives/admin的结构,就会导致错误。 现在需要逐一分这些可能性。首先,用户应该确认PVC对应的存储后端(如NFS、HostPath、云存储等)中是否存在admin子目录。例如,如果PVC使用的是HostPath,节点上的路径是/data/k8s/kubeflow/pipeline,那么在该路径下必须存在archives/admin目录,或者根据subPath的配置,可能需要检查PVC根目录下的结构是否正确。 另一个可能的问题是subPath的使用方式。当使用subPath时,容器内挂载的路径会是PVC根目录下的指定子目录。例如,如果PVC根目录是/data/k8s/kubeflow/pipeline,而subPath设置为admin,那么容器内的/archives/admin实际上对应的是节点上的/data/k8s/kubeflow/pipeline/admin。但如果用户期望的是节点上的路径是/data/k8s/kubeflow/pipeline/archives/admin,那么可能需要调整subPath为archives/admin,或者在PVC的根目录下创建相应的目录结构。 此外,用户可能混淆了挂载路径和节点上的实际路径。例如,如果PVC的存储卷在节点上的挂载点是/data/k8s/kubeflow/pipeline,而subPath设置为admin,那么容器内的/archives/admin会对应节点上的/data/k8s/kubeflow/pipeline/admin。如果该路径不存在,就会报错。因此,用户需要确保在PVC的根目录下存在相应的子目录结构。 解决方案可能包括: - 在PVC的存储后端创建所需的子目录结构,例如创建admin目录。 - 调整subPath的值,以匹配现有的目录结构。 - 检查目录权限,确保容器有权限访问该目录。 - 如果不需要subPath,可以去掉subPath,直接将整个PVC挂载到容器路径,然后在容器内使用相对路径。 还需要考虑是否用户错误地将subPath设置为了错误的层级,或者PVC的claimName是否正确,以及PVC是否已经正确绑定到PV,并且PV的后端存储配置正确。 总结来说,关键点在于subPath对应的目录在PVC存储中是否存在,以及路径是否正确。用户需要检查存储后端的具体路径,并确保子目录存在,或者调整subPath的值以适应现有的目录结构。</think>在Kubernetes配置中使用$subPath$时出现路径错误,通常由以下原因导致。我们通过分层定位逐步解决: --- ### 一、错误现象分 ```log Error: stat /data/k8s/kubeflow/pipeline/archives: no such file or directory ``` 这个报错表明: 1. 宿主机(Node)上路径`/data/k8s/kubeflow/pipeline/archives`不存在 2. 该路径与你的`subPath: admin`配置存在**层级错位** --- ### 二、核心原理:subPath的作用机制 当配置如下时: ```yaml volumes: - name: kubeflow-archives persistentVolumeClaim: claimName: kubeflow-archives # 假设对应宿主机路径为 /data/k8s/kubeflow/pipeline volumeMounts: - mountPath: /archives/admin # 容器内路径 name: kubeflow-archives subPath: admin # 宿主机侧实际路径 = PVC根路径 + subPath ``` - **最终宿主机路径** = $PVC根路径 + subPath$ 例如:若PVC根路径是`/data/k8s/kubeflow/pipeline`,则实际路径为: $$ \text{/data/k8s/kubeflow/pipeline} + \text{admin} = \text{/data/k8s/kubeflow/pipeline/admin} $$ - 但报错显示系统在寻找`/data/k8s/kubeflow/pipeline/archives`,说明路径层级不匹配 --- ### 三、根本原因定位 1. **路径结构错位** 你的`subPath: admin`指向了PVC根目录下的`admin`子目录,但报错显示系统期望在PVC根目录下存在`archives`目录,说明: - 预期路径应为:$PVC根路径/archives/admin$ - 当前实际路径为:$PVC根路径/admin$ 2. **目录未创建** PVC对应的存储后端(如NFS、HostPath等)未创建所需子目录 --- ### 四、解决方案 #### 方案1:修正subPath层级(推荐) ```yaml volumeMounts: - mountPath: /archives/admin name: kubeflow-archives subPath: archives/admin # 层级对齐 ``` - 宿主机侧路径变为:$PVC根路径/archives/admin$ - **需确保PVC根目录下已存在`archives/admin`目录** #### 方案2:直接挂载PVC根目录 ```yaml volumeMounts: - mountPath: /archives # 挂载整个PVC到容器内/archives name: kubeflow-archives # 删除subPath字段 ``` - 容器内通过`/archives/admin`访问目标目录 - 需确保PVC根目录下有`admin`子目录 --- ### 五、操作验证步骤 1. **检查PVC存储后端** ```bash # 登录到宿主机,检查PVC对应的物理路径 ls /data/k8s/kubeflow/pipeline ``` - 如果使用NFS等网络存储,需检查存储服务器上的目录结构 2. **创建缺失目录** ```bash mkdir -p /data/k8s/kubeflow/pipeline/archives/admin ``` 3. **检查目录权限** ```bash chmod 755 /data/k8s/kubeflow/pipeline/archives chown -R 1000:1000 /data/k8s/kubeflow/pipeline/archives # UID根据容器用户调整 ``` --- ### 六、附加建议 - 使用`kubectl describe pod <pod-name>`查看事件日志,确认Volume挂载状态 - 对于生产环境,建议在PVC初始化时自动创建目录(如通过Init Container) - 若使用动态存储供应(如StorageClass),需确认存储插件是否支持自动创建子目录 通过修正subPath层级或调整目录结构,即可解决该路径不存在的问题。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值