云原生CI/CD:Tekton之trigger介绍

云原生CI/CD:Tekton之trigger组件

在这里插入图片描述

简介

上面背景图片用了一张手枪扳机的图片,啥意思呢?trigger对于pipeline的作用就像扳机对于手枪的作用的,读完文章再来体会这句话。
前面我们学过tekton的pipeline组件,里面可以运行自定义工作流任务,而这些工作流任务例如task和pipeline都需要对象的触发对象例如taskrun和pipelineRun。触发的方式有两种:手动kubectl apply 文件触发和client-go触发。tekton为大家选择第三种方式,使用api接口触发。这就是本讲要着重讲的tekton的另一个组件trigger。

触发器Trigger使用户能够将事件中的字段映射到资源模板中,换句话说,这允许事件既可以建模也可以将其实例化为tekton资源。对于tektoncd / pipeline,触发器使得事件中的参数轻易封装到PipelineRuns、PipelineResources等对象中
在这里插入图片描述
上面这张是trigger的原理图,就是使用eventListener(事件监听器)监听事件,监听到事件后由triggerbinding将json数据解析并传送到triggerTemplate,而triggertemplate根据传入参数进行解析最后实例化tekton的资源(task,taskrun,pipeline等对象),要是实例化生成taskrun和pipelineRun,那就可以实现对流水线的触发。整个过程分工明确,每个对象都能做到解耦复用,设计理念非常棒。

Trigger中的核心概念

  • TriggerTemplate:TriggerTemplate是可以用于模板化资源的资源;根据传入参数,实例化k8s中tekton的对象资源(例如task,taskrun等)
  • TriggerBinding:使用TriggerBindings可以捕获事件中的字段并将其存储为参数,将参数传入triggerTemplate。故意将TriggerBindings与TriggerTemplates分开以鼓励它们之间的重用(就是解耦)
  • EventListener:EventListener是trigger定义的CRD资源,它允许用户使用HTTP请求的方式传入事件。 EventListeners需对外开放服务,才能让事件进来。用户可以声明TriggerBindings以从事件中提取字段,并将其应用于TriggerTemplates以创建Tekton资源。此外,EventListeners允许使用事件拦截器进行轻量级的事件处理;
  • ClusterTriggerBinding:ClusterTriggerBindings与TriggerBinding相似,均用于从事件中提取字段。唯一的区别是它是集群范围的,旨在鼓励集群范围内的可重用性。您可以在任何名称空间的任何EventListener中引用ClusterTriggerBinding。

具体使用

TriggerTemplate, TriggerBinding, EventListener, ClusterTriggerBinding都是CRD对象,下面就TriggerTemplate, TriggerBinding, EventListener, ClusterTriggerBinding的使用进行介绍:

TriggerTemplate

定义:TriggerTemplate是可以模板化tekton资源的资源,TriggerTemplate可使得参数在资源模板中任何位置被使用。简而言之,triggerTempate就像定义了一个完整的函数,它定义了函数所使用的形参和函数体,triggerTemplate就等着triggerBinding传入参数,然后实例化资源对象。

看下triggerTemplate的使用,你会更清楚。

apiVersion: triggers.tekton.dev/v1alpha1
kind: TriggerTemplate #TriggerTemplate
metadata:
  name: pipeline-template
spec:
  params: #参数定义
  - name: gitrevision
    description: The git revision
    default: master
  - name: gitrepositoryurl
    description: The git repository url
  - name: message
    description: The message to print
    default: This is the default message
  - name: contenttype
    description: The Content-Type of the event
  resourcetemplates: #资源模板, 将参数传入资源模板,实例化一个pipelinerun
  - apiVersion: tekton.dev/v1beta1
    kind: PipelineRun   
    metadata:
      generateName: simple-pipeline-run-
    spec:
      pipelineRef:
        name: simple-pipeline #pipelineRun所运行的pipeline
      params:
      - name: message
        value: $(params.message)  #这些参数都是上面定义的参数
      - name: contenttype
        value: $(params.contenttype) #这些参数都是上面定义的参数
      resources:
      - name: git-source
        resourceSpec:
          type: git
          params:
          - name: revision
            value: $(params.gitrevision)#这些参数都是上面定义的参数
          - name: url
            value: $(params.gitrepositoryurl)#这些参数都是上面定义的参数

与pipeline和task对象类似,TriggerTemplates并不会做任何实际的工作,而是充当应创建哪些资源的蓝图。上面的例子实例化了tekton的PipelineRun资源,你也可以创建其他tekton的资源。你可以先在集群中创建pipelineRun所使用的pipeline和task资源,毕竟pipelineRun只是对pipeline的一次调用,pipeline是可以复用的。当然,你也可以在triggertemplate中创建一套完整的task,pipeline,pipelineRun。但是这样的话就没有体会到tekton解耦的理念。反正能用就行,自己看场景发挥。

