Setup Tekton Triggers and Github Webhooks

Nikhil Thomas
10 min readDec 6, 2019

In this article we will setup OpenShift-TektonCD-Triggers (Tekton Triggers) for the CICD Pipeline from the previous article.

Quick Overview of Tekton Triggers

Triggers enable us to hook our CICD Pipelines to respond to external events (push events, pull requests etc). It consists of 3 main components (CRDs):

  1. EventListener
  2. TriggerTemplate
  3. TriggerBinding

EventListener

This is the public facing part of Tekton Triggers. An EventListener sets up a Kubernetes Service which can be exposed as an OpenShift Route (or K8s Ingress). The route URL can be used to configure webhooks in your GitHub repositories (or in any event source). In addition, an EventListener connects TriggerTemplates to TriggerBindings. (Read more)

TriggerTemplate

A TriggerTemplate defines a Template for how a Pipeline should be run in reaction to events. We can define templates for PipelineResources (git, image) and PipelineRuns (based on an existing Pipeline) as a TriggerTemplate. When a event is received by our EventListener, the TriggerTemplate is rendered by extracting parameter values (eg: git repository url, revision etc.) from the event payload. This will result in the creation of new PipelineResources and the starting of a new PipelineRun. (Read more)

TriggerBinding

In simple words, TriggerBinding specifies the mapping (binding) between event payloads received by the EventListener and parameters specified in a TriggerTemplate. For example, a PipelineResource template in a TriggerTemplate might require a git repository url. We specify the mapping between the right key in the event (eg: body.repository.url) and the parameter in TriggerTemplate by creating a TriggerBinding. (Read more)

Prerequisites

  • A publicly accessible OpenShift 4.x cluster. We should be able to expose a publicly accessible route. If you are using a local cluster (eg: CRC) you won’t be able to test Triggers with push events to a external git repository like Github. (OpenShift on AWS or any OpenShift 4.x Cluster which has a public URL)
  • Install OpenShift Pipelines (part 1: How to Install OpenShift-Pipelines on OpenShift 4.x)
  • Install Tetkon CLI ‘tkn’ on your local machine: https://github.com/tektoncd/cli#installing-tkn

Resources

Initial Setup

We will be using the same CICD Pipeline from the previous article.

Fork https://github.com/nikhil-thomas/Vote-CICD and clone it to your local machine.

$ git clone https://github.com/<you-github-username>/vote-cicd.git

Checkout branch part-3-cicd-pipeline-triggers

$ cd vote-cicdvote-cicd$ git checkout part-3-cicd-pipeline-triggersBranch 'part-3-cicd-pipeline-triggers' set up to track remote branch 'part-3-cicd-pipeline-triggers' from 'origin'.
Switched to a new branch 'part-3-cicd-pipeline-triggers'

At this point we should have the following directory structure.

vote-cicd
├── + 02-pipelineresources
├── 03-tasks
│ └── 01-oc-apply-deployment-task.yaml
├── 04-pipelines
│ └── 01-build-deploy-pipeline.yaml
├── + 05-pipelineruns
├── 06-pipeline-triggers
│ ├── 01-triggers-rbac.yaml
│ ├── 02-vote-cicd-triggertemplate.yaml
│ ├── 03_trigger-binding.yaml
│ ├── 04-event-listener.yaml
│ └── 05-eventlistener-route.yaml
├── 07-github-webhooks
│ ├── 01_create-webhook-user.yaml
│ ├── 02_webhook-secret.yaml
│ ├── 03_create-webhook-task.yaml
│ ├── 04.1_create-api-repo-webhook-run.yaml
│ └── 04.2_create-uii-repo-webhook-run.yaml
├── LICENSE
└── README.md

As we are going to create a TriggerTemplate which defines templates for PipelineResources and PipelineRuns, we don’t have to create PipelineResurces and PipelineRuns manually. Directories 02-pipelineresources and 05-pipelineruns are given as a reference.

Setup the Pipeline

We need to setup the CICD Pipeline which will be referenced by PipelineRuns triggered in reaction to events received by the Event-Listener.

The pipeline we will be using is build-and-deploy. We can see the definition in 04-pipelines/01-build-deploy-pipeline.yaml.

