EventListeners
An EventListener is a Kubernetes object that listens for events at a specified port on your Kubernetes cluster.
It exposes an addressable sink that receives incoming event and specifies one or more Triggers.
The sink is a Kubernetes service running the sink logic inside a dedicated Pod.
Each Trigger, in turn, allows you to specify one or more TriggerBindings that allow
you to extract fields and their values from event payloads, and one or more TriggerTemplates
that receive field values from the corresponding TriggerBindings and allow Tekton Triggers to instantiate resources
such as TaskRuns and PipelineRuns with that data.
If you need to modify, filter, or validate the event payload data before passing it to a TriggerBinding, you can optionally specify one
or more Interceptors.
- Structure of an
EventListener - Specifying the Kubernetes service account
- Specifying
Triggers - Specifying
Resources - Specifying
Interceptors - Constraining
EventListenersto specific namespaces - Disabling Payload Validationn
- Labels in
EventListeners - Specifying
EventListenertimeouts - Annotations in
EventListeners - Understanding
EventListenerresponse - TLS HTTPS support in
EventListeners - Obtaining the status of deployed
EventListeners - Configuring logging for
EventListeners - Exposing an
EventListeneroutside of the cluster - Understanding the deployment of an
EventListener - Deploying
EventListenersin multi-tenant scenarios
Structure of an EventListener
An EventListener definition consists of the following fields:
- Required:
apiVersion- specifies the target API version, for exampletriggers.tekton.dev/v1alpha1kind- specifies that this Kubernetes resource is anEventListenerobjectmetadata- specifies data that uniquely identifies thisEventListenerobject, for example anamespec- specifies the configuration of yourEventListener:serviceAccountName- Specifies theServiceAccounttheEventListenerwill use to instantiate Tekton resources
- Optional:
triggers- specifies a list ofTriggersto execute upon event detectionresources- specifies the resources that will be available to the event listening servicenamespaceSelector- specifies the namespace for theEventListener; this is where theEventListenerlooks for the specifiedTriggersand stores the Tekton objects it instantiates upon event detectionlabelSelector- specifies the labels for which yourEventListenerrecognizesTriggersand instantiates the specified Tekton objects
See our Tekton Triggers examples for ready-to-use example EventListener definitions.
Specifying the Kubernetes service account
You must specify a Kubernetes service account in the serviceAccountName field that the EventListener will use to instantiate Tekton objects.
Tekton Trigger creates 2 clusterroles while installing with necessary permissions required for an eventlistener. You can directly create bindings for your serviceaccount with the clusterroles.
-
A Kubernetes RoleBinding with
tekton-triggers-eventlistener-rolesclusterrole. -
A Kubernetes ClusterRoleBinding with
tekton-triggers-eventlistener-clusterrolesclusterrole.You can checkout an example here.
-
If you’re using
namespaceSelectorsin yourEventListener, you will have to create an additionalClusterRoleBindingwithtekton-triggers-eventlistener-rolesclusterrole.
Specifying Triggers
You can optionally specify one or more Triggers that define the actions to take when the EventListener detects a qualifying event. You can specify either a reference to an
external Trigger object or reference/define the TriggerBindings, TriggerTemplates, and Interceptors in the Trigger definition. A Trigger definition
specifies the following fields:
name- (optional) a valid Kubernetes name that uniquely identifies theTriggerinterceptors- (optional) a list ofInterceptorsthat will process event payload data before passing it to the associatedTriggerBindingbindings- (optional) a list ofTriggerBindingsfor thisTrigger; you can either reference existingTriggerBindingsor embed their definitions directlytemplate- (optional) a list ofTriggerTemplatesfor thisTrigger; you can either reference existingTriggerTemplatesor embed their definitions directlytriggerRef- (optional) a reference to an externalTrigger
Below is an example Trigger definition that references the desired TriggerBindings, TriggerTemplates, and Interceptors:
triggers:
- name: trigger-1
interceptors:
- github:
eventTypes: ["pull_request"]
bindings:
- ref: pipeline-binding # Reference to a TriggerBinding object
- name: message # Embedded Binding
value: Hello from the Triggers EventListener!
template:
ref: pipeline-template
Below is an example Trigger definition that specifies a reference to an external Trigger object:
triggers:
- triggerRef: trigger
Below is an example Trigger definition that embeds a triggerTemplate definition directly:
triggers:
- name: "my-trigger"
template:
spec:
params:
- name: "my-param-name"
resourceTemplates:
- apiVersion: "tekton.dev/v1beta1"
kind: TaskRun
metadata:
generateName: "pr-run-"
spec:
taskSpec:
steps:
- image: ubuntu
script: echo "hello there"
Below is an example Trigger definition tailored to a multi-tenant scenario in which you may not
want all of your Trigger objects to have the same permissions as the EventListener. In such case,
you can specify a different service account at the Trigger level. This service account overrides
the service account specified in the EventListener.
triggers:
- name: trigger-1
serviceAccountName: trigger-1-sa
interceptors:
- github:
eventTypes: ["pull_request"]
bindings:
- ref: pipeline-binding
- ref: message-binding
template:
ref: pipeline-template
You must update the Role assigned to the service account specified in the EventListener as shown below
to allow it to impersonate the service account specified in the Trigger:
rules:
- apiGroups: [""]
resources: ["serviceaccounts"]
verbs: ["impersonate"]
Specifying Resources
You can optionally customize the sink deployment for your EventListener using the resources field. It accepts the following types of objects:
- Kubernetes Resource using the
kubernetesResourcefield - Custom Resource objects via the
CustomResourcefield
Legal values for the PodSpec and Containers sub-fields for both kubernetesResource and CustomResource fields are:
ServiceAccountName
NodeSelector
Tolerations
Volumes
Containers
Legal values for the Containers sub-field are:
Resources
VolumeMounts
Env
Specifying a kubernetesResource object
Below is an example resources: field definition specifying a kubernetesResource object:
spec:
resources:
kubernetesResource:
serviceType: NodePort
spec:
template:
metadata:
labels:
key: "value"
annotations:
key: "value"
spec:
serviceAccountName: tekton-triggers-github-sa
nodeSelector:
app: test
tolerations:
- key: key
value: value
operator: Equal
effect: NoSchedule
Specifying Replicas
You can optionally use the replicas field to instruct Tekton Triggers to deploy more than one instance of your EventListener in individual Kubernetes Pods.
If you do not specify this value, the default number of instances (and thus, the number of respective Pods) per EventListener is 1. If you set a value for the replicas field
while creating or upgrading the EventListener's YAML file, that value overrides any value you set manually later as as well as a value set by any other deployment
mechanism, such as HPA.
Specifying a CustomResource object
You can specify a Kubernetes Custom Resource object using the CustomResource field. This field has one sub-field, runtime.RawExtension that allows you to specify dynamic objects.
Contract for the CustomResource object
The CustomResource object must abide by the contract shown below.
Contract-mandated CRD structure for the spec field:
spec:
template:
metadata:
spec:
Contract-mandated CRD structure for the status field:
type EventListenerStatus struct {
duckv1beta1.Status `json:",inline"`
// EventListener is addressable via the DNS address of the sink.
duckv1alpha1.AddressStatus `json:",inline"`
}
Note: The CRD must follow the WithPod{} spec.
Below is an example resources: field definition specifying a CustomResource object using a Knative Service:
Note: This example assumes that Knative is installed on your cluster.
spec:
resources:
customResource:
apiVersion: serving.knative.dev/v1
kind: Service
# metadata:
# name: knativeservice # name is optional; if not specified, Triggers substitutes the EventListener's name with an "el-" prefix, for example: el-github-knative-listener
spec:
template:
spec:
serviceAccountName: tekton-triggers-example-sa
containers:
- resources:
requests:
memory: "64Mi"
cpu: "250m"
limits:
memory: "128Mi"
cpu: "500m"
Specifying Interceptors
An Interceptor is a “catch-all” event processor for a specific platform that runs before the TriggerBinding. It allows you to perform payload filtering,
verification (using a secret), transformation, define and test trigger conditions, and implement other useful processing. Once the event data passes through
an Interceptor, it then goes to the Trigger before you pass the payload data to the TriggerBinding. You can also use an Interceptor to modify the
behavior of the associated Trigger.
For more information, see Interceptors.
Constraining EventListeners to specific namespaces
You can optionally specify a list of namespaces in which your EventListener will search for Triggers and instantiate the specified Tekton objects using the namespaceSelector field.
If you omit this field, your EventListener will only recognize Triggers specified in its definition or found under one or more specified target labels.
Below is an example namespaceSelector field that configures the EventListener to use the foo and bar namespaces:
namespaceSelector:
matchNames:
- foo
- bar
If you want your EventListener to recognize Triggers across your entire cluster, use a wildcard as the only namespace:
namespaceSelector:
matchNames:
- *
Constraining EventListeners to specific labels
You can optionally specify the labels for which your EventListener recognizes Triggers and instantiates the specified Tekton objects using the labelSelector field.
This field uses the standard Kubernetes labelSelector mechanism and supports the matchExpressions sub-field. If you omit the labelSelector field, the EventListener
accepts all resource labels.
Below is an example labelSelector field definition that constrains your EventListener to only recognize Triggers within its own namespace that are labeled foo=bar:
labelSelector:
matchLabels:
foo: bar
Below is an example labelSelector field definition that uses the matchExpression sub-field to specify expressions that allow the EventListener to recognize Triggers
across all namespaces in the cluster:
namespaceSelector:
matchNames:
- *
labelSelector:
matchExpressions:
- {key: environment, operator: In, values: [dev,stage]}
- {key: trigger-phase, operator: NotIn, values: [testing]}
Specifying EventListener timeouts
An EventListener times out if it cannot process an event request within a timeout specified in controller.yaml. The timeouts are as follows:
-el-readtimeout: Read timeout; default is 5 seconds.-el-writetimeout: Write timeout; default is 40 seconds.-el-idletimeout: Idle timeout; default is 120 seconds.-el-timeouthandler: Server route handler timeout; default is 30 seconds.
Disabling Payload Validation
To disable incoming payload validation for an EventListener, you can define an annotation tekton.dev/payload-validation: false
on EventListener.
apiVersion: triggers.tekton.dev/v1alpha1
kind: EventListener
metadata:
name: eventlistener
annotations:
tekton.dev/payload-validation: "false"
By default, payload validation is enabled and will be disabled only if the annotation is defined. Removing the annotation will enable the payload validation.
Labels in EventListeners
By default, each EventListener automatically attaches the following labels to all resources it instantiates:
| Name | Description |
|---|---|
| triggers.tekton.dev/eventlistener | Name of the EventListener that instantiated the resource. |
| triggers.tekton.dev/trigger | Name of the Trigger that instantiated the resource. |
| triggers.tekton.dev/eventid | UID of the incoming event. |
Note: Because they’re used as labels, EventListener and Trigger names must conform to the Kubernetes syntax and character set requirements.
Annotations in EventListeners
Tekton Triggers propagates all annotations that you include in your EventListener to the Kubernetes service and deployment created by that EventListener.
Keep in mind that annotations propagated from the EventListener override annotations already present in its Kubernetes service and deployment.
Below is an example load balancer protocol annotation in an EventListener definition that automatically propagates to the EventListener's service:
apiVersion: triggers.tekton.dev/v1alpha1
kind: EventListener
metadata:
name: eventlistener
annotations:
service.beta.kubernetes.io/aws-load-balancer-backend-protocol: https
Understanding EventListener response
An EventListener responds with a 202 ACCEPTED HTTP response when the EventListener
has been able to process the request and selected the appropriate triggers to process
based off the EventListener configuration.
After detecting an event, the EventListener responds with the following message:
{
"eventListener": "listener",
"namespace": "default",
"eventListenerUID": "ea71a6e4-9531-43a1-94fe-6136515d938c",
"eventID": "14a657c3-6816-45bf-b214-4afdaefc4ebd"
}
eventListenerUID- UID of the target EventListener.eventID- UID assigned to this event request
Deprecated Fields
These fields are included in EventListener responses, but will be removed in a future release.
eventListener- name of the target EventListener. UseeventListenerUIDinstead.namespace- namespace of the target EventListener. UseeventListenerUIDinstead.
TLS HTTPS support in EventListeners
Tekton Triggers supports both HTTP and TLS-based HTTPS connections. To configure your EventListener for TLS,
add the TLS_CERT and TLS_KEY reserved environment variables using the secretKeyRef variable type, then
specify a secret containing the cert and key files. See TEP-0027
and our TLS configuration example for more information.
Obtaining the status of deployed EventListeners
Use the following command to get a list of EventListeners deployed on your cluster along with their statuses:
kubectl get el
You will get a response similar to the following:
NAME ADDRESS AVAILABLE REASON READY REASON
tls-listener-interceptor http://el-tls-listener-interceptor.default.svc.cluster.local True MinimumReplicasAvailable
Where for each returned line, the column values are, from left to right:
NAME- name of theEventListenerADDRESS- IP address or URL of theEventListenerAVAILABLE- readiness state of the associatedDeploymentandServiceREASON- reason for the value displayed in theAVAILABLEcolumnREADY- readiness state of the Kubernetes Custom Resource object specified in theEventListenerREASON- reason for the value displayed in theREADYcolumn
Note: The status messaging described above is being refactored. For more information, see Issue 932.
Configuring logging for EventListeners
You can configure logging for your EventListener using the config-logging-triggers ConfigMap located in the EventListener's namespace.
Tekton Triggers automatically creates and populates this ConfigMap with default values described in config-logging.yaml.
To access your EventListener logs, query your cluster for Pods whose eventlistener label matches the name of your EventListener object. For example:
kubectl get pods --selector eventlistener=my-eventlistener
Configuring metrics for EventListeners
The following pipeline metrics are available on the eventlistener Service on port 9000.
| Name | Type | Labels/Tags | Status |
|---|---|---|---|
eventlistener_triggered_resources |
Counter | kind=<kind> |
experimental |
eventlistener_event_count |
Counter | status=<status> |
experimental |
eventlistener_http_duration_seconds_[bucket, sum, count] |
Histogram | - | experimental |
Several kinds of exporters can be configured for an EventListener, including Prometheus, Google Stackdriver, and many others.
You can configure metrics using the config-observability-triggers config map in the EventListener namespaces.
There is a config-observability-triggers configmap in the tekton-pipelines namespace that can be configured for the operation of the Triggers
webhook and controller components.
See the Knative documentation for more information about available exporters and configuration values.
Exposing an EventListener outside of the cluster
By default, ClusterIP services such as EventListeners are only accessible within the cluster on which they are running.
You can expose them outside of the cluster in one of the following ways:
- Using a Kubernetes
Ingressobject - Using the NGINX Ingress Controller
- Using OpenShift Route
Exposing an EventListener using a Kubernetes Ingress object
Use the Tekton create-ingress task to configure an Ingress object using self-signed certificates.
If you are using a cloud-based Kubernetes solution such as Google Kubernetes Engine, the Kubernetes Ingress object will not work. Instead,
use the NGINX Ingress Controller as described in the next section.
Exposing an EventListener using the NGINX Ingress Controller
Below are instructions for installing and configuring the NGINX Ingress Controller with Tekton Triggers on Google Kubernetes Cluster version 1.13.7-gke.24.
For instructions on installing the NGINX Ingress Controller on other Kubernetes services as well as additional installation options for the example below,
see the NGINX Ingress Controller Installation Guide.
-
Install the NGINX Ingress Controller:
kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v0.34.1/deploy/static/provider/cloud/deploy.yaml -
Obtain the name of your
EventListenerservice:kubectl get el <EVENTLISTENR_NAME> -o=jsonpath='{.status.configuration.generatedName}{"\n"}' -
Instantiate the
Ingressobject:apiVersion: extensions/v1beta1 kind: Ingress metadata: name: ingress-resource annotations: kubernetes.io/ingress.class: nginx nginx.ingress.kubernetes.io/ssl-redirect: "false" spec: rules: - http: paths: - path: / backend: serviceName: EVENT_LISTENER_SERVICE_NAME # REPLACE WITH YOUR SERVICE NAME FROM STEP 2 servicePort: 8080See NGINX Configuration for more information on configuring the NGINX Ingress Controller.
-
Obtain the IP address of the
Ingressobject:kubectl get ingress ingress-resource -
Test the configuragion with
curlor set up a GitHub Webhook that sends events to it.
Exposing an EventListener using Openshift Route
Below are instructions for configuring an OpenShift 4.2 cluster running API version v1.14.6+32dc4a0. For more information,
see Route Configuration.
-
Obtain the name of your
EventListenerservice:oc get el <EVENTLISTENR_NAME> -o=jsonpath='{.status.configuration.generatedName}' -
Expose the
EventListenerservice:oc expose svc/[el-listener] # REPLACE el-listener WITH YOUR SERVICE NAME FROM STEP 1 -
Obtain the IP address of the exposed route:
oc get route el-listener -o=jsonpath='{.spec.host}' # REPLACE el-listener WITH YOUR SERVICE NAME FROM STEP 1 -
Test the configuragion with
curlor set up a GitHub Webhook that sends events to it.
Understanding the deployment of an EventListener
Below is a high-level walkthrough through the deployment of an EventListener using a GitHub example provided by Tekton Triggers.
-
Instantiate the example
EventListeneron your cluster:kubectl create -f https://github.com/tektoncd/triggers/tree/master/examples/githubTekton Triggers creates a new
DeploymentandServicefor theEventListener. using theEventListenerdefinition,metadata.labels, and pre-existing values such as containerImage,Name, andPort. Tekton Triggers uses theEventListenername prefixed withel-to name theDeploymentandServicewhen instantiating them. For exampl,e if theEventListenername isfoo, theDeploymentandServicenames are namedel-foo. -
Use
kubectlto verify theDeploymentis running on your cluster:kubectl get deployment NAME READY UP-TO-DATE AVAILABLE AGE el-github-listener-interceptor 1/1 1 1 11s -
Use
kubectlto verify theServiceis running on your cluster:kubectl get svc NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE el-github-listener-interceptor ClusterIP 10.99.188.140 <none> 8080/TCP 52s -
Obtain the URL on which the
EventListeneris listening for events:kubectl get eventlistener NAME ADDRESS AVAILABLE REASON github-listener-interceptor http://el-github-listener-interceptor.ptest.svc.cluster.local:8080 True MinimumReplicasAvailableSee our GitHub
EventListenerexample to try instantiating anEventListenerlocally.
Deploying EventListeners in multi-tenant scenarios
EventListeners are effectively Tekton clients that use HTTP to bypass the normal Kubernetes authentication
mechanism established through kubeconfig files and the kubectl config command tree. Because of this,
you must be conscious of your configuration decisions, such as:
- How to securely expose each
EventListenerto the outside of your cluster, - How to securely control how each
EventListenerand its associated objects, such asInterceptors, interact with data on your cluster.
At the minimum, each EventListener specifies its own Kubernetes Service account as explained earlier and
it acts on all events it receives with the permissions of that service account. If your business needs mandate
more granular permission control across the Triggers and Interceptors specified in your EventListeners,
you have the following options:
- Deploy each
EventListenerin its own namespace - Deploy multiple
EventListenersin the same namespace - Specify a separate service account for each
Trigger
Deploying each EventListener in its own namespace
In this scenario, you create multiple EventListeners that in turn use a variety of Triggers and Interceptors,
each EventListener gets its own namespace. This way, you can use a different service account for each namespace
and tailor the permissions of those accounts to the functionality of their corresponding EventListeners. Because
creating a namespace often instantiates the necessary service accounts based on pre-configured permissions, this
also simplifies the deployment process as you simply need to update the permissions associated with those accounts.
However, this approach has the following drawbacks:
- Namespaces with separately associated
SecretsandServiceAccountscan be the most expensive items in the Kubernetesetcdstore; on large clusters, the capacity of theetcdstore can become a concern. - Since each
EventListenerrequires its own HTTP port to listen for events, you must configure your network to allow access to each corresponding IP address and port combination unless you configure an ingress abstraction layer, such as the KubernetesIngressobject, the NGINX Ingress Controller, or OpenShift Route.
Deploying multiple EventListeners in the same namespace
In this scenario, you create multiple EventListeners in the same namespace. This will require customization of
the associated service account(s), secret(s), and RBAC, since the automatically generated defaults are not always
ideal, but you will not incur a significant etcd store cost as in the multiple namespace scenario. Network security
and configuration overhead concerns, however, still apply as described earlier. You can also achieve a similar result
by specifying a separate service account for each Trigger used across your EventListener pool at the cost of
increased administration overhead.
Feedback
Was this page helpful?
Thanks! Tell us how we can further improve.
Sorry about that. Tell us how we can further improve.