注意:如果省略命名空间,它将解析为EventListener的命名空间。

参数:TriggerTemplates可以声明由TriggerBinding或EventListener提供的参数。参数必须具有名称,并且可以具有可选的描述和默认值。可以使用以下变量替换语法在TriggerTemplate中引用参数,其中参数的名称为:

$(params.<name>)

参数的目的是使TriggerTemplates可重用。

TriggerBinding

TriggerBindings是用于绑定事件的。使用TriggerBindings可以捕获事件中的字段并将其存储为参数。如下例:

apiVersion: triggers.tekton.dev/v1alpha1
kind: TriggerBinding
metadata:
  name: pipeline-binding
spec:
  params:
  - name: gitrevision
    value: $(body.head_commit.id)
  - name: gitrepositoryurl
    value: $(body.repository.url)
  - name: contenttype
    value: $(header.Content-Type)

TriggerBindings接收从EventListener发送过来的参数,然后传入TriggerTemplates,在该模板上实例化Pod,以“侦听”各个事件。
参数:TriggerBindings可以提供传递给TriggerTemplate需要的参数。每个参数都有一个名称和一个值。
事件变量:TriggerBindings可以使用$()中包装的JSONPath表达式来访问HTTP JSON正文和标头中的值。标头中的密钥不区分大小写。
这些都是有效表达式:

$(body.key1)
$(.body.key)

这些是无效表达式:

