Introduction
Tekton is a Kubernetes-native continuous integration (CI) and continuous delivery (CD) engine. A Tekton Pipeline orchestrates a set of Tasks to provide a desired goal, such as building an application and deploying it to a cluster. Until now, Tasks were always executed in containers running as Kubernetes pods. Tekton Pipelines 0.19 introduced Custom Tasks, which made it possible to integrate different execution models into the Tekton Pipeline. This article introduces Custom Tasks, explores some of the reasons why you would use them, and walks you through executing them in your Pipeline. If you are not familiar with Tekton concepts, refer to Introduction to Tekton architecture and design for an introduction.
Custom Tasks
Custom Tasks are an experimental alpha feature that you can use to plug alternative execution models into a Tekton Pipeline. They are intended to support cases where execution via a Tekton Task is potentially inefficient.
Consider the following use cases:
Implement advanced conditional checks, such as checking that a pipeline parameter setting follows certain conventions: You could do this using a normal Tekton Task, but the time to create a pod to run the task might outweigh the time to perform the check. If a pipeline needs many of these checks, then this time can add up and cause pipelines to run longer.
Wait for an external event to occur, such as an approval to perform a certain activity: You could do this using a normal Tekton Task, but it keeps a pod active in the cluster, consuming resources.
You can create Custom Tasks to support more complex workflows as well:
Execute another pipeline and wait for it to complete.
Execute a task a fixed number of times or until some condition occurs.
Use a Custom Task in a Pipeline
Because Custom Tasks are experimental, they are not enabled by default. To enable them, you need to edit the feature-flags
ConfigMap in the tekton-pipelines
namespace and change the setting of enable-custom-tasks
from false
to true
:
kubectl edit cm feature-flags -n tekton-pipelines
A Custom Task is identified by an apiVersion
, kind
, and an optional name
. A Pipeline uses the following syntax to reference a Custom Task:
apiVersion: tekton.dev/v1beta1
kind: Pipeline
metadata:
name: demo-custom-task
spec:
tasks:
- name: run-my-custom-task
taskRef:
apiVersion: example.dev/v1alpha1
kind: Example
name: my-custom-task
params:
- name: foo
value: bah
When the Pipeline is executed, Tekton creates a Run
object to run the Custom Task (as opposed to the TaskRun
object it creates for a normal Task):
apiVersion: tekton.dev/v1alpha1
kind: Run
metadata:
name: run-my-custom-task-xjns6
spec:
ref:
apiVersion: example.dev/v1alpha1
kind: Example
name: my-custom-task
params:
- name: foo
value: bah
The cluster must have a running custom task controller that is watching for and processing Run
objects that reference this apiVersion
and kind
. The apiVersion
, kind
, and name
are intended to reference a custom resource that provides input to the custom task controller about what the user wants it to do. In reality, the custom task controller is not obligated to support a custom resource. It can just use the parameters for input.
The custom task controller communicates the status of its processing by setting the Run
object’s status field with a condition of the type Succeeded
. While it is working on the request, it can set the condition status to Unknown
and optionally provide a reason and message.
status:
conditions:
- message: Working on it
reason: Running
status: "Unknown"
type: Succeeded
If the request fails, the custom task controller sets the condition status to False
. This causes the Pipeline execution itself to fail.
status:
conditions:
- message: Failed because bah happens
reason: Failed
status: "False"
type: Succeeded
If the request succeeds, the custom task controller sets the condition status to True
. This causes any Pipeline Tasks that are directly dependent on this Task to begin execution:
status:
conditions:
- message: Processing completed successfully
reason: Succeeded
status: "True"
type: Succeeded
When the request succeeds, the controller can also return results as part of the status:
status:
results:
- name: conclusion
value: positive
A Pipeline can reference these results using the normal syntax:
$(tasks.run-my-custom-task.results.conclusion)
An example Custom Task: Task Loop
Let’s look at an implementation of a custom task TaskLoops, which provides for each
kind of capability by iterating over a task and creating taskRuns
for each iteration. You can configure the number of iterations and the values for each iteration through a parameter.
Install the TaskLoop
controller:
kubectl apply -f https://storage.googleapis.com/tekton-releases-nightly/task-loops/latest/release.yaml
With TaskLoop
, you can run a Task
in a loop with varying parameter values. For example, suppose you have a Task
that runs tests based on a parameter name called test-type
, shown here:
cat <<EOF | kubectl apply -f -
apiVersion: tekton.dev/v1beta1
kind: Task
metadata:
name: testtask
spec:
params:
- name: test-type
type: string
steps:
- name: run-test
image: ubuntu
script: |
echo ["\$(params.test-type)"]
EOF
If you want to run this Task
for multiple test types, you can create a TaskLoop
custom resource
that looks like this:
cat <<EOF | kubectl apply -f -
apiVersion: custom.tekton.dev/v1alpha1
kind: TaskLoop
metadata:
name: testloop
spec:
taskRef:
name: testtask
iterateParam: test-type
EOF
A Pipeline would run the TaskLoop
as follows:
cat <<EOF | kubectl apply -f -
apiVersion: tekton.dev/v1beta1
kind: Pipeline
metadata:
name: testpipeline
spec:
tasks:
- name: run-my-tests
taskRef:
apiVersion: custom.tekton.dev/v1alpha1
kind: TaskLoop
name: testloop
params:
- name: test-type
value:
- ls
- echo
EOF
A PipelineRun
would reference the testpipeline
as follows:
cat <<EOF | kubectl apply -f -
apiVersion: tekton.dev/v1beta1
kind: PipelineRun
metadata:
name: testpipelinerun
spec:
pipelineRef:
name: testpipeline
EOF
This sample PipelineRun
runs two iterations of the same task with different parameter:
kubectl get pr testpipelinerun -o json | jq .status.runs[].status.extraFields.taskRuns[].iteration
1
2
Custom Tasks like TaskLoop
provide a great way to experiment with extensions to Tekton functionality without having to modify the Tekton controller itself.
Other custom task controllers available in the experimental repo include:
Summary
Custom Tasks provide an exciting new capability to integrate different execution models into Tekton. Custom Tasks are expected to evolve based on user requirements, so reach out to the Tekton community if you find Custom Tasks helpful or need additional guidance implementing your own.