Tasks
A Task
(or a ClusterTask
) is a collection of sequentialsteps you would want to run as part of your continuous integration flow. A taskwill run inside a pod on your cluster.
A Task
declares:
A Task
is available within a namespace, and ClusterTask
is available acrossentire Kubernetes cluster.
ClusterTask
Similar to Task, but with a cluster scope.
In case of using a ClusterTask, the TaskRef
kind should be added. The defaultkind is Task which represents a namespaced Task
apiVersion: tekton.dev/v1beta1
kind: Pipeline
metadata:
name: demo-pipeline
namespace: default
spec:
tasks:
- name: build-skaffold-web
taskRef:
name: build-push
kind: ClusterTask
params: ....
A Task
functions exactly like a ClusterTask
, and as such all references toTask
below are also describing ClusterTask
.
Syntax
To define a configuration file for a Task
resource, you can specify thefollowing fields:
- Required:
apiVersion
- Specifies the API version, for exampletekton.dev/v1beta
.kind
- Specify theTask
resource object.metadata
- Specifies data to uniquely identify theTask
resource object, for example aname
.spec
- Specifies the configuration information foryourTask
resource object.Task
steps must be defined through either ofthe following fields:steps
- Specifies one or more container images that you wantto run in yourTask
.
- Optional:
description
- Description of the Task.params
- Specifies parametersresources
- SpecifiesPipelineResources
needed or created by yourTask
. Note: this is an alpha field, it is not supported as therest of the beta field.inputs
- resources needed by yourTask
.outputs
- resources created by yourTask
workspaces
- Specifies paths at which you expect volumes tobe mounted and availableresults
- Specifies the result file name where the task can write its resultvolumes
- Specifies one or more volumes that you want to makeavailable to yourTask
’s steps.stepTemplate
- Specifies aContainer
stepdefinition to use as the basis for all steps within yourTask
.sidecars
- Specifies sidecar containers to run alongsidesteps.
The following example is a non-working sample where most of the possibleconfiguration fields are used:
apiVersion: tekton.dev/v1beta1
kind: Task
metadata:
name: example-task-name
spec:
params:
- name: pathToDockerFile
type: string
description: The path to the dockerfile to build
default: /workspace/workspace/Dockerfile
resources:
inputs:
- name: workspace
type: git
outputs:
- name: builtImage
type: image
steps:
- name: ubuntu-example
image: ubuntu
args: ["ubuntu-build-example", "SECRETS-example.md"]
- image: gcr.io/example-builders/build-example
command: ["echo"]
args: ["$(params.pathToDockerFile)"]
- name: dockerfile-pushexample
image: gcr.io/example-builders/push-example
args: ["push", "$(resources.outputs.builtImage.url)"]
volumeMounts:
- name: docker-socket-example
mountPath: /var/run/docker.sock
volumes:
- name: example-volume
emptyDir: {}
Steps
The steps
field is required. You define one or more steps
fields to definethe body of a Task
.
If multiple steps
are defined, they will be executed in the same order as theyare defined, if the Task
is invoked by a TaskRun
.Each steps
in a Task
must specify a container image that adheres to thecontainer contract. For each of the steps
fields,or container images that you define:
- The container images are run and evaluated in order, starting from the top ofthe configuration file.
- Each container image runs until completion or until the first failure isdetected.
- The CPU, memory, and ephemeral storage resource requests will be set to zeroif the container image does not have the largest resource request out of allcontainer images in the Task. This ensures that the Pod that executes the Taskwill only request the resources necessary to execute any single containerimage in the Task, rather than requesting the sum of all of the containerimage’s resource requests.
Step Script
To simplify executing scripts inside a container, a step can specify a script
.If this field is present, the step cannot specify command
.
When specified, a script
gets invoked as if it were the contents of a file inthe container. Any args
are passed to the script file.
Scripts that do not start with a shebang)line will use the following default preamble:
#!/bin/sh
set -xe
Users can override this by starting their script with a shebang to declare whattool should be used to interpret the script. That tool must then also beavailable within the step’s container.
This allows you to execute a Bash script, if the image includes bash
:
steps:
- image: ubuntu # contains bash
script: |
#!/usr/bin/env bash
echo "Hello from Bash!"
…or to execute a Python script, if the image includes python
:
steps:
- image: python # contains python
script: |
#!/usr/bin/env python3
print("Hello from Python!")
…or to execute a Node script, if the image includes node
:
steps:
- image: node # contains node
script: |
#!/usr/bin/env node
console.log("Hello from Node!")
This also simplifies executing script files in the workspace:
steps:
- image: ubuntu
script: |
#!/usr/bin/env bash
/workspace/my-script.sh # provided by an input resource
…or in the container image:
steps:
- image: my-image # contains /bin/my-binary
script: |
#!/usr/bin/env bash
/bin/my-binary
Description
The description
field is an optional field and can be used to provide description of the Task.
Parameters
Tasks can declare input parameters that must be supplied to the task during aTaskRun. Some example use-cases of this include:
- A Task that needs to know what compilation flags to use when building anapplication.
- A Task that needs to know what to name a built artifact.
Parameters name are limited to alpha-numeric characters, -
and and canonly start with alpha characters and
. For example,
fooIs-Bar_
is a validparameter name, barIsBa$
or 0banana
are not.
Each declared parameter has a type
field, assumed to be string
if not provided by the user. The other possible type is array
— useful, for instance, when a dynamic number of compilation flags need to be supplied to a task building an application. When the actual parameter value is supplied, its parsed type is validated against the type
field.
Usage
The following example shows how Tasks can be parameterized, and these parameterscan be passed to the Task
from a TaskRun
.
Input parameters in the form of $(params.foo)
are replaced inside ofthe steps
(see also variable substitution).
The following Task
declares two input parameters named ‘flags’ (array) and ‘someURL’ (string), and uses them inthe steps.args
list. Array parameters like ‘flags’ can be expanded inside of an existing array by using star expansion syntax by adding []
to the named parameter as we do below using $(params.flags[
])
.
apiVersion: tekton.dev/v1beta1
kind: Task
metadata:
name: task-with-parameters
spec:
params:
- name: flags
type: array
- name: someURL
type: string
steps:
- name: build
image: my-builder
args: ["build", "$(params.flags[*])", "url=$(params.someURL)"]
The following TaskRun
supplies a dynamic number of strings within the flags
parameter:
apiVersion: tekton.dev/v1beta1
kind: TaskRun
metadata:
name: run-with-parameters
spec:
taskRef:
name: task-with-parameters
params:
- name: flags
value:
- "--set"
- "arg1=foo"
- "--randomflag"
- "--someotherflag"
- name: someURL
value: "http://google.com"
Resources
A Task
can declare the resources it needs and create, which can be either or both of:
Input resources
Use input PipelineResources
field to provide your Task
withdata or context that is needed by your Task
. See the using resources docs.
Output resources
Task
definitions can include inputs and outputsPipelineResource
declarations. If specific set of resourcesare only declared in output then a copy of resource to be uploaded or shared fornext Task is expected to be present under the path/workspace/output/resource_name/
.
resources:
outputs:
name: storage-gcs
type: gcs
steps:
- image: objectuser/run-java-jar #https://hub.docker.com/r/objectuser/run-java-jar/
command: [jar]
args:
["-cvf", "-o", "/workspace/output/storage-gcs/", "projectname.war", "*"]
env:
- name: "FOO"
value: "world"
note: if the task is relying on output resource functionality then thecontainers in the task steps
field cannot mount anything in the path/workspace/output
.
In the following example Task tar-artifact
resource is used both as input andoutput so input resource is downloaded into directory customworkspace
(asspecified in targetPath
). Step untar
extracts tar file intotar-scratch-space
directory , edit-tar
adds a new file and last steptar-it-up
creates new tar file and places in /workspace/customworkspace/
directory. After execution of the Task steps, (new) tar file in directory/workspace/customworkspace
will be uploaded to the bucket defined intar-artifact
resource definition.
resources:
inputs:
name: tar-artifact
targetPath: customworkspace
outputs:
name: tar-artifact
steps:
- name: untar
image: ubuntu
command: ["/bin/bash"]
args: ['-c', 'mkdir -p /workspace/tar-scratch-space/ && tar -xvf /workspace/customworkspace/rules_docker-master.tar -C /workspace/tar-scratch-space/']
- name: edit-tar
image: ubuntu
command: ["/bin/bash"]
args: ['-c', 'echo crazy > /workspace/tar-scratch-space/rules_docker-master/crazy.txt']
- name: tar-it-up
image: ubuntu
command: ["/bin/bash"]
args: ['-c', 'cd /workspace/tar-scratch-space/ && tar -cvf /workspace/customworkspace/rules_docker-master.tar rules_docker-master']
Workspaces
workspaces
are a way of declaring volumes you expect to be made available to yourexecuting Task
and the path to make them available at.
Here’s a short example of a Task spec with a workspace
:
spec:
steps:
- name: write-message
image: ubuntu
script: |
#!/usr/bin/env bash
set -xe
echo hello! > $(workspaces.messages.path)/message
workspaces:
- name: messages
description: The folder where we write the message to
mountPath: /custom/path/relative/to/root
For complete documentation on using workspaces
in Tasks, seeworkspaces.md.
For a complete example see the Workspaces TaskRunin the examples directory.
Results
Specifies one or more result files in which you want the task’s steps
to write a result. All result files are writteninto the /tekton/results
folder. This folder is created automatically if the task defines one or more results.
For example, this task:
apiVersion: tekton.dev/v1beta1
kind: Task
metadata:
name: print-date
annotations:
description: |
A simple task that prints the date
spec:
results:
- name: current-date-unix-timestamp
description: The current date in unix timestamp format
- name: current-date-human-readable
description: The current date in human readable format
steps:
- name: print-date-unix-timestamp
image: bash:latest
script: |
#!/usr/bin/env bash
date +%s | tee /tekton/results/current-date-unix-timestamp
- name: print-date-humman-readable
image: bash:latest
script: |
#!/usr/bin/env bash
date | tee /tekton/results/current-date-human-readable
defines two results current-date-unix-timestamp
and current-date-human-readable
. To define a result, you specify a name
that will correspond to the file name in the /tekton/results
folder and a description
where you can explain the purpose of the result.
Note: The maximum size of a Task’s results is limited by Kubernetes’ container termination log feature. The resultsare passed back to the controller via this mechanism. At time of writing this has a capped maximum size of“2048 bytes or 80 lines, whichever is smaller”.
A Task Result is encoded as a JSON object when it is written to the termination log and Tekton also uses thisobject to pass some other information back to the controller as well. As such Task Results are best utilized forsmall pieces of data. Good candidates are commit SHAs, branch names, ephemeral namespace names, and so on.
If you are writing many small Task Results from a single Task you can work around this size limit by writingthe results from separate Steps - each Step has its own termination log. But for data larger than a kilobytethe next best alternative is to use a Workspace to shuttle data between Tasks in a Pipeline.
Volumes
Specifies one or morevolumes that you want tomake available to your Task
, including all the steps
. Add volumesto complement the volumes that are implicitly created forinput resources and output resources.
For example, use volumes to accomplish one of the following common tasks:
- Mount a Kubernetes secret.
- Create an
emptyDir
volume to act as a cache for use across multiple buildsteps. Consider using a persistent volume for inter-build caching. - MountKubernetes configmapas volume source.
- Mount a host’s Docker socket to use a
Dockerfile
for container image builds.Note: Building a container image usingdocker build
on-cluster is veryunsafe. Use kaniko instead.This is used only for the purposes of demonstration.
Step Template
Specifies a Container
configuration that will be used as the basis for all steps
in yourTask
. Configuration in an individual step will override or merge with thestep template’s configuration.
In the example below, the Task
specifies a stepTemplate
with theenvironment variable FOO
set to bar
. The first step will use that value forFOO
, but in the second step, FOO
is overridden and set to baz
.
stepTemplate:
env:
- name: "FOO"
value: "bar"
steps:
- image: ubuntu
command: [echo]
args: ["FOO is ${FOO}"]
- image: ubuntu
command: [echo]
args: ["FOO is ${FOO}"]
env:
- name: "FOO"
value: "baz"
Sidecars
Specifies a list ofContainers
to runalongside your Steps. These containers can provide auxiliary functions likeDocker in Docker or running a mock APIserver for your app to hit during tests.
Sidecars are started before your Task’s steps are executed and are torndown after all steps have completed. For further information about a sidecar’slifecycle see the TaskRun doc.
In the example below, a Docker in Docker sidecar is run so that a step canuse it to build a docker image:
steps:
- image: docker
name: client
script: |
#!/usr/bin/env bash
cat > Dockerfile << EOF
FROM ubuntu
RUN apt-get update
ENTRYPOINT ["echo", "hello"]
EOF
docker build -t hello . && docker run hello
docker images
volumeMounts:
- mountPath: /var/run/
name: dind-socket
sidecars:
- image: docker:18.05-dind
name: server
securityContext:
privileged: true
volumeMounts:
- mountPath: /var/lib/docker
name: dind-storage
- mountPath: /var/run/
name: dind-socket
volumes:
- name: dind-storage
emptyDir: {}
- name: dind-socket
emptyDir: {}
Sidecars can also run a script, like a Step:
sidecars:
image: busybox
name: hello-sidecar
script: |
echo 'Hello from sidecar!'
Note: There is a known bug with Tekton’s existing sidecar implementation.Tekton uses a specific image, called “nop”, to stop sidecars. The “nop” imageis configurable using a flag of the Tekton controller. If the configured “nop”image contains the command that the sidecar was running before the sidecarwas stopped then the sidecar will actually keep running, causing the TaskRun’sPod to remain running, and eventually causing the TaskRun to timeout ratherthen exit successfully. Issue 1347has been created to track this bug.
Variable Substitution
Tasks
support string replacement using values from:
Parameter and Resource substitution
params
and resources
attributes can be used in replacements,including params
and resources
.
Parameters can be referenced in the Task
spec using the variable substitution syntax below,where <name>
is the name of the parameter:
$(params.<name>)
Param values from resources can also be accessed using variable substitution
Variable Substitution with Parameters of Type Array
Referenced parameters of type array
can be expanded using ‘star-expansion’ by adding [*]
to the named parameter to insert the array elements in the reference string’s spot.
So, with the following parameter:
params:
- name: array-param
value:
- "some"
- "array"
- "elements"
then command: ["first", "$(params.array-param[*])", "last"]
will becomecommand: ["first", "some", "array", "elements", "last"]
Note that array parameters must be referenced in a completely isolated string within a larger string array.Any other attempt to reference an array is invalid and will throw an error.
For instance, if build-args
is a declared parameter of type array
, then this is an invalid step becausethe string isn’t isolated:
- name: build-step
image: gcr.io/cloud-builders/some-image
args: ["build", "additionalArg $(params.build-args[*])"]
Similarly, referencing build-args
in a non-array field is also invalid:
- name: build-step
image: "$(params.build-args[*])"
args: ["build", "args"]
A valid reference to the build-args
parameter is isolated and in an eligible field (args
, in this case):
- name: build-step
image: gcr.io/cloud-builders/some-image
args: ["build", "$(params.build-args[*])", "additonalArg"]
Variable Substitution with Workspaces
Paths to a Task's
declared workspaces can be substituted with:
$(workspaces.myworkspace.path)
Since the name of the Volume
is not known until runtime and is randomized, you can alsosubstitute the volume name with:
$(workspaces.myworkspace.volume)
Variable Substitution within Volumes
Task volume names and differenttypes of volumescan be parameterized. Current support includes for widely used types of volumeslike configmap, secret and PersistentVolumeClaim. Here is anexample on how to use this inTask definitions.
Examples
Use these code snippets to help you understand how to define your Tasks
.
- Example of image building and pushing
- Mounting extra volumes
- Mounting configMap as volumesource
- Using secret as environment source
Tip: See the collection of simpleexamples foradditional code samples.
Example Task
For example, a Task
to encapsulate a Dockerfile
build might look somethinglike this:
Note: Building a container image using docker build
on-cluster is veryunsafe. Use kaniko instead.This is used only for the purposes of demonstration.
spec:
params:
# These may be overridden, but provide sensible defaults.
- name: directory
type: string
description: The directory containing the build context.
default: /workspace
- name: dockerfileName
type: string
description: The name of the Dockerfile
default: Dockerfile
resources:
inputs:
- name: workspace
type: git
outputs:
- name: builtImage
type: image
steps:
- name: dockerfile-build
image: gcr.io/cloud-builders/docker
workingDir: "$(params.directory)"
args:
[
"build",
"--no-cache",
"--tag",
"$(resources.outputs.image.url)",
"--file",
"$(params.dockerfileName)",
".",
]
volumeMounts:
- name: docker-socket
mountPath: /var/run/docker.sock
- name: dockerfile-push
image: gcr.io/cloud-builders/docker
args: ["push", "$(resources.outputs.image.url)"]
volumeMounts:
- name: docker-socket
mountPath: /var/run/docker.sock
# As an implementation detail, this Task mounts the host's daemon socket.
volumes:
- name: docker-socket
hostPath:
path: /var/run/docker.sock
type: Socket
Using an extra volume
Mounting multiple volumes:
spec:
steps:
- image: ubuntu
script: |
#!/usr/bin/env bash
curl https://foo.com > /var/my-volume
volumeMounts:
- name: my-volume
mountPath: /var/my-volume
- image: ubuntu
script: |
#!/usr/bin/env bash
cat /etc/my-volume
volumeMounts:
- name: my-volume
mountPath: /etc/my-volume
volumes:
- name: my-volume
emptyDir: {}
Using Kubernetes Configmap as Volume Source
spec:
params:
- name: CFGNAME
type: string
description: Name of config map
- name: volumeName
type: string
description: Name of volume
steps:
- image: ubuntu
script: |
#!/usr/bin/env bash
cat /var/configmap/test
volumeMounts:
- name: "$(params.volumeName)"
mountPath: /var/configmap
volumes:
- name: "$(params.volumeName)"
configMap:
name: "$(params.CFGNAME)"
Using secret as environment source
apiVersion: tekton.dev/v1beta1
kind: Task
metadata:
name: goreleaser
spec:
params:
- name: package
type: string
description: base package to build in
- name: github-token-secret
type: string
description: name of the secret holding the github-token
default: github-token
resources:
inputs:
- name: source
type: git
targetPath: src/$(params.package)
steps:
- name: release
image: goreleaser/goreleaser
workingDir: /workspace/src/$(params.package)
command:
- goreleaser
args:
- release
env:
- name: GOPATH
value: /workspace
- name: GITHUB_TOKEN
valueFrom:
secretKeyRef:
name: $(params.github-token-secret)
key: bot-token
Using a sidecar
apiVersion: tekton.dev/v1beta1
kind: Task
metadata:
name: with-sidecar-task
spec:
params:
- name: sidecar-image
type: string
description: Image name of the sidecar container
- name: sidecar-env
type: string
description: Environment variable value
sidecars:
- name: sidecar
image: $(params.sidecar-image)
env:
- name: SIDECAR_ENV
value: $(params.sidecar-env)
steps:
- name: test
image: hello-world
Except as otherwise noted, the content of this page is licensed under theCreative Commons Attribution 4.0 License,and code samples are licensed under theApache 2.0 License.
Debugging
In software, we do things not because they are easy, but because we think they will be.Lots of things can go wrong when writing a Task.This section contains some tips on how to debug one.
Inspecting the Filesystem
One common problem when writing Tasks is not understanding where files are on disk.For the most part, these all live somewhere under /workspace
, but the exact layout canbe tricky.To see where things are before your task runs, you can add a step like this:
- name: build-and-push-1
image: ubuntu
command:
- /bin/bash
args:
- -c
- |
set -ex
find /workspace
This step will output the name of every file under /workspace to your build logs.
To see the contents of every file, you can use a similar step:
- name: build-and-push-1
image: ubuntu
command:
- /bin/bash
args:
- -c
- |
set -ex
find /workspace | xargs cat
These steps are useful both before and after your Task steps!
Inspecting the pod
One task
will map to one Pod
, to check arbitrary thing in Pod
, the best way is to login the pod
, add a step at the position you want to pause
the task, then checking.
- name: pause
image: docker
args: ["sleep", "6000"]