Tekton Pipelines

Tekton, well from their page, is:

Tekton is a Kubernetes-native, continuous integration and delivery (CI/CD) framework that enables you to create containerized, composable, and configurable workloads declaratively through CRDs.

As I ran into the project I decided to give it a quick test.

Installing Tekton Pipelines

The install process is covered in Installing Tekton Pipelines and it’s actually pretty easy, you can just run the following:

k apply -f https://storage.googleapis.com/tekton-releases/pipeline/latest/release.yaml

After the install is done you will have a new namespace called tekton-pipelines and you can check out the pods that are deployed there:

> k get pods -n tekton-pipelines
NAME                                           READY   STATUS    RESTARTS   AGE
tekton-pipelines-controller-57c7799c8b-6t4r2   1/1     Running   0          23h
tekton-pipelines-webhook-6fc8499666-tmhm8      1/1     Running   0          23h

If you need to save output artifacts don’t forget to create the necessary configuration and that’s covered in Configuring artifact storage. You can also customize the install by creating a configmap and the instructions for that are covered in Customizing basic execution parameters. I just wanted a simple configuration so I left the defaults.

Running a Simple Task with TaskRun

With tekton we have a couple of new resources/entities that are introduced and they are covered in the documentation:

  • Tasks
    • A Task is a collection of Steps that you define and arrange in a specific order of execution as part of your continuous integration flow. A Task executes as a Pod on your Kubernetes cluster. A Task is available within a specific namespace, while a ClusterTask is available across the entire cluster.

    • There is a nice example of building a docker image in Building and pushing a Docker image
  • TaskRuns
  • Pipelines
    • A Pipeline is a collection of Tasks that you define and arrange in a specific order of execution as part of your continuous integration flow. Each Task in a Pipeline executes as a Pod on your Kubernetes cluster. You can configure various execution conditions to fit your business needs.

    • Nice example is at Configuring the Task execution order
  • PipelineRuns

    • A PipelineRun allows you to instantiate and execute a Pipeline on-cluster. A PipelineRun automatically creates corresponding TaskRuns for every Task in your Pipeline.

As a simple exampe let’s run a simple task as described in Tekton Pipelines Tutorial. First let’s create a task to just echo out a message:

> cat task.yaml
apiVersion: tekton.dev/v1beta1
kind: Task
  name: echo-hello-world
    - name: echo
      image: ubuntu
        - echo
        - "Hello World"

Then we can apply it:

> k apply -f task.yaml

You can of course check all the tasks:

> k get tasks
NAME               AGE
echo-hello-world   24h

You can also download the cli and get more info:

> curl -LO https://github.com/tektoncd/cli/releases/download/v0.9.0/tkn_0.9.0_Linux_x86_64.tar.gz
> tar xvzf tkn_0.9.0_Linux_x86_64.tar.gz -C /usr/local/bin/ tkn

Then we can run the following to see the task:

> tkn t list
NAME               DESCRIPTION   AGE
echo-hello-world                 1 day ago

Then you can create a taskrun to execute the defined task:

> cat taskrun.yaml
apiVersion: tekton.dev/v1beta1
kind: TaskRun
  name: echo-hello-world-task-run
    name: echo-hello-world

Now let’s run it:

> k apply -f taskrun.yaml

After it’s done you will see the task status:

> tkn t describe  echo-hello-world
Name:        echo-hello-world
Namespace:   default

📨 Input Resources
 No input resources
📡 Output Resources
 No output resources
⚓ Params
 No params
🦶 Steps
 ∙ echo
🗂  Taskruns
NAME                        STARTED     DURATION     STATUS
echo-hello-world-task-run   1 day ago   16 seconds   Succeeded

You can also check out the logs:

> tkn t logs  echo-hello-world
[echo] Hello World

You can check out the same with the taskrun:

> tkn tr describe echo-hello-world-task-run
Name:        echo-hello-world-task-run
Namespace:   default
Task Ref:    echo-hello-world
Timeout:     1h0m0s
🌡️  Status
1 day ago   16 seconds   Succeeded
📨 Input Resources
 No input resources
