KubeVela篇12:自定义工作流步骤以及踩坑经验

原创 吴就业 205 0 2023-10-13

本文为博主原创文章,未经博主允许不得转载。

本文链接:https://wujiuye.com/article/81808166feb2400088f1128c7bc58f18

作者:吴就业
链接:https://wujiuye.com/article/81808166feb2400088f1128c7bc58f18
来源:吴就业的网络日记
本文为博主原创文章,未经博主允许不得转载。

官方提供的工作流步骤有限,另外,对于自研的PaaS平台,我们需要借助工作流步骤实现一些例如存量项目基础设施导入、项目环境初始化、平台组件共享基础设施需要解决的差异对比审核、基础设施漂移等。

如何定义一个工作流步骤

由于kubevela以Addon提供安装扩展,因此我们需要用Addon作为自定义工作流步骤的载体,通过Addon安装工作流步骤和升级、卸载工作流步骤。 自定义工作流步骤需要使用CUE语言,并且只能使用语言本身支持的操作和kubevela为我们提供的一系列内置操作。 假设我们自定义一个工作流步骤是调用一个接口做某件事情,如果接口返回0,就是需要暂停工作流步骤等待人工完成审核,如果接口返回1,就是审核通过需要恢复工作流步骤,如果返回2,就是审核被驳回,需要终止工作流。

这里我们需要用到官方提供的3个操作:

  1. 发送http请求的HTTPDo操作
  2. 暂停工作流步骤的Suspend操作
  3. 失败终止工作流的Fail操作

另外还需要依赖encoding/json库的序列化和反序列化操作。

apiVersion: core.oam.dev/v1beta1
kind: WorkflowStepDefinition
metadata:
  name: custom-ws
  namespace: vela-system
spec:
  schematic:
    cue:
      template: |
        import (
                "vela/op"
                "encoding/json"
        )
        
        reqBody: {
            ... // 省略
            stepId: ad123213 ## 让接口实现幂等,识别是同一个工作流发出的请求
        }

        http: op.#HTTPDo & {
          method: "POST"
          url: parameter.url
          request: {
                body: json.Marshal(reqBody) 
                header: "Content-Type": "application/json"
          }
        } 
        
        if http.response.statusCode != 200 {
          fail: op.#Fail & {
                message: "request of \(parameter.url) is fail: \(http.response.statusCode)"
          } 
        } 
        
        if http.response.statusCode == 200 {
          response: json.Unmarshal(http.response.body) 
          if response.code != 0 {
            exception: op.#Fail & {
               message: "request of \(parameter.url) is fail. code:\(response.code) msg:\(response.msg)"
            }
          }
          ## 状态为2失败终止工作流
          if response.code == 0 && response.data.status == 2 {
            terminated: op.#Fail & {
              message: "Manual handle terminated the workflow"
            }
          }
          ## 状态为0等待审核
          if response.code == 0 && response.data.status == 0 {
            diff: op.#Suspend & {
              message: "Suspend."
            }
          }
          ## 状态为1继续工作流,不需要写什么
        } 
        
        parameter: {
          url: *"http://127.0.0.1:8080/api/custom-ws" | string
        }

颠覆你正常逻辑的坑

如果你实践过上面的案例,或者实践过类似案例,那么你应该发现问题了。那就是工作流步骤首先被暂停了一下,然后:如果接口响应2,就立马失败了,我们都没执行vela workflow terminated命令;如果接口响应1,就继续走到下一个工作流步骤了,我们也没执行vela workflow resume命令。看起来就像是暂停方法没被执行一样。

这是因为kubevela执行工作流步骤的原理并不是我们理解的代码执行流程。工作流步骤的代码无法像我们写的go代码一样被kubevela挂起和恢复。工作流步骤的暂停是指不执行后面的代码,而工作流的恢复是指重新执行一次工作流步骤。

当工作流步骤中调用Suspend操作,首先会终止本次工作流的执行,然后修改状态为Suspend。由于controller只要监听到事件,如果工作流状态不是成功或失败或终止,都会执行一次工作流,工作流的未完成步骤也会执行,而被暂停的工作流步骤是未完成状态,因此也会被执行。

当我们执行vela workflow resume命令后,发现被暂停的工作流步骤又被执行一次。

但我们用官方的Suspend工作流步骤并不会重复执行,这是为什么呢。其实只是我们看到的结果是没有重复执行而已。官方文档可能也觉得这个解释起来有些难以用正常的逻辑理解,或者是因此用起来麻烦,因此并没有在参考手册-CUE操作符中给出Suspend这个操作符,我们是通过查看Suspend工作流步骤的定义找到的Suspend这个操作符。

为了解开这个疑惑,我们只能从源码找答案了。

源码位置: - 官方的Suspend工作流步骤定义:https://github.com/kubevela/kubevela/blob/master/charts/vela-core/templates/defwithtemplate/suspend.yaml - cue操作声明:https://github.com/kubevela/workflow/blob/main/pkg/stdlib/actions/v1/op.cue - go代码实现:https://github.com/kubevela/workflow/blob/main/pkg/providers/workspace/workspace.go

Suspend工作流步骤源码

我们找到Suspend操作对应的Go语言实现,从上面代码不难看出,该操作通过stepId(每次执行工作流步骤都会生成一个id)确保此步骤只会生效一次,多次执行不会有任务操作,而当执行vela workflow resume命令后,此工作流步骤的状态会变为Running,代码中有这样一句注释:“if it is already suspended before and has been resumed, we should not suspend it again.”。即多次重复执行Suspend操作实际会被忽略,当我们执行vela workflow resume后,重复执行不会导致工作流又被暂停,而是已经暂停过的工作流步骤不会再被执行,继续下一个工作流步骤了。

#云原生

声明:公众号、CSDN、掘金的曾用名:“Java艺术”,因此您可能看到一些早期的文章的图片有“Java艺术”的水印。

文章推荐

KubeVela完结篇:我为Terraform Controller贡献了3个PR

KubeVela于2020年年底开源,距离现在还未满三年时间,是一个非常年轻的产物。KubeVela是非常创新的产物,如OAM模型的抽象设计。所以也并未成熟,除了官方文档,找不到更多资料,在使用过程中,我们也遇到各种大大小小的问题。

KubeVela篇14:如何实现存量业务的基础设施导入Kubevela+Terraform

由于我们的使用场景是将基础设施资源定义成KubeVela的组件,一个terraform “module”对应的就是一个kubevela的组件,对应terraform-controller的一个Configuration资源。因此导入的最小粒度是组件,即一个terraform “module”。

KubeVela篇13:跨地域的多集群管理方案

随着公司全球化战略的布局,业务呈点状分布在亚太、美东、欧洲等多个地域,云原生kubevela在跨地域多集群管控方面也遇到网络上的互通问题。

KubeVela篇11:可持续测试应用部署之Mock基础设施

我们基于KubeVela开发的云原生应用交付平台,提供如初始化基础设施导入、中间件部署共用基础设施等相关能力的测试,需要依赖基础设施。虽然terraform是面向公司内部的混合云平台,但是测试都要跨部门配置效率太低了,而且这种模式无法支持持续测试。

KubeVela篇10:KubeVela 私有云Terraform Provider Addon插件开发指南

如何Debug Terraform Controller;如何让Configuration可以指向私有仓库;为云资源编写ComponentDefinition;验证流程是否跑通。

KubeVela篇09:KubeVela工作流步骤CUE模版和Go代码是怎么关联的

terraformProvider、multiclusterProvider、oamProvider、configprovider、kube这些provider的Install方法注册了很多操作处理方法。这些方法就是提供给CUE中调用的方法。