«

Argo Workflow 简介及对比(上)

image.png

[toc]

Argo Workflows 简介

Argo Workflows 是一个开源的 container-native 工作流引擎,用于在 Kubernetes 上编排并行作业,基于 Kubernetes CRD (自定义资源定义) 实现,支持:

注:Argo 当前已经作为孵化器项目正式加入 CNCF

使用 Argo Workflows 的好处:

Argo 基于 Kubernetes CRD 实现, 因此可以使用 kubectl 或 Argo CLI 管理 Argo 工作流,并与其他 Kubernetes 服务(如卷、机密、RBAC等)进行本地集成。Argo 是轻量级的,安装时间不到一分钟,并提供了完整的工作流特性,包括参数替换、工件、夹具、循环和递归工作流。

Argo Workflows 架构图

注:从 v2.5开始,Argo Workflow 支持两种运行模式:hostedlocal

image.png

Argo Workflows 功能点

Argo Workflows 详细示例

为了更好的了解 Argo Workflows 的用法,本文将详细的介绍它的使用例子,并在这个过程中对比 CNCF Serverless 的 Workflow 规范。

Argo CLI vs kubectl

Argo 提供了一个非常有用的 CLI 工具,简介如下:

argo is the command line interface to Argo

Usage:  
  argo [flags]
  argo [command]

Examples:

If you're using the Argo Server (e.g. because you need large workflow support or workflow archive),  
please read https://github.com/argoproj/argo/blob/master/docs/cli.md.

Available Commands:  
  archive          
  auth             
  cluster-template manipulate cluster workflow templates
  completion       output shell completion code for the specified shell (bash or zsh)
  cron             manage cron workflows
  delete           
  get              display details about a workflow
  help             Help about any command
  lint             validate files or directories of workflow manifests
  list             list workflows
  logs             view logs of a pod or workflow
  resubmit         resubmit one or more workflows
  resume           resume zero or more workflows
  retry            retry zero or more workflows
  server           Start the Argo Server
  stop             stop zero or more workflows
  submit           submit a workflow
  suspend          suspend zero or more workflow
  template         manipulate workflow templates
  terminate        terminate zero or more workflows
  version          Print version information
  wait             waits for workflows to complete
  watch            watch a workflow until it completes

使用方法如下:

argo submit hello-world.yaml    # submit a workflow spec to Kubernetes  
argo list                       # list current workflows  
argo get hello-world-xxx        # get info about a specific workflow  
argo logs -w hello-world-xxx    # get logs from all steps in a workflow  
argo logs hello-world-xxx-yyy   # get logs from a specific step in a workflow  
argo delete hello-world-xxx     # delete workflow  

也可以直接使用 kubectl 来运行Argo工作流,但是 Argo CLI 提供了语法检查、更友好的输出,只需更少的输入。

kubectl create -f hello-world.yaml  
kubectl get wf  
kubectl get wf hello-world-xxx  
kubectl get po --selector=workflows.argoproj.io/workflow=hello-world-xxx --show-all  # similar to argo  
kubectl logs hello-world-xxx-yyy -c main  
kubectl delete wf hello-world-xxx  

Hello World!

让我们首先创建一个非常简单的工作流模板,使用 DockerHub 中的 docker / whalesay 容器映像回显“ hello world”。

你可以通过一个简单的 docker 命令直接在你的 shell 中运行:

$ docker run docker/whalesay cowsay "hello world"
 _____________