apiVersion: tekton.dev/v1alpha1
kind: Pipeline
metadata:
name: build-and-deploy
spec:
...
tasks:
- name: build-image
taskRef:
name: buildah-v0-8-0
kind: ClusterTask
...
- name: create-upate-deployment
taskRef:
name: oc-apply-deployment
...

The build-and-deploy pipeline uses 2 Tasks, buildah-v0–8–0 ClusterTask and oc-apply-deployment Task. The ClusterTask buildah-v0–8–0 is a default Task supplied by OpenShift-Pipelines-Operator. It should be already present on your cluster as we have installed OpenShift-Pipelines using OpenShift-Pipeline-Operator.

$ oc get clustertask buildah-v0-8-0NAME             AGE
buildah-v0-8-0 6h39m

The other task oc-apply-deployment is a custom Task defined in 03-tasks/ 01-oc-apply-deployment-task.yaml.

First let’s create a new project for our CICD Pipeline and Triggers.

$ oc new-project vote-cicdNow using project "vote-cicd" on server ...
...

Let’s create the custom Task,

vote-cicd$ oc apply -f 03-tasks/task.tekton.dev/oc-apply-deployment created

and the Pipeline.

vote-cicd$ c apply -f 04-pipelines/pipeline.tekton.dev/build-and-deploy created

If we switch to Developer Perspective on OpenShift WebConsole (using Top-Left drop down), we should see build-and-deploy Pipeline in vote-cicd project.

Adding Triggers to our Voting Application CICD

Now let’s add a TriggerTemplate, TriggerBinding, and an EventListener to our project.

TriggerTemplate

The definition of our TriggerTemplate is given in vote-cicd/06-pipeline-triggers/02-vote-cicd-triggertemplate.yaml. We can see the key parts of our TriggerTemplate below. In short, it specifies templates for:

  1. PipelineResource — type: git
  2. PipelineResource — type: image
  3. PipelineRun — pipelineRef: build-and-deploy
apiVersion: tekton.dev/v1alpha1
kind: TriggerTemplate
metadata:
name: vote-cicd-triggertemplate
spec:
...
resourcetemplates:
- apiVersion: tekton.dev/v1alpha1
kind: PipelineResource
...
- apiVersion: tekton.dev/v1alpha1
kind: PipelineResource
metadata:
name: image-source-$(params.gitrepositoryname)-$(uid)
namespace: $(params.namespace)
spec:
type: image
...
- apiVersion: tekton.dev/v1alpha1
kind: PipelineRun
metadata:
name: vote-cicd-$(params.gitrepositoryname)-$(uid)
namespace: $(params.namespace)
spec:
pipelineRef:
name: build-and-deploy
...

TriggerBinding

A TriggerBinding is a map from event payload data to parameters specified in a TriggerTemplate. The TriggerBinding for our TriggerTemplate can be found in vote-cicd/06-pipeline-triggers/03_trigger-binding.yaml.

apiVersion: tekton.dev/v1alpha1
kind: TriggerBinding
metadata:
name: vote-cicd-pipelinebinding
spec:
params:
- name: gitrevision
value: $(body.head_commit.id)
- name: namespace
value: vote-cicd
- name: gitrepositoryurl
value: $(body.repository.url)
- name: gitrepositoryname
value: $(body.repository.name)

The exact paths (keys) of parameter we need can be found by examining the event payload (eg: GitHub events).

Note:- The parameter namespace is hardcoded. It can be also parameterized. It can also be dropped from your TriggerTemplates and let Triggers use current Namespace.

EventListener

This component sets up a Service and listens for events. It also connects a TriggerTemplate (what to run) to a TriggerBinding (what to extract from events). The definition for our EventListener can be found in vote-cicd/06-pipeline-triggers/04-event-listener.yaml.

apiVersion: tekton.dev/v1alpha1
kind: EventListener
metadata:
name: votecicd-listener
spec:
serviceAccountName: tekton-triggers-sa
triggers:
- binding:
name: vote-cicd-pipelinebinding
template:
name: vote-cicd-triggertemplate

Note:- EventListener will setup a Service. We need to expose that Service as an OpenShift Route to make it publicly accessible. Refer: vote-cicd/06-pipeline-triggers/05-eventlistener-route.yaml.

