This article documents how to use ArgoWorkflow to build pipelines, as well as conceptual models such as Workflow and Template in ArgoWorkflow.
This paper analyzes the following issues:
- 1) How to create a pipeline
- 2) Workflow, Template, template own reference relationship
- 3) Parameter passing issues between Workflow and Template
- 4) ArgoWorkflow Pipeline Best Practices
1. Conceptual model
The next step is how to build our pipeline. The concepts related to pipelines in ArgoWorkflow are as follows:
- Workflow: pipeline, a real running instance of a pipeline, similar to pipelinerun in Tekton.
- WorkflowTemplate: pipeline template, you can create a pipeline based on the template, similar to the pipeline in Tekton.
- ClusterWorkflowTemplate: cluster-level pipeline template, the relationship with WorkflowTemplate is similar to Role and ClusterRole in K8s.
- templates: Workflow or Template's smallest component unit, the pipeline consists of multiple templates.
WorkflowTemplate and ClusterWorkflowTemplate are collectively referred to as Templates for now.
The relationship between Workflow, Template (uppercase), and template (lowercase) is as follows:
The relationship between the three is complicated, and officials have also mentioned that the naming of this area is confusing due to some historical problems.
Personal Understanding:
- template (lowercase): the basic building block of a Template, understood as a step in a pipeline.
- Template (uppercase): a complete pipeline, typically consisting of multiple templates (lowercase)
- Workflow: the real running pipeline instance, generally created directly by the Template, similar to the pipeline run records, each record is a Workflow
Once the basic concepts are sorted out, the next step is to look at the specific uses.
In ArgoWorkflow, Workflow is a pipeline running instance, and every time a Workflow object is created, it will trigger the pipeline to run once.
Here's a simple Workflow example:
apiVersion: /v1alpha1
kind: Workflow
metadata:
generateName: steps-
spec:
entrypoint: hello # We reference our first "template" here
templates:
- name: hello # The first "template" in this Workflow, it is referenced by "entrypoint"
steps: # The type of this "template" is "steps"
- - name: hello
template: whalesay # We reference our second "template" here
arguments:
parameters: [{name: message, value: "hello"}]
- name: whalesay # The second "template" in this Workflow, it is referenced by "hello"
inputs:
parameters:
- name: message
container: # The type of this "template" is "container"
image: docker/whalesay
command: [cowsay]
args: ["{{}}"]
The core content of the entire Workflow object is divided into the following three parts:
-
entrypoint
: A pipeline entry, similar to the main method in code, which generally references one of thetemplate invocators
Ready to go. -
templates
: A list of templates where all the steps in the pipeline and the order of precedence between them are defined. -
parameters
: The parameters used in the pipeline, including global parameters in the arguments block and local parameters in the inputs block.
entrypoint
The entrypoint must be specified in the Workflow, and the entrypoint is the starting point for the execution of the task, similar to the main method in a program.
templates
See the official documentation for details:#template-types
Templates are categorized into various types, which are classified according to the type oftemplate definitions(template definition) andtemplate invocators(template caller).
-
template definitions: This type template is used to define what specific steps are to be performed, as in the whalesay template in the example.
- embody
container
,script
,resource
,suspend
and other types
- embody
-
template invocators: This type template is used to combine othertemplate definitions The hello template in the example is of this type.
- An entrypoint is generally a template of this type
- embody
dag
cap (a poem)steps
The hello template in the example is of type steps.
Spoiler alert: template is a bit convoluted, and it would be nice if theTemplate definition, template caller Splitting into two different objects is clearer.
Once you understand the template classification, it's clearer to go back and look at the previous Workflow examples:
apiVersion: /v1alpha1
kind: Workflow
metadata:
generateName: steps-
spec:
entrypoint: hello # We reference our first "template" here
templates:
- name: hello # The first "template" in this Workflow, it is referenced by "entrypoint"
steps: # The type of this "template" is "steps"
- - name: hello
template: whalesay # We reference our second "template" here
arguments:
parameters: [{name: message, value: "hello"}]
- name: whalesay # The second "template" in this Workflow, it is referenced by "hello"
inputs:
parameters:
- name: message
container: # The type of this "template" is "container"
image: docker/whalesay
command: [cowsay]
args: ["{{}}"]
- 1) First of all the whalesay template is a
container
template of typetemplate definitions - 2) Secondly hello is a
steps
template of typetemplate invocators- The steps field in this caller defines a step named hello, which references the whalesay template
- 3) Entrypoint specifies hello, thetemplate invocators
Summary:entrypoint, template definitions, and template invocators are the three components of a Workflow The necessary components of the
parameters
Workflow supports two types of parameters:
- arguments: global arguments, available to all templates under Workflow.
- inputs: local parameters, only available for the current template.
arguments Global arguments
is used to define global parameters that are available in all Templates under the current Workflow, and can be used with the
{{.$name}}
syntax to quote.
For example, the following example specifies a parameter named message and assigns it the value hello world.
arguments:
parameters:
- name: message
value: hello world
inputs Local parameters
Templates can use thetemplates[*].inputs
field to specify thelocal parameterThis part of the parameter can only be used by the current Template. The parameters can be changed with the{{.$name}}
syntax to refer to the parameters.
The following example declares that template requires a parameter called message, but does not provide a value.
templates:
- name: whalesay-template
inputs:
parameters:
- name: message
container:
image: docker/whalesay
command: [cowsay]
args: ["{{}}"]
parameter passing
Global parameter values in Workflow are specified by the user, while values in local parameters are generally overridden by global parameters.
apiVersion: /v1alpha1
kind: Workflow
metadata:
generateName: steps-
spec:
entrypoint: hello # We reference our first "template" here
templates:
- name: hello # The first "template" in this Workflow, it is referenced by "entrypoint"
steps: # The type of this "template" is "steps"
- - name: hello
template: whalesay # We reference our second "template" here
arguments:
parameters: [{name: message, value: "hello"}]
- name: whalesay # The second "template" in this Workflow, it is referenced by "hello"
inputs:
parameters:
- name: message
container: # The type of this "template" is "container"
image: docker/whalesay
command: [cowsay]
args: ["{{}}"]
In the above example, template whalesay defines a local parameter named message, but does not assign a value to it, and defines a parameter named message in the template, so eventually the local parameter message will be overridden by the global parameter message.
The above example can be seen as such:
templates:
- name: hello # The first "template" in this Workflow, it is referenced by "entrypoint"
steps: # The type of this "template" is "steps"
- - name: hello
template: whalesay # We reference our second "template" here
arguments:
parameters: [{name: message, value: "hello"}]
- name: whalesay # The second "template" in this Workflow, it is referenced by "hello"
inputs:
parameters:
- name: message
value: "{{}}"
container: # The type of this "template" is "container"
image: docker/whalesay
command: [cowsay]
args: ["{{}}"]
That is: template references local parameters, local parameters come from global parameters, and the user configures global parameters.
As you can specify from the previous description, we can create Workflow objects directly to run the pipeline, but there are some problems with this approach:
- 1) If there are a lot of templates, the Workflow object will be very large, which makes it more troublesome to modify it.
- 2) templates can not be shared, different Workflow need to write the same template
Therefore, it is generally recommended to save the template to WorkflowTemplate, and only reference the Template in Workflow and provide parameters.
The workflow templates in ArgoWorkflow are categorized according to their scope asWorkflowTemplate cap (a poem)ClusterWorkflowTemplate Two kinds.
- WorkflowTemplate: Namespace scope, can only be referenced in the same namespace
- ClusterWorkflowTemplate: cluster scope, any namespace can be referenced
WorkflowTemplate
Here is a simple example of a WorkflowTemplate:
apiVersion: /v1alpha1
kind: WorkflowTemplate
metadata:
name: workflow-template-submittable
namespace: default
spec:
entrypoint: whalesay-template
arguments:
parameters:
- name: message
value: tpl-argument-default
templates:
- name: whalesay-template
inputs:
parameters:
- name: message
value: tpl-input-default
container:
image: docker/whalesay
command: [cowsay]
args: ["{{}}"]
You can see that the parameters of WorkflowTemplate and Workflow are exactly the same, just replace the kind in yaml from Workflow to WorkflowTemplate, so we won't go into details here.
workflowMetadata
The workflowMetadata is a field unique to Template and is mainly used for theStoring metadata,Subsequent Templates created by this Template Workflow All automatically carry this information with them。
With this information you can track which Template the Workflow was created from.
It is used like the following, with a label specified in the workflowMetadata
apiVersion: /v1alpha1
kind: WorkflowTemplate
metadata:
name: workflow-template-submittable
spec:
workflowMetadata:
labels:
example-label: example-value
Workflow objects created by this Template will then carry this label:
apiVersion: /v1alpha1
kind: Workflow
metadata:
annotations:
/pod-name-format: v2
creationTimestamp: "2023-10-27T06:26:13Z"
generateName: workflow-template-hello-world-
generation: 2
labels:
example-label: example-value
name: workflow-template-hello-world-5w7ss
namespace: default
ClusterWorkflowTemplate
Similar to WorkflowTemplate, it can be understood as the relationship between Role and ClusterRole in k8s.
and WorkflowTemplate are the same for all parameters, except that the yaml Replace kind with ClusterWorkflowTemplate.
wrap-up
It is a good idea to have all three of the following sections configured in the Template:
- entrypoint: Recommended, although you can specify it in the Workflow, but then every time you create a Workflow you need to see what templates are in the Template first, which is troublesome, so it's best to fill in the Template directly.
- templates: It is necessary, the role of Template is to write templates.
- arguments: It's a good idea to fill in the default value so that Workflow can use it without specifying any parameters.
Once the Template is populated with these three core elements, Workflow is very simple to use.
4. TemplateRef
Once you have created a Template, you can use TemplateRef to directly reference the corresponding template in Workflow, so that the Workflow object will be cleaner.
workflowTemplateRef
This can be done byworkflowTemplateRef
field directly references the WorkflowTemplate.
Note 📢: hereneed Workflow and WorkflowTemplate in the same namespace.。
It's like this:
apiVersion: /v1alpha1
kind: Workflow
metadata:
generateName: workflow-template-hello-world-
spec:
arguments:
parameters:
- name: message
value: "from workflow"
workflowTemplateRef:
name: workflow-template-submittable
workflowTemplateRef
Specify the name of the Template you want to reference, this sentence is equivalent to moving all the contents under the spec field of the corresponding Template, including entrypoint, template and so on.
Generally, Workflow only needs to override arguments with the argument field, but of course you can leave it unspecified. If you don't specify an argument in Workflow, the default value provided in the Template will be used.
A minimalist Workflow looks like this:
apiVersion: /v1alpha1
kind: Workflow
metadata:
generateName: workflow-template-hello-world-
spec:
workflowTemplateRef:
name: workflow-template-submittable
only ifworkflowTemplateRef
field, no argument is provided.
Contrasted with the previous Workflow, there is even less content, because most of it is written in the WorkflowTemplate, and the Workflow usually just needs to specify the parameters.
Parameter issues:
- Global parameters can be used directly in the WorkflowTemplate, they just need to be defined in the Workflow by then.
- Local parameters must be defined and assigned values in the WorkflowTemplate.
See the official documentation for details:#working-with-parameters
It seems that it is better to use global parameters in WorkflowTemplate, because the values of local parameters are defined directly in WorkflowTemplate and cannot be overridden in Workflow.
clusterWorkflowTemplateRef
Similar to workflowTemplateRef, just add theclusterScope: true
Configuration is sufficient.
The default is false, i.e. WorkflowTemplate
It's like this:
apiVersion: /v1alpha1
kind: Workflow
metadata:
generateName: workflow-template-hello-world-
spec:
entrypoint: whalesay
templates:
- name: whalesay
steps: # You should only reference external "templates" in a "steps" or "dag" "template".
- - name: call-whalesay-template
templateRef: # You can reference a "template" from another "WorkflowTemplate or ClusterWorkflowTemplate" using this field
name: cluster-workflow-template-whalesay-template # This is the name of the "WorkflowTemplate or ClusterWorkflowTemplate" CRD that contains the "template" you want
template: whalesay-template # This is the name of the "template" you want to reference
clusterScope: true # This field indicates this templateRef is pointing ClusterWorkflowTemplate
arguments: # You can pass in arguments as normal
parameters:
- name: message
value: "hello world"
Core components:
workflowTemplateRef:
name: cluster-workflow-template-submittable
clusterScope: true
When specified as cluster-scoped, ArgoWorkflow will go searching for ClusterWorkflowTemplate objects, otherwise it will search for WorkflowTemplate in the current namespace.
templateRef
In addition to using workflowTemplateRef / clusterWorkflowTemplateRef to reference an entire WorkflowTemplate, you can also use thetemplateRef parameter to reference a template in the WorkflowTemplate.
Note 📢: according to the official documentation, it's best not to use thesteps
cap (a poem)dag
Use templateRef in addition to templates of type templateRef.
apiVersion: /v1alpha1
kind: Workflow
metadata:
generateName: workflow-template-hello-world-
spec:
entrypoint: whalesay
templates:
- name: whalesay
steps: # You should only reference external "templates" in a "steps" or "dag" "template".
- - name: call-whalesay-template
templateRef: # You can reference a "template" from another "WorkflowTemplate" using this field
name: workflow-template-1 # This is the name of the "WorkflowTemplate" CRD that contains the "template" you want
template: whalesay-template # This is the name of the "template" you want to reference
arguments: # You can pass in arguments as normal
parameters:
- name: message
value: "hello world"
5. Parameter prioritization tests
Since there are multiple places where parameters can be set, and at the same time there are differences such as global and local parameters, it is not very clear about the specific logic of the parameters, so we tested the specific parameter passing situation.
There are a total of three places to set the parameters:
- 1) WorkflowTemplate arguments global parameters
- 2) WorkflowTemplate inputs local parameters
- 3) Workflow arguments global parameters
Note 📢: With workflowTemplateRef references, there is no way to specify input values in Workflow.
Tests were done for different scenarios and the final conclusions are as follows for:
Workflow hit the nail on the head argument > argument in Template > Template input
Whenever a higher priority parameter is supplied, the lower priority overrides the
- Argument > Input i.e., global parameters have higher priority than local parameters.
- Workflow > Template i.e. pipeline parameters can override the default values in the template
6. Summary
Workflow in ArgoWorkflow includes the following concepts:
- Workflow
- Template:WorkflowTemplate、ClusterWorkflowTemplate
- TemplateRef:workflowTemplateRef、clusterWorkflowTemplateRef
- Template
The relationship is shown in the figure
A Workflow / WorkflowTemplate contains three parts of parameters:
- entrypoint: entry point, required, value is the name of the Template.
- can be derived from Workflow, i.e. explicitly written inside Workflow.
- It can also be derived from the WorkflowTemplate, i.e., the field is not written in Workflow, but in the WorkflowTemplate.
- It's best to write it directly in the WorkflowTemplate.
- arguments: arguments, again, can be specified by both Workflow and WorkflowTemplate, and arguments in Workflow have higher priority than WorkflowTemplate.
- templates: templates, this section contains the actions that Workflow will perform.
- This part is recommended to be defined in the WorkflowTemplate, and the WorkflowTemplate can be directly referenced in Workflow.
Best Practices:
- 1) Use Template to manage the pipeline, and define the entrypoint and templates and arguments in WorkflowTemplate.
- Template specifies entrypoints, templates, arguments, etc.
- 2) Use TemplateRef in Workflow to directly reference an existing Template and specify arguments to override.
Parameter Priority:The argument > argument in Template > Template input
[ArgoWorkflow Series]Continuously updated, search the public number [Explore Cloud Native]Subscribe to read more articles.