.body.key1 # INVALID - Not wrapped in $()
$({body) # INVALID - Ending curly brace absent

如果 ()嵌入另一个 ()内(json中嵌入json的情况),我们将使用最里面的$()的内容作为JSONPath表达式

$($(body.b)) -> $(body.b)
$($($(body.b))) -> $(body.b)

带点的key怎么获取?访问包含.的JSON字符,我们需要转义。例如:

# body contains a filed called "tekton.dev" e.g. {"body": {"tekton.dev": "triggers"}}
$(body.tekton\.dev) -> "triggers"

举个使用例子:

`$(body)` 代表整个Body体中的json.

$(body) -> "{"key1": "value1", "key2": {"key3": "value3"}, "key4": ["value4", "value5", "value6"]}"

$(body.key1) -> "value1"   获取body中key1的值

$(body.key2) -> "{"key3": "value3"}"  获取body中key2的值

$(body.key2.key3) -> "value3" 

$(body.key4[0]) -> "value4"

$(body.key4[0:2]) -> "{"value4", "value5"}"

# $(header) 代表事件中的header

$(header) -> "{"One":["one"], "Two":["one","two","three"]}"

$(header.One) -> "one"

$(header.one) -> "one"

$(header.Two) -> "one two three"

$(header.Two[1]) -> "two"

多个绑定:在EventListener中,您可以将多个绑定指定为触发器的一部分。这使您可以创建可重用的绑定,这些绑定可以与各种触发器混合并匹配。例如,触发器具有一个绑定,该绑定提取事件信息,而另一个绑定提供部署环境信息,如下:

apiVersion: triggers.tekton.dev/v1alpha1
kind: TriggerBinding
metadata:
  name: event-binding
spec:
  params:
    - name: gitrevision
      value: $(body.head_commit.id)
    - name: gitrepositoryurl
      value: $(body.repository.url)
---
apiVersion: triggers.tekton.dev/v1alpha1
kind: TriggerBinding
metadata:
  name: prod-env
spec:
  params:
    - name: environment
      value: prod
---
apiVersion: triggers.tekton.dev/v1alpha1
kind: TriggerBinding
metadata:
  name: staging-env
spec:
  params:
    - name: environment
      value: staging
---
apiVersion: triggers.tekton.dev/v1alpha1
kind: EventListener #在listener中组合binding和template
metadata:
  name: listener
spec:
  triggers:
    - name: prod-trigger  #触发器1
      bindings: #trigger-binding #两个绑定
        - name: event-binding
        - name: prod-env
      template: #引用已有的template
        name: pipeline-template
    - name: staging-trigger # 触发器2
      bindings:# 引用定义的trigger-binding #两个绑定
        - name: event-binding
        - name: staging-env
      template: #引用已有的template
        name: pipeline-template

关于这个例子,之后我会出个实践例子。

EventListener

EventListener也是trigger的CRD资源,它允许用户以声明方式处理带有JSON负载的基于HTTP的传入事件。用户可以声明TriggerBindings以从事件中提取字段,并将其应用于TriggerTemplates进而创建Tekton资源。此外,EventListeners允许使用事件拦截器进行轻量级的事件处理(这个之后有机会再讲)。

多租户问题

与在其他地方看到的通过kubectl或tkn进行的示例用法相比,EventListener实际上是Tekton的另一种客户端形式。特别是,基于HTTP的事件会绕过您通过kubeconfig文件和kubectl config系列命令获得的常规Kubernetes身份验证路径。所以,至少每个EventListener都需要拥有自己的ServiceAccount,并且所有接收的事件都会导致Tekton资源交互,而tekton资源交互使用的权限就是ServiceAccount所赋予的。但是,如果您需要跨各种触发器和拦截器对一组Tekton资源进行不同级别的许可,而并非所有触发器或拦截器都以相同的方式操作某些Tekton资源,那么简单的单个EventListener将无法满足要求。

多个EventListeners (每个Ns都可以有一个EventListener)

您可以创建多个EventListener对象,如果在它们自己的命名空间中创建每个EventListener,则可以轻松地为每个ServiceAccount分配不同的权限来满足您的需求。通常,创建命名空间的同时还会定义一组默认的ServiceAccounts和Secrets。

缺点:从总体上讲,带有关联的Secrets和ServiceAccounts的命名空间被证明是etcd存储底层Kubernetes中最昂贵的项目(开销比较大)。在更大的集群中,etcd的存储容量可能成为一个问题。 多个EventListener意味着必须向访问“接收器”的外部实体公开多个HTTP端口,如果您的集群和外部实体之间恰好有一个HTTP防火墙,这意味着要增加管理成本,请在防火墙中为每个服务打开端口,除非您可以使用Kubernetes Ingress充当EventListeners集合的路由抽象层。

Multiple EventListeners (一个命名空间下多个EventListeners )

每个命名空间有多个EventListener,这很可能意味着管理员需要进行更多的ServiceAccount / Secret / RBAC操作。但是,通过减少命名空间的数量,您可以节省etcd的存储成本。 多个EventListener和潜在的防火墙问题仍然存在(同样,除非您使用Ingress)

ServiceAccount per EventListenerTrigger(一个EventListenerTrigger一个serviceAccount)

能够在EventListenerTrigger上设置ServiceAccount的功能还允许获得更细粒度的权限。 您仍然必须创建其他ServiceAccounts。 但是,如果不使用Ingress,则留在1个命名空间内,并通过与其关联的“接收器”将EventListener的数量减至最少,可以将对etcd存储和端口注意事项的担心降至最低。

暴露EventListener的方式

trigger作为触发器暴露服务的方式是通过http对外提供api接口,而对外提供http的具体实现,trigger这边提供了两种:使用k8s的ingress和使用Openshift Route。

Ingress

trigger controller会为每一个建立的eventlistener创建对应的deployment,该deployment的副本数是1,你可以为该deployment创建service,而service的selector选择的标签是eventlistener: build-listener。build-listener是所创建的eventlistener的资源名称。如果你想将service暴露出去,可以使用Ingress的方式:

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: ingress-resource
  namespace: getting-started
  annotations:
    kubernetes.io/ingress.class: nginx
    nginx.ingress.kubernetes.io/ssl-redirect: "false"
spec:
  rules:
    - http:
        paths:
          - path: /
            backend:
              serviceName: getting-started-listener-b8rqz # REPLACE WITH YOUR SERVICE NAME FROM STEP 2
              servicePort: 8080

如果你的触发器只在内网中使用,那么service就够了。

Using Openshift Route

trigger提供的第二种暴露事件监听器的方式是openshift,Openshift也是为了解决从集群外部(就是从除了集群节点以外的其它地方)访问服务的需求。我目前还没用,暂时不介绍用法,有兴趣的同学自行谷歌吧。

总结

以上就是trigger中的主要内容,还存在一些例如拦截器和对接github/gitlab的内容,我将放在之后的实践文章中。本篇主要介绍了tekton的trigger组件中的核心概念:TriggerTemplate, TriggerBinding, EventListener。记住下面这张图,你就能掌握trigger运行原理:
在这里插入图片描述
看着这张图,就想到:事件发送给eventListener 的pod,pod讲事件中的参数解析给到triggerbinding,triggerbind找到关联的triggerTemplate并把参数传入,triggerTemplate实例化tekton中的资源(即创建),以上过程实现从一个http请求到运行一个完整的工作流。

如有问题,烦请留言。

最后的最后,要是对我写的内容有兴趣,可以关注下微信公众号“云原生手记”。

猜你喜欢

转载自blog.csdn.net/u013276277/article/details/107347253