Triggering your Tekton Pipelines on a Github Push Event
In a previous blog post we’ve used Tekton Pipelines to set up a simple pipeline that runs tests, builds a docker image and pushes it to a registry.
In this blog post we’re going to take a look at Tekton Triggers and integrate it with GitHub. We’re going to setup a GitHub webhook that will automatically run our pipeline when a PR is merged to the default branch (in our case it would be
For this tutorial we need a Kubernetes cluster with an ingress-controller installed that can give us an external IP. In my demo I would be using the Openshift 4.8 cluster as it can give us an external IP with the help of
We also need a GitHub repository where we can add the webhook.
Tekton Triggers requires Tekton Pipelines to be installed. We also need to install the core interceptors (GitHub, GitLab, BitBucket, and CEL) manifests as we’ll use them later on.
By default all resources will be installed in the
To install Tekton Pipelines refer to the installation guide. Once the Pipelines are installed successfully we can now move ahead to install the Triggers. To install Triggers on kubernetes you can run the following command
kubectl apply -f https://storage.googleapis.com/tekton-releases/triggers/previous/v0.15.1/release.yaml
kubectl apply -f https://storage.googleapis.com/tekton-releases/triggers/previous/v0.15.1/interceptors.yaml
If you are using an OpenShift cluster then you need to run the following commands first before applying the above manifests
oc adm policy add-scc-to-user anyuid -z tekton-triggers-controller
oc adm policy add-scc-to-user anyuid -z tekton-triggers-core-interceptors
oc adm policy add-scc-to-user anyuid -z tekton-triggers-webhook
In my tutorial I am installing Pipelines and Triggers using upstream release but if you are an
OpenShift user then you can install Tekton Pipelines and Triggers with the help of
OpenShift Pipelines operator which is available in OperatorHub in order to reduce all the above steps. To install you can follow the installation guide.
In this blog post I am going to trigger an API whenever there is a change in particular file and for that I need two tasks. First Task will check whether the file was present in the commit or not and second task which is going to make a CURL request to the API. The two tasks can be found below:
The above task takes two parameters first is the commits array which comes from the json when payload of push event emitted by Github and second one is the file which we want to check whether changed or not. Now let’s apply it
$ kubectl create ns triggers-demo
$ kubectl -n triggers-demo apply --filename https://gist.githubusercontent.com/vinamra28/ff7852770a9b453135e534bde5ad818c/raw/c94956b53a48b9095af6ce4dcf3045be226ce847/check-file-changed.yaml
PS: please ignore the python script as I am bad at it 😅
Task can be installed by running the following command
$ tkn hub install task curl -n triggers-demo
We can now go ahead and create the
Pipeline which will be triggered on an github
$ kubectl -n triggers-demo apply --filename https://gist.githubusercontent.com/vinamra28/46b18aac9dcf66559d0f30005534ab6a/raw/ab17b3423570647dfcbe2fb106e974bd7408db2f/triggers-pipeline.yaml
Now it’s time to create the resources related to
Creating Resources for Tekton Triggers
For our project we need to create the following resources:
EventListener: A Kubernetes Service that listens for incoming HTTP requests and executes a Trigger.
Trigger: Decides what to do with the received event. Sets a TriggerBinding, TriggerTemplate and Interceptor to run.
TriggerBinding: Specifies the data to be extracted from the request and saved as parameters. This data will be passed to the TriggerTemplate.
TriggerTemplate: A template of a resource (TaskRun/PipelineRun) to be created when an event is received.
Interceptor: Processes an event to do custom validation or filtering.
Before we start with applying the Triggers manifests let’s first configure the RBAC. You can run the below to configure the RBAC:
$ kubectl -n triggers-demo --filename https://gist.githubusercontent.com/vinamra28/a9074c08f8b05a7fd657b682fdcb0e0d/raw/aba3ec62664b8511d1ab16c5310ddc494debe26c/triggers-demo-rbac.yaml
Note: Your RBAC configuration might vary depending on the permissions you are having.
We can now go ahead and start creating Trigger resources.
EventListener processes an incoming request and executes a
EventListenerlooks like this:
- triggerRef: github-listener
After receiving the incoming request it will execute the
Trigger decides what to do with the received event. Our
Trigger looks like this:
- name: "secretRef"
- name: "eventTypes"
- name: "filter"
value: body.ref == 'refs/heads/trigger-config'
- ref: github-binding
Our github-listener trigger will then make use of
Interceptor’s. An Interceptor let’s us validate or modify incoming requests before they trigger a
The first interceptor we’re running is called
github. It’s part of the core interceptors that we installed above. It makes sure that the request:
- has a valid format for GitHub webhooks
- matches a pre-defined secret (that we have set while setting the
- matches the
The github interceptor requires a secret token. This token is set when creating the webhook in GitHub and will be validated by the github interceptor when the request arrives. Below is how the secret looks:
The second interceptor we’re using is called
cel and is also included in the core interceptor manifests that we installed above. Interceptors are executed in the order they’re specified. The cel interceptor will run after the github interceptor.
It let’s us specify a CEL filter expression that will be applied to requests.
We’ll apply this filter expression because GitHub
push events are sent for every action performed on any of the branch present in the configured github repository.
For this tutorial we only need to know when a PR was merged in
trigger-config branch or a commit was pushed into that branch. If you want to read more about CEL expressions then you can refer the doc.
After the Trigger is done validating and modifying the incoming request, we need to extract values from it and bind them to variables that we can later use in our Pipeline. This is what a
TriggerBinding is used for. Our TriggerBinding looks like this:
- name: gitRepository
- name: commits
We’re only interested in the following two fields out of which only one is necessary to perform the check and one is just to keep as annotation:
- gitRepository: The html URL of the repo which can be stored as annotation so that we can know from which repo the event happened.
- commits: the commits which were the part of push event.
The parameters are then passed to a
A TriggerTemplate is responsible for dynamically generating a resource. In our case it’s a
The TriggerTemplate receives the two variables from the previously created TriggerBinding and makes them available under
- name: commits
description: The commits which got pushed
- name: gitRepository
description: The git repository that hosts context
- apiVersion: tekton.dev/v1beta1
- name: commits
- name: filename
- name: urlToCurl
- name: options
["-i", "-k", "-X", "GET"]
Note that to access variables from a triggertemplate inside a resourcetemplate they need to be prefixed with
For GitHub to be able to send a request to our event listener we need to expose it by creating an Ingress resource and pointing it to our event listener service:
- path: /hooks
An EventListener will create a service with the
el- prefix followed by the name of the event-listener. Our event-listener is named
trigger-demo-el, so the EventListener Service is named
el-trigger-demo-el. EventListener services will always use port 8080.
Make sure to note the external IP address of your ingress. In this example it’s
$ kubectl get ingress
NAME CLASS HOSTS ADDRESS PORTS AGE
ingress-resource <none> * 220.127.116.11 80 26d
If you are using OpenShift then you can create a route by exposing the service by running the command
oc expose svc/el-trigger-demo-el . You can then get the route by running the command
oc get route .
We can now send GitHub webhook requests to
http://18.104.22.168/hooks or the route obtained from Openshift and automatically trigger a PipelineRun.
Adding the webhook to Github
In your GitHub repo go to
Settings -> Webhooks and click
Add Webhook. The fields we need to set are:
- Payload URL: Your external IP Address from the Ingress with
/hookspath or the
- Content type:
1234567which should match the secret value created above.
Under events select
Just the push event.
After saving the webhook, GitHub will send a ping event. It will be filtered out by our Interceptor which only allows
push events, but we can check the EventListener Pod logs to verify it by running
$ kubectl get pods | grep el-trigger-demo-el
el-trigger-demo-el-1df7f66d57-tqe6k 1/1 Running 0 13s
$ kubectl logs el-trigger-demo-el-1df7f66d57-tqe6k
"msg": "interceptor stopped trigger processing: rpc error: code = FailedPrecondition desc = event type ping is not allowed",
Creating a branch and testing the Trigger
Let’s test that everything works by creating a branch named
trigger-config, either manually or using the GitHub CLI:
git switch -c trigger-config
git commit --allow-empty -m "trigger webhook"
git push origin trigger-config
And checking for a PipelineRun to get created:
$ kubectl get pr
NAME SUCCEEDED REASON STARTTIME COMPLETIONTIME
config-refresh-run-qfvsx True Succeeded 73s 44s
We can see that everything worked. The pipeline was triggered and the run succeeded.
Follow and hit me up on Twitter @jvinamra776 if you have any questions or comments. If I’ve made a mistake or if there is something that I have missed out in this article be sure to let me know so that I can get it corrected.
Do follow me up on medium for more Tekton related stuffs 😉.