Note:- At present RBAC needed by Triggers to manage Trigger Resources is not handled by the operator. Hence, we need to create them using vote-cicd/06-pipeline-triggers/01-triggers-rbac.yaml.

Let’s Create Trigger Resources.

vote-cicd$ oc apply -f 06-pipeline-triggersrole.rbac.authorization.k8s.io/tekton-triggers-role created
serviceaccount/tekton-triggers-sa created
rolebinding.rbac.authorization.k8s.io/tekton-triggers-rolebinding created
triggertemplate.tekton.dev/vote-cicd-triggertemplate created
triggerbinding.tekton.dev/vote-cicd-pipelinebinding created
eventlistener.tekton.dev/votecicd-listener created
route.route.openshift.io/vote-cicd-eventlistener created

Configuring GitHub WebHooks

Now let’s use the Triggers we have setup. We need to configure webhooks on frontend and backend source code repositories with the Route we exposed in the previous step.

Note:- Fork the backend and frontend source code repositories so that you have sufficient privileges to configure GitHub webhooks.

We can either configure the webhooks manually from GitHub web ui or automate the process using the create-webhook Task defined in vote-cicd/07-github-webhooks/03_create-webhook-task.yaml.

Create GitHub Access Token

Running the create-webhook Task needs your GitHub token to configure webhooks on your GitHub repositories. Create your GitHub access token with the following access: (refer: creating a personal access token)

  • public_repo
  • admin:repo_hook

Once you have created the token, add it to the Secret webhook-secret vote-cicd/07-github-webhooks/02_webhook-secret.yaml.

apiVersion: v1
kind: Secret
metadata:
name: webhook-secret
stringData:
token: # add your github token here
secret: random-string-data

Configuring Webhooks for vote-api and vote-ui