📡 Output Resources
 No output resources
⚓ Params
 No params
🦶 Steps
 ∙ echo   ---
🚗 Sidecars
No sidecars

and the logs as well:

> tkn tr logs  echo-hello-world-task-run
[echo] Hello World

I won’t get into pipelines in this post but maybe later.

Tekton Triggers

There is actually another project within the tekton umbrella: Tekton Triggers. From that page:

Triggers is a Kubernetes Custom Resource Definition (CRD) controller that allows you to extract information from events payloads (a “trigger”) to create Kubernetes resources.

And this consists of 3 more new constructs:

  • EventListener
    • EventListener is a Kubernetes custom resource that allows users a declarative way to process incoming HTTP based events with JSON payloads. EventListeners expose an addressable “Sink” to which incoming events are directed.

      Triggers within an EventListener can optionally specify interceptors, to modify the behavior or payload of Triggers.

    • For now the following interceptors are supported: Webhook Interceptors, GitHub Interceptors, GitLab Interceptors, CEL Interceptors
  • TriggerBindings
    • TriggerBindings enable you to capture fields from an event and store them as parameters.

    • Nice example is seen in Multiple Bindings
  • TriggerTemplates
    • A TriggerTemplate is a resource that can template resources. TriggerTemplates have parameters that can be substituted anywhere within the resource template.

      Similar to Pipelines,TriggerTemplates do not do any actual work, but instead act as the blueprint for what resources should be created.

So let’s give them a shot.

Installing Tekton Triggers

Very similar to the Tekton Pipelines install we can run the following to install them (covered in Installing Tekton Triggers):

> k apply -f https://storage.googleapis.com/tekton-releases/triggers/latest/release.yaml

And now you will see more pods:

> k get pods -n tekton-pipelines
NAME                                           READY   STATUS    RESTARTS   AGE
tekton-pipelines-controller-57c7799c8b-6t4r2   1/1     Running   0          23h
tekton-pipelines-webhook-6fc8499666-tmhm8      1/1     Running   0          23h
tekton-triggers-controller-697c9b844d-rdzx8    1/1     Running   0          4h58m
tekton-triggers-webhook-6bcb96f965-fx2n5       1/1     Running   0          4h58m

Now let’s create a simple trigger to print out the parameters that are POST‘ed to it.

Create a Tekton Trigger to Print Sent Parameters

First let’s create an eventlistener:

> cat eventlistener.yaml
apiVersion: triggers.tekton.dev/v1alpha1
kind: EventListener
  name: listener
    - name: foo-trig
        - name: pipeline-binding
        name: pipeline-template

Let’s apply it:

k apply -f eventlistener.yaml

You can check the status of it with the tkn cli:

> tkn eventlistener describe listener
Name:                      listener
Namespace:                 default
URL:                       http://el-listener.default.svc.cluster.local:8080
EventListnerServiceName:   el-listener

 ∙ foo-trig
 ∙ pipeline-binding   TriggerBinding
 ∙ pipeline-template

Now let’s create a pipeline binding to just save the whole body and different parts that are POST‘ed:

> cat triggerbinding.yaml
apiVersion: triggers.tekton.dev/v1alpha1
kind: TriggerBinding
  name: pipeline-binding
  - name: body
    value: $(body)
  - name: title
    value: $(body.title)
  - name: link
    value: $(body.link)
  - name: contenttype
    value: $(header.Content-Type)

Now let’s apply that:

> k apply -f triggerbinding.yaml

And lastly let’s create a triggertemplate to run a task to print those out:

> cat triggertemplate.yaml
apiVersion: triggers.tekton.dev/v1alpha1
kind: TriggerTemplate
  name: pipeline-template
  - name: title
    description: "Title"
    default: "test"
  - name: body
    description: "Body of Mesg (For testing)"
    default: "Test body"
  - name: link
    description: "Link of Mesg"
    default: "http://who.com"
  - name: contenttype
    description: "Headers of event"
    default: "json"
    - apiVersion: tekton.dev/v1alpha1
      kind: TaskRun
        generateName: task-run-
            - image: ubuntu
              script: |
                #! /bin/bash
                echo $(params.body)
                echo $(params.title)
                echo $(params.link)
                echo $(params.contenttype)