< hello world >  
 -------------
    \
     \
      \
                    ##        .
              ## ## ##       ==
           ## ## ## ##      ===
       /""""""""""""""""___/ ===
  ~<del> {</del> ~~<del> </del>~ ~~<del> </del> ~ /  ===- ~~~
       \&#95;&#95;&#95;&#95;&#95;&#95; o          __/
        \    \        __/
          \&#95;&#95;&#95;&#95;\&#95;&#95;&#95;&#95;&#95;&#95;/


Hello from Docker!  
This message shows that your installation appears to be working correctly.  

下面,我们使用 Argo 工作流模板在 Kubernetes 集群上运行相同的容器,其中住注释对你理解模板很有帮助。

apiVersion: argoproj.io/v1alpha1  
kind: Workflow                  # new type of k8s spec  
metadata:  
  generateName: hello-world-    # name of the workflow spec
spec:  
  entrypoint: whalesay          # invoke the whalesay template
  templates:
  - name: whalesay              # name of the template
    container:
      image: docker/whalesay
      command: [cowsay]
      args: ["hello world"]
      resources:                # limit the resources
        limits:
          memory: 32Mi
          cpu: 100m

解释下上面的模板,首先增加了一种新的 Kubernetes 规范叫做Workflow。上面的规范包含一个名为 whalesay 的模板,它运行 docker/whalesay 容器并调用 cowsay "hello world"Whalesay 模板是规范的入口点。 入口点指定由 Kubernetes 执行工作流规范时应调用的初始模板。当在 Kubernetes 工作流规范中定义了多个模板时,能够指定入口点更有用。

Parameters/参数 vs Workflow Spec

让我们来看一个稍微复杂一点的带有参数的工作流规范。

apiVersion: argoproj.io/v1alpha1  
kind: Workflow  
metadata:  
  generateName: hello-world-parameters-
spec:  
  # invoke the whalesay template with
  # "hello world" as the argument
  # to the message parameter
  entrypoint: whalesay
  arguments:
    parameters:
    - name: message
      value: hello world

  templates:
  - name: whalesay
    inputs:
      parameters:
      - name: message       # parameter declaration
    container:
      # run cowsay with that message input parameter as args
      image: docker/whalesay
      command: [cowsay]
      args: ["{{inputs.parameters.message}}"]
Argo Workflow Serverless Workflow
apiVersion: argoproj.io/v1alpha1  
kind: Workflow  
metadata:  
  generateName: hello-world-parameters-
spec:  
  entrypoint: whalesay
  arguments:
    parameters:
    - name: message
      value: hello world

  templates:
  - name: whalesay
    inputs:
      parameters:
      - name: message
    container:
      image: docker/whalesay
      command: [cowsay]
      args: ["{{inputs.parameters.message}}"]
id: hello-world-parameters  
name: Hello World with parameters  
version: '1.0'  
functions:  
- name: whalesayimage
  resource: docker/whalesay
  type: container
  metadata:
    command: cowsay
states:  
- name: whalesay
  type: OPERATION
  start:
    kind: DEFAULT
  actions:
  - functionRef:
      refName: whalesayimage
      parameters:
        message: "$.message"
  end:
    kind: DEFAULT

这一次,whalesay 模板接受一个名为 message 的输入参数,该参数作为 args 传递给 cowsay 命令。 为了引用参数(例如,"{ inputs.parameters.message }}") ,参数必须用双引号括起来,以转义 YAML 中的花括号。

Argo CLI 提供了一种方便的方法来覆盖用于调用入口点的参数。 例如,下面的命令将 message 参数绑定到“ goodbye world” ,而不是默认的“hello world”。

argo submit arguments-parameters.yaml -p message="goodbye world"  

对于可以覆盖的多个参数,argo CLI 提供一个命令来加载 YAML 或 JSON 格式的参数文件。 下面是这种参数文件的一个例子:

message: goodbye world  

要运行以下命令:

argo submit arguments-parameters.yaml --parameter-file params.yaml  

命令行参数还可用于覆盖默认的入口点并调用工作流规范中的任何模板。 例如,如果你添加了 whalesay 模板的新版本 whalesay-caps,但是你不想改变默认的入口点,你可以通过如下命令行调用它:

argo submit arguments-parameters.yaml --entrypoint whalesay-caps  

通过使用 -- entrypoint 和-p 参数的组合,您可以使用任何您喜欢的参数调用工作流规范中的任何模板。

spec.arguments.parameters 中设置的值是全局范围的,可以通过 {{workflow.parameters.parameter_name}} 访问。 这对于将信息传递给工作流中的多个步骤非常有用。 例如,如果你想在每个容器的环境中设置不同的日志级别来运行你的工作流,你可以有一个类似这个的 YAML 文件:

apiVersion: argoproj.io/v1alpha1  
kind: Workflow  
metadata:  
  generateName: global-parameters-
spec:  
  entrypoint: A
  arguments:
    parameters:
    - name: log-level
      value: INFO

  templates:
  - name: A
    container:
      image: containerA
      env:
      - name: LOG_LEVEL
        value: "{{workflow.parameters.log-level}}"
      command: [runA]
  - name: B
    container:
      image: containerB
      env:
      - name: LOG_LEVEL
        value: "{{workflow.parameters.log-level}}"
      command: [runB]

在这个工作流中,步骤 A 和步骤 B 将具有相同的日志级别设置为 INFO,并且可以很容易地在使用 -p 标志的工作流提交之间进行更改。

Steps/步骤 vs Workflow Spec

在这个例子中,我们将看到如何创建多步骤工作流,如何在工作流规范中定义多个模板,以及如何创建嵌套工作流。 请务必阅读文件中的注释,它们提供了有用的解释。

apiVersion: argoproj.io/v1alpha1  
kind: Workflow  
metadata:  
  generateName: steps-
spec:  
  entrypoint: hello-hello-hello

  # This spec contains two templates: hello-hello-hello and whalesay
  # 本规范包含两个模板
  templates:
  - name: hello-hello-hello
    # Instead of just running a container
    # This template has a sequence of steps
    # 该模板有一个顺序执行的步骤
    steps:
    - - name: hello1            # hello1 is run before the following steps # hello1第一个执行
        template: whalesay
        arguments:
          parameters:
          - name: message
            value: "hello1"
    - - name: hello2a           # double dash => run after previous step # 双横线表示接着上个步骤运行
        template: whalesay
        arguments:
          parameters:
          - name: message
            value: "hello2a"
      - name: hello2b           # single dash => run in parallel with previous step # 单横线表示和上个步骤一起并行运行
        template: whalesay
        arguments:
          parameters:
          - name: message
            value: "hello2b"

  # This is the same template as from the previous example
  - name: whalesay
    inputs:
      parameters:
      - name: message
    container:
      image: docker/whalesay
      command: [cowsay]
      args: ["{{inputs.parameters.message}}"]
Argo Workflow Serverless Workflow
apiVersion: argoproj.io/v1alpha1  
kind: Workflow  
metadata:  
  generateName: steps-
spec:  
  entrypoint: hello-hello-hello

  # This spec contains two templates: hello-hello-hello and whalesay
  templates:
  - name: hello-hello-hello
    # Instead of just running a container
    # This template has a sequence of steps
    steps:
    - - name: hello1            # hello1 is run before the following steps
        template: whalesay
        arguments:
          parameters:
          - name: message
            value: "hello1"
    - - name: hello2a           # double dash => run after previous step
        template: whalesay
        arguments:
          parameters:
          - name: message
            value: "hello2a"
      - name: hello2b           # single dash => run in parallel with previous step
        template: whalesay
        arguments:
          parameters:
          - name: message
            value: "hello2b"

  # This is the same template as from the previous example
  - name: whalesay
    inputs:
      parameters:
      - name: message
    container:
      image: docker/whalesay
      command: [cowsay]
      args: ["{{inputs.parameters.message}}"]
id: hello-hello-hello  
name: Multi Step Hello  
version: '1.0'  
functions:  
- name: whalesayimage
  resource: docker/whalesay
  type: container
  metadata:
    command: cowsay
states:  
- name: hello1
  type: OPERATION
  start:
    kind: DEFAULT
  actions:
  - functionRef:
      refName: whalesayimage
      parameters:
        message: hello1
  transition:
    nextState: parallelhello
- name: parallelhello
  type: PARALLEL
  completionType: AND
  branches:
  - name: hello2a-branch
    states:
    - name: hello2a
      type: OPERATION
      start:
        kind: DEFAULT
      actions:
      - functionRef:
          refName: whalesayimage
          parameters:
            message: hello2a
      end:
        kind: DEFAULT
  - name: hello2b-branch
    states:
    - name: hello2b
      type: OPERATION
      start:
        kind: DEFAULT
      actions:
      - functionRef:
          refName: whalesayimage
          parameters:
            message: hello2b
      end:
        kind: DEFAULT
  end:
    kind: DEFAULT

上面的工作流规范打印了三种不同风格的“ hello”。 hello-hello-hello 模板由三个步骤组成。 名为 hello1的第一步将按顺序运行,而名为 hello2a 和 hello2b 的接下来两步将并行运行。 使用 argo CLI 命令,我们可以以图形方式显示此工作流规范的执行历史,它显示名为 hello2a 和 hello2b 的步骤彼此并行运行。

STEP                                     PODNAME  
 ✔ arguments-parameters-rbm92
 ├---✔ hello1                   steps-rbm92-2023062412
 └-·-✔ hello2a                  steps-rbm92-685171357
   └-✔ hello2b                  steps-rbm92-634838500

DAG/有向无环图 vs Workspec

作为指定步骤序列的替代方法,您可以通过指定每个任务的依赖关系将工作流定义为有向无环图(DAG)。 对于复杂的工作流,这可以更简单地维护,并且在运行任务时允许最大的并行性。

在下面的工作流中,步骤 A 首先运行,因为它没有依赖项。 一旦 A 完成,步骤 B 和步骤 C 并行运行。 最后,一旦 B 和 C 完成,步骤 D 就可以运行了。

apiVersion: argoproj.io/v1alpha1  
kind: Workflow  
metadata:  
  generateName: dag-diamond-
spec:  
  entrypoint: diamond
  templates:
  - name: echo
    inputs:
      parameters:
      - name: message
    container:
      image: alpine:3.7
      command: [echo, "{{inputs.parameters.message}}"]
  - name: diamond
    dag:
      tasks:
      - name: A
        template: echo
        arguments:
          parameters: [{name: message, value: A}]
      - name: B
        dependencies: [A]
        template: echo
        arguments:
          parameters: [{name: message, value: B}]
      - name: C
        dependencies: [A]
        template: echo
        arguments:
          parameters: [{name: message, value: C}]
      - name: D
        dependencies: [B, C]
        template: echo
        arguments:
          parameters: [{name: message, value: D}]

注意: 即使这个例子可以用规范来描述(只有一个启动任务) ,规范当前也不支持多个启动事件。 目前不能使用规范描述具有多个启动 DAG 任务的 Argo 工作流。

Argo Serverless Workflow
apiVersion: argoproj.io/v1alpha1  
kind: Workflow  
metadata:  
  generateName: dag-diamond-
spec:  
  entrypoint: diamond
  templates:
  - name: echo
    inputs:
      parameters:
      - name: message
    container:
      image: alpine:3.7
      command: [echo, "{{inputs.parameters.message}}"]
  - name: diamond
    dag:
      tasks:
      - name: A
        template: echo
        arguments:
          parameters: [{name: message, value: A}]
      - name: B
        dependencies: [A]
        template: echo
        arguments:
          parameters: [{name: message, value: B}]
      - name: C
        dependencies: [A]
        template: echo
        arguments:
          parameters: [{name: message, value: C}]
      - name: D
        dependencies: [B, C]
        template: echo
        arguments:
          parameters: [{name: message, value: D}]
id: dag-diamond-  
name: DAG Diamond Example  
version: '1.0'  
functions:  
- name: echo
  resource: alpine:3.7
  type: container
  metadata:
    command: '[echo, "{{inputs.parameters.message}}"]'
states:  
- name: A
  type: OPERATION
  start:
    kind: DEFAULT
  actions:
  - functionRef:
      refName: echo
      parameters:
        message: A
  transition:
    nextState: parallelecho
- name: parallelecho
  type: PARALLEL
  completionType: AND
  branches:
  - name: B-branch
    states:
    - name: B
      type: OPERATION
      start:
        kind: DEFAULT
      actions:
      - functionRef:
          refName: echo
          parameters:
            message: B
      end:
        kind: DEFAULT
  - name: C-branch
    states:
    - name: C
      type: OPERATION
      start:
        kind: DEFAULT
      actions:
      - functionRef:
          refName: echo
          parameters:
            message: C
      end:
        kind: DEFAULT
  transition:
    nextState: D
- name: D
  type: OPERATION
  start:
    kind: DEFAULT
  actions:
  - functionRef:
      refName: echo
      parameters:
        message: D
  end:
    kind: DEFAULT

依赖关系图可能有多个根。 从 DAG 或者 steps 模板调用的模板本身可以是 DAG 或者 steps 模板。 这样就可以将复杂的工作流拆分为可管理的部分。

有向无环图逻辑有一个内置的 fail fast 特性,一旦它检测到有向无环图节点中的一个失败,它就停止调度新的步骤。 然后等待所有有向无环图节点都完成后,再判断有向无环图本身是否失败。 Failfast 标志缺省值为 true,如果设置为 false,它将允许 DAG 运行 DAG 的所有分支(成功或失败) ,而与 DAG 分支的失败结果无关。 这里有更多关于这个特性的信息和例子。

Artifacts

注意: 您需要配置一个 artifact 存储库来运行这个示例。

在运行工作流时,生成或使用工件的步骤是非常常见的。 通常,一个步骤的输出构件可以用作后续步骤的输入构件。

下面的工作流规范包含两个按顺序运行的步骤。 名为 generate-artifact 的第一步将使用 whalesay 模板生成一个构件,该构件将由名为 print-message 的第二步使用消费。

apiVersion: argoproj.io/v1alpha1  
kind: Workflow  
metadata:  
  generateName: artifact-passing-
spec:  
  entrypoint: artifact-example
  templates:
  - name: artifact-example
    steps:
    - - name: generate-artifact
        template: whalesay
    - - name: consume-artifact
        template: print-message
        arguments:
          artifacts:
          # bind message to the hello-art artifact
          # generated by the generate-artifact step
          - name: message
            from: "{{steps.generate-artifact.outputs.artifacts.hello-art}}"

  - name: whalesay
    container:
      image: docker/whalesay:latest
      command: [sh, -c]
      args: ["cowsay hello world | tee /tmp/hello_world.txt"]
    outputs:
      artifacts:
      # generate hello-art artifact from /tmp/hello_world.txt
      # artifacts can be directories as well as files
      - name: hello-art
        path: /tmp/hello_world.txt

  - name: print-message
    inputs:
      artifacts:
      # unpack the message input artifact
      # and put it at /tmp/message
      - name: message
        path: /tmp/message
    container:
      image: alpine:latest
      command: [sh, -c]
      args: ["cat /tmp/message"]

whalesay 模板使用 cowsay 命令生成一个名为 /tmp/hello-world.txt 的文件。 然后,它将该文件作为一个名为 hello-art 的工件输出。 通常,工件的路径可能是一个目录,而不仅仅是一个文件。 print-message 模板获取一个名为 message 的输入构件,在名为 /tmp/message 的路径上解包它,然后使用 cat 命令打印 /tmp/message 的内容。 工件示例模板将生成的 hello-art ,作为generate-artifact 步骤的输出,作为message输入工件,传递到print-message步骤。 DAG 模板使用任务前缀引用另一个任务,例如{{tasks.generate-artifact.outputs.artifacts.hello-art}}

工件在默认情况下被打包为 Tarballs 和 gzipped。 您可以通过使用 archive 字段指定归档策略来自定义此行为。 例如:

<... snipped ...>  
    outputs:
      artifacts:
        # default behavior - tar+gzip default compression.
      - name: hello-art-1
        path: /tmp/hello_world.txt

        # disable archiving entirely - upload the file / directory as is.
        # this is useful when the container layout matches the desired target repository layout.   
      - name: hello-art-2
        path: /tmp/hello_world.txt
        archive:
          none: {}

        # customize the compression behavior (disabling it here).
        # this is useful for files with varying compression benefits, 
        # e.g. disabling compression for a cached build workspace and large binaries, 
        # or increasing compression for "perfect" textual data - like a json/xml export of a large database.
      - name: hello-art-3
        path: /tmp/hello_world.txt
        archive:
          tar:
            # no compression (also accepts the standard gzip 1 to 9 values)
            compressionLevel: 0
<... snipped ...>  

工作流规范的结构

我们现在对工作流规范的基本组成部分有了足够的了解,可以回顾一下它的基本结构:

总而言之,工作流规范是由一组 Argo 模板组成,其中每个模板包含一个可选的输入部分,一个可选的输出部分,以及一个容器调用或者每个步骤调用另一个模板的步骤列表。

注意,工作流规范的容器部分将接受与 pod 规范的容器部分相同的选项,包括但不限于环境变量、机密和卷挂载,还有卷声明和卷。

Secrets/秘钥

Argo 支持与 Kubernetes Pod 规格相同的秘钥语法和机制,允许在环境变量或卷挂载时访问秘钥。 有关更多信息,请参见 Kubernetes documentation 文档。

# To run this example, first create the secret by running:
# kubectl create secret generic my-secret --from-literal=mypassword=S00perS3cretPa55word
apiVersion: argoproj.io/v1alpha1  
kind: Workflow  
metadata:  
  generateName: secret-example-
spec:  
  entrypoint: whalesay
  # To access secrets as files, add a volume entry in spec.volumes[] and
  # then in the container template spec, add a mount using volumeMounts.
  volumes:
  - name: my-secret-vol
    secret:
      secretName: my-secret     # name of an existing k8s secret
  templates:
  - name: whalesay
    container:
      image: alpine:3.7
      command: [sh, -c]
      args: ['
        echo "secret from env: $MYSECRETPASSWORD";
        echo "secret from file: `cat /secret/mountpath/mypassword`"
      ']
      # To access secrets as environment variables, use the k8s valueFrom and
      # secretKeyRef constructs.
      env:
      - name: MYSECRETPASSWORD  # name of env var
        valueFrom:
          secretKeyRef:
            name: my-secret     # name of an existing k8s secret
            key: mypassword     # 'key' subcomponent of the secret
      volumeMounts:
      - name: my-secret-vol     # mount file containing secret at /secret/mountpath
        mountPath: "/secret/mountpath"

Scripts & Results/脚本和结果 vs Workspec

通常,我们只需要一个模板来执行工作流规范中指定为 here-script (也称为 here document)的脚本。 这个例子展示了如何做到这一点:

apiVersion: argoproj.io/v1alpha1  
kind: Workflow  
metadata:  
  generateName: scripts-bash-
spec:  
  entrypoint: bash-script-example
  templates:
  - name: bash-script-example
    steps:
    - - name: generate
        template: gen-random-int-bash
    - - name: print
        template: print-message
        arguments:
          parameters:
          - name: message
            value: "{{steps.generate.outputs.result}}"  # The result of the here-script

  - name: gen-random-int-bash
    script:
      image: debian:9.4
      command: [bash]
      source: |                                         # Contents of the here-script
        cat /dev/urandom | od -N2 -An -i | awk -v f=1 -v r=100 '{printf "%i\n", f + r * $1 / 65536}'

  - name: gen-random-int-python
    script:
      image: python:alpine3.6
      command: [python]
      source: |
        import random
        i = random.randint(1, 100)
        print(i)

  - name: gen-random-int-javascript
    script:
      image: node:9.1-alpine
      command: [node]
      source: |
        var rand = Math.floor(Math.random() * 100);
        console.log(rand);

  - name: print-message
    inputs:
      parameters:
      - name: message
    container:
      image: alpine:latest
      command: [sh, -c]
      args: ["echo result was: {{inputs.parameters.message}}"]
Argo Workflow Serverless Workflow
apiVersion: argoproj.io/v1alpha1  
kind: Workflow  
metadata:  
  generateName: scripts-bash-
spec:  
  entrypoint: bash-script-example
  templates:
  - name: bash-script-example
    steps:
    - - name: generate
        template: gen-random-int-bash
    - - name: print
        template: print-message
        arguments:
          parameters:
          - name: message
            value: "{{steps.generate.outputs.result}}"  # The result of the here-script

  - name: gen-random-int-bash
    script:
      image: debian:9.4
      command: [bash]
      source: |                                         # Contents of the here-script
        cat /dev/urandom | od -N2 -An -i | awk -v f=1 -v r=100 '{printf "%i\n", f + r * $1 / 65536}'

  - name: gen-random-int-python
    script:
      image: python:alpine3.6
      command: [python]
      source: |
        import random
        i = random.randint(1, 100)
        print(i)

  - name: gen-random-int-javascript
    script:
      image: node:9.1-alpine
      command: [node]
      source: |
        var rand = Math.floor(Math.random() * 100);
        console.log(rand);

  - name: print-message
    inputs:
      parameters:
      - name: message
    container:
      image: alpine:latest
      command: [sh, -c]
      args: ["echo result was: {{inputs.parameters.message}}"]
id: scripts-bash-  
name: Scripts and Results Example  
version: '1.0'  
functions:  
- name: gen-random-int-bash
  resource: debian:9.4
  type: script
  metadata:
    command: bash
    source: |-
      cat /dev/urandom | od -N2 -An -i | awk -v f=1 -v r=100 '{printf "%i
      ", f + r * $1 / 65536}'
- name: gen-random-int-python
  resource: python:alpine3.6
  type: script
  metadata:
    command: python
    source: | 
      import random 
      i = random.randint(1, 100) 
      print(i)
- name: gen-random-int-javascript
  resource: node:9.1-alpine
  type: script
  metadata:
    command: node
    source: |
      var rand = Math.floor(Math.random() * 100); 
      console.log(rand);
- name: printmessagefunc
  resource: alpine:latest
  type: container
  metadata:
    command: sh, -c
    source: 'echo result was: {{inputs.parameters.message}}'
states:  
- name: generate
  type: OPERATION
  start:
    kind: DEFAULT
  actions:
  - functionRef:
      refName: gen-random-int-bash
    actionDataFilter:
      dataResultsPath: "$.results"
  transition:
    nextState: print-message
- name: print-message
  type: OPERATION
  actions:
  - functionRef:
      refName: printmessagefunc
      parameters:
        message: "$.results"
  end:
    kind: DEFAULT

Script 关键字允许使用源标记来规范脚本主体。 这将创建一个包含脚本体的临时文件,然后将临时文件的名称作为最后一个参数传递给 command,command 应该是一个执行脚本体的解释器。

使用 script 特性还将运行脚本的标准输出指定给一个名为 result 的特殊输出参数。 这允许您在工作流规范的其余部分中使用运行脚本本身的结果。 在这个示例中,结果只是由 print-message 模板回显。

分享