This proposal addresses the specifications as outlined in the initial design proposal (https://docs.google.com/document/d/1fngeNn3kGD4P_FTZjAnfERcEajS7zQhSEUaN7BYIlTw/edit#heading=h.iyqzt1brkg3o), namely:
- Whether or not to have first class support of CloudEvents
- How to create an addressable endpoint
This proposal takes the perspective of getting things out the door "as quickly as possible", but not at the cost of diminishing the Triggers
design. Rather, an initial release might provide insights from other users and have us consider things we had not otherwise. This could help build a base to iterate from.
Cloud Events
From the CloudEvents
specification,
Events are everywhere. However, event producers tend to describe events differently.
CloudEvents
are a standardized way to format messages. The project justification is that without such a standardized format "developers must constantly re-learn how to consume events". This seems like a good idea to me, but CloudEvent
adapters is where I draw skepticism. The specification mentions adapters as follows:
Since not all event producers generate CloudEvents
by default, there is documentation describing the recommended process for adapting some popular events into CloudEvents
, see CloudEvents Adapters.
Since the addressable endpoint provided by an EventListener
is a terminal (the event is consumed/not be emitted further), it seems unclear why Triggers
should convert the payload into a CloudEvent
. Although adapters could be provided for the "popular events" (e.g., GitHub, GitLab, DockerHub), since these are likely the primary concern, this already seems like bespoke implementation for events within Triggers
. I understand anything bespoke as the inverse of the intent behind the project since the power of Triggers
is in supporting any event. This is accomplished through user provided event bindings where the structure of the data must be known. This is the only stipulation, but it allows for the intended decoupling from vendors. CloudEvents
is working to standardize payload structures, but in the end, the payload is always going to be pushed down somewhere (https://github.com/cloudevents/sdk-go/blob/master/pkg/cloudevents/event.go#L13) because producers produce different things, which ties back into the idea of handling arbitrary payloads.
If Triggers
is coupled to CloudEvents
, it will require that we enumerate an adapter for each event type. Assuming this path, one further issue to consider here is how to determine if an event is actually a CloudEvent
because otherwise these adapters will wrap CloudEvents
into yet another CloudEvent
, which would be unintended. With this adapter pattern, it seems like it hinges upon the assumption that the incoming events are not CloudEvents
. First class CloudEvents
also have a side effect that users who are familiar with the payload they should be receiving now have to know to go through the CloudEvent
envelope rather than the raw data when constructing event bindings.
TriggerBinding
event bindings necessitate that the structure of the data was already known. In this way, it should not matter if the event is a CloudEvent
. The popular events like GitHub and GitLab (and likely others) provide headers that best provide the concept of an "event type" that can be used agnostic of CloudEvents
. This can address the concern of multiple TriggerBindings
with distinct events on a single EventListener
.
With optional headers to match against event types, TriggerBindings
could look as follows:
apiVersion: tekton.dev/v1alpha1
kind: TriggerBinding
metadata:
name: simple-pipeline-binding
namespace: default
spec:
templateRef:
name: simple-pipeline-template
serviceAccount: default
headerMatch:
- X-GitHub-Event: issues
params:
- name: gitrevision
value: ${event.head_commit.id}
- name: gitrepositoryurl
value: ${event.repository.url}
Conclusion
Triggers
should not provide first class support for CloudEvents
- There is a performance cost in wrapping messages
- The benefit of the
CloudEvent
abstraction to Triggers
is unclear
- Wrapping can be potentially error prone
- Writing adapters is in contrast to the strengths of parsing arbitrary messages
- Event bindings logic becomes unclear
- Will take time to implement
Addressable Endpoint
The pods generated by the EventListener
need to be (at least conditionally) addressable external to the cluster. One way to accomplish this is to use Knative eventing. Knative uses Istio
as the underlying technology to expose an address. In any case, the underlying resources that are created to create the external endpoint devolve to an Ingress
and/or a LoadBalancer service
.
For the sake of decoupling from all unnecessary components, a simplistic solution would involve creating a LoadBalancer Service
that refers to the Deployment
(as underway here) so that it can properly consume events. Most cloud providers have baked in implementations for LoadBalancers
as well, which allows us to leverage this "without paying". To the effect of being configurable, we could (later or otherwise) allow for an embedded specification of a service rather than making all the assumptions about how the LoadBalancer
should be configured.
Conclusion
Use LoadBalancer Services
to make the EventListener
pods addressable
- Does not require any installation dependencies
- Supported by most clouds for "free"
- We have control on how this is configured
- Less moving parts to fail
- Should be easy