And let’s apply it:

k apply -f triggertemplate.yaml

Now from the above output we can see that the internal service that has been exposed is called el-listener, here is more information about it:

> k get svc -l eventlistener=listener
NAME          TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)    AGE
el-listener   ClusterIP   <none>        8080/TCP   6h42m

By default it’s of type ClusterIP and there are instructions on how to expose it externally with an ingress (it’s covered in Exposing EventListeners Externally), but I skipped that since I didn’t need it available externally. So then I POST‘ed to my listener:

> curl -X POST -d '{"title":"test","link":"http://f"}'

Then checking out the taskruns, I saw more:

> tkn taskruns list
NAME                        STARTED          DURATION     STATUS
task-run-8c9wc              39 seconds ago   5 seconds    Succeeded
echo-hello-world-task-run   1 day ago        16 seconds   Succeeded

Checking out the logs I saw the following:

> tkn taskruns logs task-run-8c9wc
[unnamed-0] link:http://f title:test
[unnamed-0] test
[unnamed-0] http://f
[unnamed-0] application/x-www-form-urlencoded

That was sweet. You can also check out the logs of the tekton-pipelines-controller for more information:

> k logs -n tekton-pipelines -f -l app=tekton-pipelines-controller
{"level":"info","logger":"tekton.taskrun-controller","caller":"taskrun/taskrun.go:314","msg":"Cloud Events: []","commit":"ab391e7","knative.dev/controller":"taskrun-controller"}
{"level":"info","logger":"tekton.taskrun-controller","caller":"taskrun/taskrun.go:403","msg":"Successfully reconciled taskrun task-run-ztbdg/default with status: &apis.Condition{Type:\"Succeeded\", Status:\"True\", Severity:\"\", LastTransitionTime:apis.VolatileTime{Inner:v1.Time{Time:time.Time{wall:0xbfa4481dce3c8dcc, ext:93308434659041, loc:(*time.Location)(0x2eb33e0)}}}, Reason:\"Succeeded\", Message:\"All Steps have completed executing\"}","commit":"ab391e7","knative.dev/controller":"taskrun-controller"}
{"level":"info","logger":"tekton.taskrun-controller.event-broadcaster","caller":"record/event.go:274","msg":"Event(v1.ObjectReference{Kind:\"TaskRun\", Namespace:\"default\", Name:\"task-run-ztbdg\", UID:\"b9cd8b1a-e7c7-499d-b034-7bbef7ef6ff0\", APIVersion:\"tekton.dev/v1alpha1\", ResourceVersion:\"59559830\", FieldPath:\"\"}): type: 'Normal' reason: 'Succeeded' All Steps have completed executing","commit":"ab391e7","knative.dev/controller":"taskrun-controller"}
{"level":"info","logger":"tekton.taskrun-controller","caller":"controller/controller.go:403","msg":"Reconcile succeeded. Time taken: 12.66091ms.","commit":"ab391e7","knative.dev/controller":"taskrun-controller","knative.dev/traceid":"5ded1131-ca4e-4517-88ec-63fca78b03d2","knative.dev/key":"default/task-run-ztbdg"}
{"level":"info","logger":"tekton.taskrun-controller","caller":"taskrun/taskrun.go:115","msg":"taskrun done : task-run-ztbdg \n","commit":"ab391e7","knative.dev/controller":"taskrun-controller"}
{"level":"info","logger":"tekton.taskrun-controller","caller":"controller/controller.go:403","msg":"Reconcile succeeded. Time taken: 5.56325ms.","commit":"ab391e7","knative.dev/controller":"taskrun-controller","knative.dev/traceid":"5e5f1b9b-4d8c-459b-8936-f8c7a9223d94","knative.dev/key":"default/task-run-ztbdg"}