We need to create 2 TaskRuns (with TaskRef: create-webhook Task). One for vote-api repository and one for vote-ui repository. The TaskRuns are defined in vote-cicd2/07-github-webhooks. Make sure you edit the 2 TaskRuns with the following information with respect to your setup.

  1. GitHubOrg: your GitHub username (or your GitHub org name, depending on where your cloned vote-api and vote-ui
  2. GitHubUser: your GitHub username
  3. GitHubRepo: vote-api in one TaskRun and vote-ui in the other.
  4. ExternalDomain: The url of the Route we created it the above section — Adding Triggers to our Voting Application CICD. Run `oc get route vote-cicd-eventlistener` find the host URL for the route.

Example: vote-cicd/07-github-webhooks/04.1_create-api-repo-webhook-run.yaml

apiVersion: tekton.dev/v1alpha1
kind: TaskRun
metadata:
name: create-api-repo-webhook-run
spec:
taskRef:
name: create-webhook
inputs:
params:
- name: GitHubOrg
value: "<your user name or or org name>"
- name: GitHubUser
value: "<your user name>"
- name: GitHubRepo
value: "vote-api"
- name: GitHubSecretName
value: webhook-secret
- name: GitHubAccessTokenKey
value: token
- name: GitHubSecretStringKey
value: secret
- name: ExternalDomain
value: <route url from previous section>
timeout: 1000s
serviceAccount: tekton-triggers-createwebhook

Once we have filled in the GitHub token in the webhook-secret manifest and the details in 2 TaskRuns (frontend and backend), run:

vote-cicd$ oc apply -f 06-pipeline-triggersrole.rbac.authorization.k8s.io/tekton-triggers-createwebhook created
serviceaccount/tekton-triggers-createwebhook created
rolebinding.rbac.authorization.k8s.io/tekton-triggers-createwebhook created
secret/webhook-secret created
task.tekton.dev/create-webhook created
taskrun.tekton.dev/create-api-repo-webhook-run created
taskrun.tekton.dev/create-ui-repo-webhook-run created

Ensure that the 2 TaskRuns are completed successfully.

vote-cicd$ tkn taskrun lsNAME                          STARTED         DURATION     STATUS      
create-api-repo-webhook-run 2 minutes ago 26 seconds Succeeded
create-ui-repo-webhook-run 2 minutes ago 26 seconds Succeeded

Now we should see a webhook configured in your fork of frontend and backend source code repositories (on our GitHub Repo, go to Settings>Webhooks).

Let’s Trigger a PipelineRun

We have setup our Pipeline, Trigger and Webhooks. Suppose a push event or a pull request occur in the backend repo (vote-api) the following should happen.

  1. The configured webhook in vote-api GitHub repository should push the event to our route (exposed EventListener Service).
  2. The Event-Listner will pass the event to the TriggerBinding and TriggerTemplate pair.
  3. TriggerBinding will extract parameters needed for rendering the TriggerTemplate.
  4. Successful rendering of TriggerTemplate should create 2 PipelineResources (api-git and api-image) and a PipelineRun (build-and-deploy-vote-api)

We can test this by pushing a commit to vote-api repository from GitHub web ui or from terminal.

Let’s push an empty commit to vote-api repository.

vote-api$ git commit -m "empty-commit" --allow-empty && git push origin master...
Writing objects: 100% (1/1), 190 bytes | 190.00 KiB/s, done.
Total 1 (delta 0), reused 0 (delta 0)
To github.com:nikhil-thomas/vote-api.git
89a12e1..784d1c3 master -> master

Watch OpenShift WebConsole Developer perspective and a PipelineRun will be automatically created.

Note:- make sure that the Complete and Running filters are seelcted

Let’s trigger a PipelineRun for vote-ui as well.

vote-ui$ git commit -m "empty-commit" --allow-empty && git push origin master...
Writing objects: 100% (1/1), 188 bytes | 188.00 KiB/s, done.
Total 1 (delta 0), reused 0 (delta 0)
To github.com:nikhil-thomas/vote-ui.git
1073d7c..bc27f5f master -> master

Let’s Vote

When both the PipelineRuns succeed the backend and frontend Deployments, Services and frontend Service will be created (or updated on reruns).

vote-cicd$ oc get DeploymentNAME                   READY   UP-TO-DATE   AVAILABLE   AGE
el-votecicd-listener 1/1 1 1 121m
vote-api 1/1 1 1 5m6s
vote-ui 1/1 1 1 3m25s
vote-cicd$ oc get serviceNAME TYPE AGE
el-votecicd-listener ClusterIP 122m
vote-api ClusterIP 6m25s
vote-ui NodePort 4m44s
vote-cicd$ oc get routeNAME HOST/PORT
vote-cicd-eventlistener vote-cicd-eventlistener-vote-cicd.apps.nikhil42.devcluster.openshift.com
vote-ui vote-ui-vote-cicd.apps.nikhil42.devcluster.openshift.com
(Note:- output is edited to reducenoise)

go to the Host URL of vote-ui Route:

Note:- PipelineResources, PipelineRuns and Logs

PipelineResources and PipelineRuns

Each time the the TriggerTemplate is rendered as a result of an event in a source code Repository, the PipelineResources and PipelineRuns for that source code repository is re-created with a randomized name.

vote-cicd$ tkn resources lssource-repo-vote-api-qtpnk    git     url: https://github.com/nikhil-thomas/vote-api
source-repo-vote-ui-jkd9n git url: https://github.com/nikhil-thomas/vote-ui
image-source-vote-api-qtpnk image url: image-registry.openshift-image-registry.svc:5000/vote-cicd/vote-api:latest
image-source-vote-ui-jkd9n image url: image-registry.openshift-image-registry.svc:5000/vote-cicd/vote-ui:latest

vote-cicd$ tkn pipelineruns ls
NAME STARTED DURATION STATUS
vote-cicd-vote-ui-jkd9n 21 minutes ago 1 minute Succeeded
vote-cicd-vote-api-qtpnk 24 minutes ago 2 minutes Succeeded

Logs

We can view the logs either from OpensShift WebConsole Developer Perspective or from CLI (tkn pipelinerun logs command).

Summary

End-to-end CICD workflow with OpenShift Pipelines

  1. Write your CICD Pipeline
  2. Setup Triggers (TriggerTemplate, TriggerBinding, EventListener)
  3. Configure Webhooks
  4. Write code and push commits

Other Articles in this series

Reference

  1. TektonCD Triggers Getting Started
  2. What’s New in OpenShift 4.2 — Tekton Pipelines with GitHub Webhooks
  3. Triggers: Event Based Workflows for Tekton Pipelines and More! — Dibyo Mukherjee, Google

--

--