Tasks
At the end of this chapter you will be able to :
-
Understand what is a Task ?
-
Understand how to clone your build resources using Task
-
Understand where cloned sources reside i.e. Workspace
-
Create a Task that can build the sources
-
How to run a Task
-
Use the pipeline resource with TaskRun
If you are not in tutorial chapter folder, then navigate to the folder:
cd $TUTORIAL_HOME/tasks
Tekton Task
Each Task has the following:
-
name - the unique name using which the task can be referred
-
inputs - the inputs to the task
-
resources - the pipeline resources that will be used in the task e.g. git-source
-
name - the name of the input resource using which it can be referenced and bound via TaskRun
-
type - the type of the input resource, typically the pipeline resource type
-
-
params - the parameters that will be used in the task steps. Each parameter has
-
name - the name of the parameter
-
description - the description of the parameter
-
default - the default value of parameter
-
-
The TaskRun could override the parameter values, if no parameter value is passed then the default value will be used. |
-
outputs the pipeline resource that will end artifact of the task. In the above example the build will produce a container image artifact.
-
resources - the pipeline resources that will be used in the task e.g. builtImage
-
name - the name of the input resource using which it can be referenced and bound via TaskRun
-
type - the type of the input resource, typically the pipeline resource type
-
-
-
steps - One or more sub-tasks that will be executed in the defined order. The step has all the attributes like a Pod spec
-
volumes - the task can also mount external volumes using the volumes attribute.
The parameters that were part of the $(<variable-name>)
.
Clone Source Code
The following listing shows a simple Task that clones the sources using git command and lists the sources:
---
apiVersion: tekton.dev/v1beta1
kind: Task
metadata:
name: source-lister
spec:
params:
- name: contextDir
description: "The context directory within the repository for sources"
default: quarkus
resources:
inputs:
- name: source
type: git
steps:
- name: ls-build-sources
image: busybox
command: ["ls", "-ltr", "/workspace/source/$(inputs.params.contextDir)"]
The sources are usually cloned to a standard path called /workspace/<input.resource.name>
, in this example the input source name is source
and hence the git clone will be done to a path called /workspace/source
.
You can create the Task using the command as shown in the following listing:
kubectl apply -n tektontutorial -f source-lister.yaml
Verify that your task was created:
tkn task ls
NAME AGE
source-lister 37 seconds ago
Lets describe the task
resource:
tkn task describe source-lister
The command above will shown an output like:
Name: source-lister
Namespace: tektontutorial
π¨ Input Resources
NAME TYPE
β source git
π‘ Output Resources
No output resources
β Params
NAME TYPE DESCRIPTION DEFAULT VALUE
β contextDir string The context directo... apps/greeter/java/quarkus
π¦Ά Steps
β ls-build-sources
π Taskruns
No taskruns
Since we have not run the Task yet, the command shows No taskruns. You can use the tkn
CLI tool to run the Task, pass parameters and input sources.
Use the
|
Since we just have to pass the GitHub repo for the source-lister, run the following command to start the TaskRun
:
tkn task start source-lister \
--showlog \(1)
--inputresource='source=git-source'(2)
1 | Show the logs while running the Task |
2 | You are mapping the git-source from the Pipeline resource to be the input source for the Task. |
The command might ask your to confirm any default values, in this task we have a parameter called
Be sure press Enter to start the TaskRun after providing inputs to the prompts. |
The command should show an output like:
? Value for param `contextDir` of type `string`? (Default is `apps/greeter/java/quarkus`) apps/greeter/java/quarkus
TaskRun started: source-lister-run-nbpvz
Waiting for logs to be available...
[git-source-git-source-qtp5j] {"level":"info","ts":1595743350.5350783,"caller":"git/git.go:105","msg":"Successfully cloned https://github.com/redhat-scholars/tekton-tutorial @ master in path /workspace/source"}
[git-source-git-source-qtp5j] {"level":"warn","ts":1595743350.5351503,"caller":"git/git.go:152","msg":"Unexpected error: creating symlink: symlink /tekton/home/.ssh /root/.ssh: file exists"}
[git-source-git-source-qtp5j] {"level":"info","ts":1595743350.5708065,"caller":"git/git.go:133","msg":"Successfully initialized and updated submodules in path /workspace/source"}
[ls-build-sources] total 36
[ls-build-sources] drwxr-xr-x 4 root root 4096 Jul 26 06:02 src
[ls-build-sources] -rw-r--r-- 1 root root 4005 Jul 26 06:02 pom.xml
[ls-build-sources] -rwxr-xr-x 1 root root 6607 Jul 26 06:02 mvnw.cmd
[ls-build-sources] -rwxr-xr-x 1 root root 10069 Jul 26 06:02 mvnw
[ls-build-sources] drwxr-xr-x 2 root root 4096 Jul 26 06:02 k8s
[ls-build-sources] -rw-r--r-- 1 root root 154 Jul 26 06:02 Dockerfile
The container images used by the steps need to be downloaded therefore the first execution of the task will take some time before it starts logging the output to the terminal. |
Remember a Task is running as a pod therefore you can watch your pod to see task lifecycle: Init, PodInitializing, Running, and finally Completed as seen in the following listing:
While the task is running open a new terminal and run:
watch kubectl get pods
The command should show an output like:
NAME READY STATUS AGE
source-lister-run-6xpgx-pod-c7dc67 0/2 Init:0/2 9s
...
NAME READY STATUS AGE
source-lister-run-6kt8d-pod-67b326 0/2 Completed 41s
Watching logs
If the Task ran successfully you will notice the following logs in your terminal (lines truncated for brevity):
Taskrun started: source-lister-run-96qc4
Waiting for logs to be available...
...
[git-source-git-source-rdr2k] {"level":"info","ts":1585065123.3817806,"logger":"fallback-logger","caller":"logging/config.go:69","msg":"Fetch GitHub commit ID from kodata failed: open /var/run/ko/refs/heads/master: no such file or directory"}
[git-source-git-source-rdr2k] {"level":"info","ts":1585065133.3997571,"logger":"fallback-logger","caller":"logging/config.go:69","msg":"Fetch GitHub commit ID from kodata failed: open /var/run/ko/refs/heads/master: no such file or directory"}
[git-source-git-source-rdr2k] {"level":"info","ts":1585065138.9021251,"logger":"fallback-logger","caller":"git/git.go:102","msg":"Successfully cloned https://github.com/redhat-scholars/tekton-tutorial @ master in path /workspace/source"}
[git-source-git-source-rdr2k] {"level":"warn","ts":1585065138.902316,"logger":"fallback-logger","caller":"git/git.go:149","msg":"Unexpected error: creating symlink: symlink /tekton/home/.ssh /root/.ssh: file exists"}
[git-source-git-source-rdr2k] {"level":"info","ts":1585065138.9946759,"logger":"fallback-logger","caller":"git/git.go:130","msg":"Successfully initialized and updated submodules in path /workspace/source"}
[ls-build-sources] {"level":"info","ts":1585065132.8109465,"logger":"fallback-logger","caller":"logging/config.go:69","msg":"Fetch GitHub commit ID from kodata failed: \"KO_DATA_PATH\" does not exist or is empty"}
[ls-build-sources] total 36
[ls-build-sources] drwxr-xr-x 3 root root 4096 Mar 24 15:52 src
[ls-build-sources] -rw-r--r-- 1 root root 3472 Mar 24 15:52 pom.xml
[ls-build-sources] -rw-r--r-- 1 root root 6609 Mar 24 15:52 mvnw.cmd
[ls-build-sources] -rwxr-xr-x 1 root root 10078 Mar 24 15:52 mvnw
[ls-build-sources] -rw-r--r-- 1 root root 671 Mar 24 15:52 Dockerfile.jvm
[ls-build-sources] -rw-r--r-- 1 root root 188 Mar 24 15:52 Dockerfile
The logs are the consolidated logs from all the Task step containers. You can identify the source of the log i.e the step that has generated the logs using the text within the square brackets []
of each log line.
e.g.
Logs starting with [ls-build-sources] are from the container that is responsible for running the Task step i.e. ls-build-sources
.
Know the workspace directory
In the example above, there is a log which shows the git clone
command that cloned the application sources to the /workspace/source
directory. The workspace directory is where your Task/Pipeline sources/build atrifacts will be cloned and generated. The source
sub-path under is the directory where Tekton cloned the applicaiton sources. It is usually the name of the resources -→ inputs -→ Resource of type Git.
Cluster Task
The tasks are by default tied to namespace i.e their visibility is restricted to the namespace where they were created. E.g. the source-lister
that we created and ran earlier is tied to tektontutorial.
To check lets create a new namespace called clustertask-demo
:
kubectl create namespace clustertask-demo
kubectl config set-context --current --namespace clustertask-demo
Listing the tasks in the clustertask-demo
will not show any Tasks as shown in the command output below.
tkn task ls
No Tasks found
The reason that there are no Tasks found us that, we have not created any ClusterTask yet. If the Task is not a ClusterTask type then we will not be able to run the Task in namespaces where its not installed. Try running our source-lister
task from within clustertask-demo
:
tkn task start source-lister --showlog --inputresource='source=git-source'
The command should fail with following output:
# shifting to clustertask-demo
Context "tektontutorial" modified.
Error: Task name source-lister does not exist in namespace clustertask-demo
Let us now create a very simple ClusterTask called echoer as shown in the below listing:
apiVersion: tekton.dev/v1beta1
kind: ClusterTask (1)
metadata:
name: echoer
spec:
steps:
- image: alpine
script: | (2)
#!/bin/sh
echo 'Meeow!! from Tekton πΊπ'
1 | The kind ClusterTask makes the task available in all namespaces. |
2 | The step can also be shell script π |
kubectl apply -n clustertask-demo -f echoer.yaml
List and Describe ClusterTasks
tkn clustertask ls
You have to use clustertask command to list all cluster tasks
|
The comand should return an output like, with one ClusterTask echoer
:
NAME DESCRIPTION AGE
echoer 18 minutes ago
Let us decribe ClusterTask echoer
:
tkn clustertask describe echoer
The comand should return an output like:
Name: echoer
π¨ Input Resources
No input resources
π‘ Output Resources
No output resources
β Params
No params
π¦Ά Steps
β unnamed-0
π Taskruns
No taskruns
If you compare the output above with source-lister Task, the one big difference with respect to definition is the missing |
Run ClusterTask echoer
Lets run the task in the current namesapce clustertask-demo
:
tkn clustertask start echoer --showlog
TaskRun started: echoer-run-75n6g
Waiting for logs to be available...
[unnamed-0] Meeow!! from Tekton πΊπ
Run ClusterTask echoer
in other namespace(s)
Let us now shift back to tektontutorial
and run the echoer
task again:
kubectl config set-context --current --namespace=tektontutorial
tkn clustertask start echoer --showlog
The command should produce an identical output as shown in above.
Points to Ponder
-
Tasks are namespace bound i.e. available only in namespace(s) where they were created
-
Tasks resources are interacted using
tkn task
command and its options -
ClusterTasks are available across the cluster i.e. in any namesapce(s) of the cluster
-
ClusterTasks resources are interacted using
tkn clustertask
command and its options
Build Cloud Native Application
The Tekton Task can be of one or more steps. A Cloud Native Java Application at minimum comprises of the following steps:
-
Building the Application from sources using build tool like Apache Maven or Gradle
-
Building the linux container image from the build artifacts
-
Pushing the built container image to remote registry like Quay.io or Docker Hub
The task build-app
is used to build the Java application that is part of the tutorial. As a step one(build-sources
) the application will be built using Apache Maven, then the step two (build-image
) the application artifacts a jar in this case will be used to built the linux container image using buildah, the Dockerfile in the sources will be used as base to build the linux container image and as part of the last step(build-push
) the built linux container image will be pushed to the container registry.
The following section explains the three Task steps. The Deploy a task will finally deploy all these three steps together as one single build-app
task.
Step :: Task Inputs and Outputs
inputs:
resources: (1)
- name: source
type: git
params:
- name: contextDir (2)
description: the context dir within source
default: springboot
- name: destinationImage (3)
description: the fully qualified image name
default: "$(outputs.resources.builtImage.url)"
- name: dockerFile (4)
description: the docker file to used for building the application
default: Dockerfile
- name: tlsVerify (5)
description: tls verify
type: string
default: "false"
outputs:
resources: (6)
- name: builtImage
type: image
1 | The input referred via source , which will be of type git . Having a input resource of type git will cause the TektonPipelines to add implict git clone step to download the sources to workspace/source directory |
2 | contextDir - specifies the directory under the sources, which will be the context for the Task |
3 | destinationImage - the linux container image name that will be built as part of this Task. Defaults to the outputs.resources.builtImage.url |
4 | dockerFile - the Dockerfile that will be used to build the image |
5 | tlsVerify - enable or disable TLS when pushing the image to remote registry |
6 | The output specifices the final output of the Task, in this case the built linux container image referred via builtImage |
For Task inputs and outputs - we will use the PipelineResources that was created in previous chapter. |
Step 1 :: Build Application Sources
- name: build-sources
image: docker.io/maven:3.6.3-jdk-8-slim
workingDir: "/workspace/source/$(inputs.params.contextDir)" (1)
command: (2)
- mvn
args: (3)
- -DskipTests
- -pl
- $(inputs.params.contextDir)
- clean
- package
env: (4)
- name: user.home
value: /home/tekton
1 | the working dir or the context directory within the sources from where the build command(s) will be run |
2 | the build command to run |
3 | the maven build command arguments |
4 | The environment variables that will be set within the step container |
Step 2 :: Build Application Linux Container Image
- name: build-image
image: quay.io/buildah/stable
workingDir: "/workspace/source/$(inputs.params.contextDir)"
command:
- "buildah"
args:
- "bud"
- "--layers"
- "-f"
- "$(inputs.params.dockerFile)"
- "-t"
- "$(inputs.params.destinationImage)"
- "."
securityContext: (1)
runAsUser: 0
volumeMounts: (2)
- name: varlibc
mountPath: /var/lib/containers
1 | Running buildah inside container needs to be run as root user and needs privilege esclation. These are set as part of security context. |
2 | The buildah tool saves the built linux container layers in the local file system at /var/lib/containers , which can then be used in other steps or to push the image to remote registry. |
Step 3:: Push Application Linux Container Image
- name: push-image
image: quay.io/buildah/stable
workingDir: "/workspace/source/$(inputs.params.contextDir)"
command:
- "buildah"
args:
- "push"
- "--tls-verify=$(inputs.params.tlsVerify)"
- $(inputs.params.destinationImage)
- "docker://$(inputs.params.destinationImage)"
securityContext:
runAsUser: 0
volumeMounts:
- name: varlibc
mountPath: /var/lib/containers
Having see the three individual steps of the build-app
task, the following snippet shows all three chained together:
---
apiVersion: tekton.dev/v1beta1
kind: Task
metadata:
name: build-app
spec:
params:
- name: contextDir
description: the context dir within source
default: .
- name: mavenMirrorUrl
description: the maven mirrror url
default: https://repo.maven.apache.org/maven2/
- name: destinationImage
description: the fully qualified image name
default: "$(outputs.resources.builtImage.url)"
- name: dockerFile
description: the docker file to used for building the application
default: Dockerfile
- name: tlsVerify
description: tls verify
type: string
default: "false"
resources:
inputs:
- name: source
type: git
outputs:
- name: builtImage
type: image
steps:
- name: build-sources
image: docker.io/maven:3.6.3-openjdk-11-slim
workingDir: "/workspace/source/$(inputs.params.contextDir)"
command:
- mvn
args:
- -DskipTests
- clean
- package
env:
- name: user.home
value: /home/tekton
- name: build-image
image: quay.io/buildah/stable
workingDir: "/workspace/source/$(inputs.params.contextDir)"
command:
- "buildah"
args:
- "bud"
- "--layers"
- "-f"
- "$(inputs.params.dockerFile)"
- "-t"
- "$(inputs.params.destinationImage)"
- "."
securityContext:
privileged: true
runAsUser: 0
volumeMounts:
- name: varlibc
mountPath: /var/lib/containers
- name: push-image
image: quay.io/buildah/stable
workingDir: "/workspace/source/$(inputs.params.contextDir)"
command:
- "buildah"
args:
- "push"
- "--tls-verify=$(inputs.params.tlsVerify)"
- $(inputs.params.destinationImage)
- "docker://$(inputs.params.destinationImage)"
securityContext:
runAsUser: 0
privileged: true
volumeMounts:
- name: varlibc
mountPath: /var/lib/containers
volumes:
- name: varlibc
emptyDir: {}
Deploy a task
Make sure we are in the tektontutorial
:
kubectl config view --minify | grep namespace
Output should be like:
namespace: tektontutorial
The application build task could be created using the command:
kubectl apply -n tektontutorial -f build-app-task.yaml
We will use the Tekton cli to inspect the created resources
tkn task ls
The above command should list one Task as shown below:
NAME AGE
build-app 12 seconds ago
source-lister 7 minutes ago
|
TaskRun
The TaskRun is used to run a specific task independently. In the following section we will run the build-app
task created in the previous step.
The application build task(build-app
) could be run using the command:
tkn task start -n tektontutorial build-app \(1)
--inputresource='source=git-source' \(2)
--outputresource='builtImage=tekton-tutorial-greeter-image' \(3)
--param contextDir='springboot' \(4)
--showlog(5)
1 | The task that need to be run, in this case build-app |
2 | The input resource mapping, i.e. mapping input source to PipelineResource git-source of type git |
3 | The output resource mapping, i.e. mapping output builtImage to PipelineResource built-image of type image |
It will take few seconds for the TaskRun to show status as Running
as it needs to download the container images.
|
Watch TaskRun logs
To check the status of the TaskRun use the logs
command of taskrun like:
tkn tr ls
NAME STARTED DURATION STATUS
build-app-run-tsqrf 2 minutes ago --- Running
echoer-run-gx6wp 40 minutes ago 15 seconds Succeeded
source-lister-run-6t2mj 1 hour ago 14 seconds Succeeded
source-lister-run-nbpvz 1 hour ago 28 seconds Succeeded
# use one task run for which you need the log from list above
tkn tr logs -f -a build-app-run-tsqrf (1)
1 | The -f or -a allows to tail the logs from all the containers of the task. For more options run tkn tr --help |
TaskRun Containers
Each task step will be run within a container of its own. You can list the containers of the build pod like:
kubectl get pods --selector=tekton.dev/task=build-app
e.g. For a build-app TaskRun pod build-app-run-lj7sm-pod-s74bp
kubectl get pod build-app-run-lj7sm-pod-s74bp \
-o jsonpath="{range .spec.containers[*] }{.name}{'\n'}{end}"
The command should show an output like:
step-create-dir-builtimage-hn654
step-git-source-git-source-2lqtx
step-build-sources
step-build-image
step-push-image
step-image-digest-exporter-52lh6
As noted from the output each container will be prefixed by step-
followed by the step-name from that of the Task definition.
Apart from your step pods there will also be other Tekton pods that will be added to each TaskRun based on the input and output resources. e.g step-git-source-git-source-2lqtx, step-image-digest-exporter-52lh6
If you see the TaskRun status as Failed
or Error
use the following command to check the reason for error:
tkn taskrun describe <taskrun-name>
Test Task output
Lets try running the image build using the build-app
task:
kubectl run demo-greeter -n tektontutorial \
--generator='run-pod/v1' \
--image='example.com/rhdevelopers/tekton-tutorial-greeter' && \
kubectl expose pod demo-greeter -n tektontutorial --port 8080 --type=NodePort
Wait for the demo-greeter
to be up and running:
watch kubectl get pods -n tektontutorial
Lets try checking the application:
SVC_URL=$(minikube -p tektontutorial -n tektontutorial service demo-greeter --url)
oc expose svc -n tektontutorial demo-greeter
SVC_URL=$(oc get routes -o yaml | yq r - 'spec.url.host' )
http --body $SVC_URL
The above command should show an output like Meeow!! from Tekton πΊπ
Step Template
When there is a need to have similar container configuration across all steps of a Task, we can have them defined in the stepTemplate. The Task steps will then inherit them implicitly in all steps. In the example above we define the resources and securityContext for all the steps using the stepTemplate. Also if you notice in the example above we can also override the stepTemplate at the step level. That gives a unique flexibility to tweak the settings at step level.
With the current build-app
task, we see the following configurations are repeated in build-image
and push-image
:
securityContext:
privileged: true
runAsUser: 0
volumeMounts:
- name: varlibc
mountPath: /var/lib/containers
We can move the the above step configuration into a stepTemplate as shown in the following updated build-app
task:
---
apiVersion: tekton.dev/v1beta1
kind: Task
metadata:
name: build-app
spec:
stepTemplate:
securityContext:
runAsUser: 0
privileged: true
volumeMounts:
- name: varlibc
mountPath: /var/lib/containers
params:
- name: contextDir
description: the context dir within source
default: .
- name: mavenMirrorUrl
description: the maven mirrror url
default: https://repo.maven.apache.org/maven2/
- name: destinationImage
description: the fully qualified image name
default: "$(outputs.resources.builtImage.url)"
- name: dockerFile
description: the docker file to used for building the application
default: Dockerfile
- name: tlsVerify
description: tls verify
type: string
default: "false"
resources:
inputs:
- name: source
type: git
outputs:
- name: builtImage
type: image
steps:
- name: build-sources
image: docker.io/maven:3.6.3-openjdk-11-slim
command:
- mvn
args:
- -DskipTests
- clean
- package
env:
- name: user.home
value: /home/tekton
workingDir: "/workspace/source/$(inputs.params.contextDir)"
- name: build-image
image: quay.io/buildah/stable
command:
- "buildah"
args:
- "bud"
- "--layers"
- "-f"
- "$(inputs.params.dockerFile)"
- "-t"
- "$(inputs.params.destinationImage)"
- "."
workingDir: "/workspace/source/$(inputs.params.contextDir)"
- name: push-image
image: quay.io/buildah/stable
command:
- "buildah"
args:
- "push"
- "--tls-verify=$(inputs.params.tlsVerify)"
- $(inputs.params.destinationImage)
- "docker://$(inputs.params.destinationImage)"
workingDir: "/workspace/source/$(inputs.params.contextDir)"
volumes:
- name: varlibc
emptyDir: {}
Apply new Task updates
Now you can apply the task as shown:
kubectl apply -n tektontutorial -f build-app-task-step-template.yaml
Now try running build-app
Task again:
tkn task start -n tektontutorial build-app \
--inputresource='source=git-source' \
--outputresource='builtImage=tekton-tutorial-greeter-image' \
--param contextDir='springboot' \
--showlog
When you examine the TaskRun pods should notice stepTemplate
added to all the step containers including build-sources
.
List the pods that were part of the TaskRun for Task build-app
:
kubectl get pods --selector=tekton.dev/task=build-app
Check securityContext
Assuming the build-app-run pod to be build-app-run-dnbwp-pod-4hcvr
:
kubectl get pod -n tektontutorial build-app-run-dnbwp-pod-4hcvr \
-o=jsonpath="{range .spec.containers[*]}{.name}{'\n'}\
{'\t'}{'Privileged: '}{.securityContext.privileged}{'\t'}{'User: '}{.securityContext.runAsUser}{'\n'}{end}"
The command should an output like :
step-create-dir-builtimage-mqg45
Privileged: true User: 0
step-git-source-git-source-t5xcb
Privileged: true User: 0
step-build-sources
Privileged: true User: 0
step-build-image
Privileged: true User: 0
step-push-image
Privileged: true User: 0
step-image-digest-exporter-tr4mf
Privileged: true User: 0
As you noticed that all steps have inherited the securityContext
from the StepTemplate
, making the step container to run in privileged
mode with user 0
Check volumeMounts
kubectl get pod -n tektontutorial build-app-run-dnbwp-pod-4hcvr \
-o=jsonpath="{range .spec.containers[*]}{.name}{'\n'}{'\t'}{'Mount Path: '}{.volumeMounts[?(@.name=='varlibc')].mountPath} {'\n'}{end}"
The command should an output like :
step-create-dir-builtimage-mqg45
Mount Path: /var/lib/containers
step-git-source-git-source-t5xcb
Mount Path: /var/lib/containers
step-build-sources
Mount Path: /var/lib/containers
step-build-image
Mount Path: /var/lib/containers
step-push-image
Mount Path: /var/lib/containers
step-image-digest-exporter-tr4mf
Mount Path: /var/lib/containers
As you noticed that all steps have inherited the mountPath
from the StepTemplate
.
The Task steps can override the stepTemplate values. |