暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

Tekton系列之实践篇-使用Tekton Trigger让Tekton使用更简单

运维开发故事 2022-04-14
393

《Tekton实践篇-如何用Jenkins来管理Tekton》我们介绍了如何使用Jenkins来管理Tekton,这种方式是运维主动式管理,也就是需要运维去触发发布,那有没有可能让自动触发Tekton PipelineRun的运行呢?

答案是有的,也就是这篇文章分享的Tekton Trigger。

什么是Tekton Trigger?

Tekton Trigger是Tekton的一个组件,它可以从各种来源的事件中检测并提取需要信息,然后根据这些信息来运行TaskRun和PipelineRun,还可以将提取出来的信息传递给它们以满足不同的运行要求。

其核心组件如下:

  • EventListener:时间监听器,是外部事件的入口 ,通常需要通过HTTP方式暴露,以便于外部事件推送,比如配置Gitlab的Webhook。
  • Trigger:指定当EventListener检测到事件发生时会发生什么,它会定义TriggerBinding、TriggerTemplate以及可选的Interceptor。
  • TriggerTemplate:用于模板化资源,根据传入的参数实例化Tekton对象资源,比如TaskRun、PipelineRun等。
  • TriggerBinding:用于捕获事件中的字段并将其存储为参数,然后会将参数传递给TriggerTemplate。
  • ClusterTriggerBinding:和TriggerBinding相似,用于提取事件字段,不过它是集群级别的对象。
  • Interceptor:拦截器,在TriggerBinding之前运行,用于负载过滤、验证、转换等处理,只有通过拦截器的数据才会传递给TriggerBinding。

工作原理图如下:

image.png

下面会详细介绍Trigger 的CRD对象。

Trigger CRD对象

TriggerTemplate

TriggerTemplate可以模块化Tekton资源的资源,可以使传入的参数在资源模板中的任何位置被使用,它就好比我们定义了一个对象,这个对象可以接收外部的参数,在对象内部把接收到的参数再传递给Tekton资源对象进行使用。

TriggerTemplate的定义很简单,如下:

apiVersion: triggers.tekton.dev/v1beta1kind: TriggerTemplatemetadata:  name: pipeline-templatespec:  params:  # 参数的定义,从外部接收的参数  - name: gitrevision    description: The git revision    default: main  - 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      params:      - name: message        value: $(tt.params.message)      - name: contenttype        value: $(tt.params.contenttype)      resources:      - name: git-source        resourceSpec:          type: git          params:          - name: revision            value: $(tt.params.gitrevision)          - name: url            value: $(tt.params.gitrepositoryurl)

从上面可以看出,resourcetemplates
字段中就是定义的资源模板,上面定义的PipelineRun的资源,里面的语法和定义一个PipelineRun CRD一致,就像Deployment的Template中定义的Pod资源和单独定义Pod资源的语义一样。

params
字段定义我们需要从外部获得的参数,这个参数后续会传递给resourcetemplates
以完成其资源实例化。

TriggerBinding

TriggerBinding用于将事件进行绑定,通过捕获事件中的字段并将其存储为参数。

其定义方式如下:

apiVersion: triggers.tekton.dev/v1beta1kind: TriggerBindingmetadata:  name: pipeline-bindingspec:  params:  - name: gitrevision    value: $(body.head_commit.id)  - name: gitrepositoryurl    value: $(body.repository.url)  - name: contenttype    value: $(header.Content-Type)

TriggerBinding接收从EventListener传递过来的参数,然后传给TriggerTemplate,在TriggerTemplate上实例化资源对象。

TriggerBinding提供TriggerTemplate需要的参数,参数以key-value的方式存储并传递。其中的value是通过$()
中包裹的JSONPath
表达式来提取(https://tekton.dev/docs/triggers/triggerbindings/)。

Trigger

用于指定当事件发生时需要做什么,它会定义TriggerBinding、TriggerTemplate以及可选的Interceptor。

如下:

apiVersion: triggers.tekton.dev/v1beta1kind: Triggermetadata:  name: triggerspec:  interceptors:    - ref:        name: "cel"      params:        - name: "filter"          value: "header.match('X-GitHub-Event', 'pull_request')"        - name: "overlays"          value:            - key: extensions.truncated_sha              expression: "body.pull_request.head.sha.truncate(7)"  bindings:  - ref: pipeline-binding  template:    ref: pipeline-template

上面定义了interceptors
bindings
template
,一当EventListener收到事件,就会触发这个Trigger,先经过interceptors
进行拦截筛选,然后再传给bindings
template

ClusterTriggerBinding

ClusterTriggerBinding和TriggerBinding功能一样,从名字就可以看到,ClusterTriggerBinding是集群级别的,可以作用于任何namespace。

其定义和TriggerBinding一样,如下:

apiVersion: triggers.tekton.dev/v1beta1kind: ClusterTriggerBindingmetadata:  name: pipeline-clusterbindingspec:  params:    - name: gitrevision      value: $(body.head_commit.id)    - name: gitrepositoryurl      value: $(body.repository.url)    - name: contenttype      value: $(header.Content-Type)

Interceptor

Interceptor是在TriggerBinding运行之前的事件处理器,可以做一些预处理,比如账户密码验证,再比如一些事件方式验证,如gitlab的push event。只有通过了Interceptor,才会把有效数据传递给TriggerBinding。

Tekton Trigger目前支持两种Interceptor的实现方式:

  • 独立Interceptor
  • 传统Interceptor(将被废弃)

独立Interceptor是ClusterInterceptor自定义资源的实例,可以在下面介绍的EventListener中引用这些Interceptor以及所需的参数。传统的Interceptor就是在EventListener中完全定义,不过这种方式将被废弃。

目前已经内置了以下Interceptor:

  • Webhook Interceptor
  • Github Interceptor
  • Gitlab Interceptor
  • Bitbucket Interceptor
  • CEL Interceptor

这里以Gitlab Interceptor为例。Gitlab Interceptor包括验证和过滤的逻辑,它可以验证Webhook的来源,也可以验证指定标准过滤传入的事件。如下:

interceptors:- ref:    name: "gitlab"  params:  - name: "secretRef"    value:      secretName: foo      secretKey: bar  - name: "eventTypes"    value: ["Push Hook"]

也可以直接在EventListener中定义,如下:

apiVersion: triggers.tekton.dev/v1alpha1kind: EventListenermetadata:  name: gitlab-listener-interceptorspec:  serviceAccountName: tekton-triggers-example-sa  triggers:    - name: foo-trig      interceptors:        - gitlab:            secretRef:              secretName: foo              secretKey: bar            eventTypes:              - Push Hook      bindings:        - ref: pipeline-binding      template:        ref: pipeline-template

EventListener

EventListener是一个Kubernetes对象,用于监听Kubernetes上指定端口的事件,然后会接收传入的事件并指定一个或多个触发器。

EventListener实际上是Tekton的另一种客户端形式,只是它是基于HTTP事件的,通过HTTP的方式可以绕过常规的认证路径,比如kubeconfig等,我们知道,任何需要通过kube-apiserver的事件都需要认证、鉴权等一系列操作,那HTTP方式是如何实现的呢?我们在创建一个简单的nginx deployment的时候,可以看到yaml文件里会自动生成一个default的serviceaccount,这个default就是用于认证、鉴权的。所以要使用EventListener,就需要让它拥有自己的serviceaccount,并且这个serviceaccount需要Tekton资源操作的权限才能让Event正常的和Tekton进行交互。

EventListener的定义示例如下:

apiVersion: triggers.tekton.dev/v1alpha1kind: EventListenermetadata:  name: gitlab-listenerspec:  serviceAccountName: tekton-triggers-example-sa  triggers:    - name: gitlab-push-events-trigger      interceptors:        - name: "verify-gitlab-payload"          ref:            name: "gitlab"            kind: ClusterInterceptor          params:            - name: secretRef              value:                secretName: "gitlab-secret"                secretKey: "secretToken"            - name: eventTypes              value:                - "Push Hook"      bindings:        - name: gitrevision          value: $(body.checkout_sha)        - name: gitrepositoryurl          value: $(body.repository.git_http_url)      template:        spec:          params:            - name: gitrevision            - name: gitrepositoryurl          resourcetemplates:            - apiVersion: tekton.dev/v1alpha1              kind: TaskRun              metadata:                generateName: gitlab-run-              spec:                taskSpec:                  inputs:                    resources:                      - name: source                        type: git                  steps:                    - image: ubuntu                      script: |                        #! /bin/bash                        ls -al $(inputs.resources.source.path)                inputs:                  resources:                    - name: source                      resourceSpec:                        type: git                        params:                          - name: revision                            value: $(tt.params.gitrevision)                          - name: url                            value: $(tt.params.gitrepositoryurl)

Trigger安装

上面简单介绍了一下Trigger的常用功能,更多的可以到官方文档(https://tekton.dev/docs/triggers/)进行学习。

下面我们将正式的把之前的Pipeline流程接入Trigger,实现开发人员推送代码,通过Webhook自动触发对应的PipelineRun。

首先我们需要安装Trigger(https://tekton.dev/docs/triggers/install/)。

安装的时候选择对应的版本安装,如果Kubernetes集群版本太低,会导致安装失败。

kubectl apply --filename https://storage.googleapis.com/tekton-releases/triggers/latest/release.yamlkubectl apply --filename https://storage.googleapis.com/tekton-releases/triggers/latest/interceptors.yaml

不过由于网络原因,直接按着官方文档进行安装是下载不了,我将自己用到的上传到了仓库(https://gitee.com/coolops/tekton-install/tree/master/trigger),有需要的自己去下载。

安装完成后,可以看到如下Pod。

# kubectl get po -n tekton-pipelines NAME                                                 READY   STATUS    RESTARTS   AGEtekton-dashboard-565c78b68d-6fjdz                    1/1     Running   12         32dtekton-pipelines-controller-75c456df85-qxvq2         1/1     Running   5          32dtekton-pipelines-webhook-5bc8d6b7c4-w6pdn            1/1     Running   5          32dtekton-triggers-controller-686c6c8f79-fp7wd          1/1     Running   0          9m37stekton-triggers-core-interceptors-5d77595f79-8q9hb   1/1     Running   0          10stekton-triggers-webhook-76c55d6799-h997b             1/1     Running   0          9m36s

使用Tekton Trigger

上面已经安装好了Tekton Trigger,下面我们将正式接入Tekton Trigger实现自动持续部署。

定义Trigger Template

回看《Tekton系列之实践篇-由Jenkins改成Tekton》中的PipelineRun的YAML文件,可以看到有参数revision、git_url、imageUrl、imageTag、namespace等,所以在定义Trigger Template的时候需要这些参数传递进去。

apiVersion: triggers.tekton.dev/v1beta1 kind: TriggerTemplatemetadata:  name: trigger-rd-pipeline-templatespec:  params:    - name: gitrevision      description: The git revision      default: master    - name: gitrepositoryurl      description: The git repository url    - name: namespace      description: The namespace to create the resources      default: tekton-devops-pipeline    - name: projectname      description: The project name    - name: imagetag      description: The image tag      default: latest  resourcetemplates:    - apiVersion: tekton.dev/v1alpha1      kind: PipelineRun      metadata:        name: rd-pipeline-run-$(uid)        namespace: $(tt.params.namespace)      spec:        serviceAccountName: tekton-build-sa        params:         - name: revision          value: $(tt.params.gitrevision)        - name: git_url          value: $(tt.params.gitrepositoryurl)        - name: imageUrl          value: registry.cn-hangzhou.aliyuncs.com/coolops/$(tt.params.projectname)        - name: imageTag          value: latest        - name: pathToDockerfile          value: Dockerfile        - name: chart_username          value: xxx        - name: chart_password          value: xxx        - name: app_name          value: hello-world        - name: namespace          value: default        - name: sonar_username          value: xxxx        - name: sonar_password          value: xxxx        - name: sonar_url          value: http://sonarqube.coolops.cn        pipelineRef:          name: rd-pipeline        workspaces:        - name: rd-repo-pvc          volumeClaimTemplate:            spec:              accessModes:              - ReadWriteOnce              storageClassName: local               resources:                requests:                  storage: 1Gi        - name: docker-config          secret:            secretName: docker-config        - name: kubernetes-config          secret:            secretName: kubernetes-config

定义Trigger Binding

Trigger Template的入参都可以通过PushEvent中获取,PushEvent里的数据需要通过Trigger Binding来绑定。

apiVersion: triggers.tekton.dev/v1beta1kind: TriggerBindingmetadata:  name: trigger-rd-pipeline-bingding  namespace: tekton-devops-pipelinespec:  params:    - name: gitrevision      value: $(body.ref)    - name: namespace      value: tekton-devops-pipeline    - name: gitrepositoryurl      value: $(body.project.git_http_url)    - name: projectname      value: $(body.project.name)

定义EventListener

上面创建好Trigger Template和Trigger Binding,接下来就是创建EventListener,把Template和Binding关联起来。

apiVersion: triggers.tekton.dev/v1beta1kind: EventListenermetadata:  name: trigger-rd-pipeline-eventlistenerspec:  serviceAccountName: tekton-triggers-gitlab-sa  triggers:    - bindings:        - ref: trigger-rd-pipeline-bingding      template:        ref: trigger-rd-pipeline-template

这里的tekton-triggers-gitlab-sa
是需要我们创建的,如下:

apiVersion: v1kind: ServiceAccountmetadata:  name: tekton-triggers-gitlab-sasecrets:- name: gitlab-secret- name: gitlab-auth---kind: ClusterRoleapiVersion: rbac.authorization.k8s.io/v1metadata:  name: tekton-triggers-gitlab-minimalrules:  # Permissions for every EventListener deployment to function  - apiGroups: ["triggers.tekton.dev"]    resources: ["eventlisteners""triggerbindings""triggertemplates","clustertriggerbindings""clusterinterceptors","triggers"]    verbs: ["get","list","watch"]  - apiGroups: [""]    # secrets are only needed for Github/Gitlab interceptors, serviceaccounts only for per trigger authorization    resources: ["configmaps""secrets""serviceaccounts"]    verbs: ["get""list""watch"]  # Permissions to create resources in associated TriggerTemplates  - apiGroups: ["tekton.dev"]    resources: ["pipelineruns""pipelineresources""taskruns"]    verbs: ["create"]---apiVersion: rbac.authorization.k8s.io/v1kind: ClusterRoleBindingmetadata:  name: tekton-triggers-gitlab-bindingsubjects:  - kind: ServiceAccount    name: tekton-triggers-gitlab-sa    namespace: tekton-devops-pipelineroleRef:  apiGroup: rbac.authorization.k8s.io  kind: ClusterRole  name: tekton-triggers-gitlab-minimal

现在需要新增一个Gitlab的Webhook的Secret Token,如下:

apiVersion: v1kind: Secretmetadata:  name: gitlab-secrettype: OpaquestringData:  secretToken: "coolops"

当创建完EventListener过后,会在当前namespace下生成一个service和deployment,如下:

# kubectl get all | grep eventpod/el-trigger-rd-pipeline-eventlistener-674768c8d5-p8z66             2/2     Running     2          128mservice/el-trigger-rd-pipeline-eventlistener   ClusterIP   10.98.84.33      <none>        8080/TCP   128mdeployment.apps/el-trigger-rd-pipeline-eventlistener   1/1     1            1           128mreplicaset.apps/el-trigger-rd-pipeline-eventlistener-674768c8d5   1         1         1       128m

我们需要把这个service暴露出去,创建Ingress如下:

apiVersion: extensions/v1beta1kind: Ingressmetadata:  name: el-trigger-test-eventlistenerspec:  rules:  - host: hello-word.webhook.coolops.cn    http:      paths:      - backend:          serviceName: el-trigger-rd-pipeline-eventlistener           servicePort: 8080

创建Webhook

上面已经把EventListener暴露出来了,下面就在代码仓库中创建Webhook。

由于我的代码放在私有Gitlab中的,配置如下(由于内网,就直接使用了NodePort暴露EventListener):

然后可以测试一下,并查看更多的信息。

需要的信息都是从Request中获取,如下:

{  "object_kind""push",  "event_name""push",  "before""77e1901516fc2ee1a47b03bb4bfc63ca02e6b23d",  "after""ac84d875c6094b5feebd477809a2021fd745c9df",  "ref""refs/heads/master",  "checkout_sha""ac84d875c6094b5feebd477809a2021fd745c9df",  "message": null,  "user_id": 1,  "user_name""Administrator",  "user_username""root",  "user_email""",  "user_avatar""https://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80&d=identicon",  "project_id": 2,  "project": {    "id": 2,    "name""Devops Hello World",    "description""",    "web_url""http://192.168.205.128/root/devops-hello-world",    "avatar_url": null,    "git_ssh_url""git@192.168.205.128:root/devops-hello-world.git",    "git_http_url""http://192.168.205.128/root/devops-hello-world.git",    "namespace""Administrator",    "visibility_level": 0,    "path_with_namespace""root/devops-hello-world",    "default_branch""master",    "ci_config_path": null,    "homepage""http://192.168.205.128/root/devops-hello-world",    "url""git@192.168.205.128:root/devops-hello-world.git",    "ssh_url""git@192.168.205.128:root/devops-hello-world.git",    "http_url""http://192.168.205.128/root/devops-hello-world.git"  },  "commits": [    {      "id""ac84d875c6094b5feebd477809a2021fd745c9df",      "message""ceshi ",      "title""ceshi ",      "timestamp""2022-03-30T08:54:11+00:00",      "url""http://192.168.205.128/root/devops-hello-world/-/commit/ac84d875c6094b5feebd477809a2021fd745c9df",      "author": {        "name""coolops",        "email""baidjay@163.com"      },      "added": [      ],      "modified": [        "Jenkinsfile"      ],      "removed": [      ]    },    {      "id""cc36ed8cf920d9a3470fda6a28576ba7d29f9c04",      "message""ceshi ",      "title""ceshi ",      "timestamp""2022-03-30T08:52:13+00:00",      "url""http://192.168.205.128/root/devops-hello-world/-/commit/cc36ed8cf920d9a3470fda6a28576ba7d29f9c04",      "author": {        "name""coolops",        "email""baidjay@163.com"      },      "added": [      ],      "modified": [        "Jenkinsfile"      ],      "removed": [      ]    },    {      "id""77e1901516fc2ee1a47b03bb4bfc63ca02e6b23d",      "message""多分支发布",      "title""多分支发布",      "timestamp""2022-03-30T08:45:11+00:00",      "url""http://192.168.205.128/root/devops-hello-world/-/commit/77e1901516fc2ee1a47b03bb4bfc63ca02e6b23d",      "author": {        "name""coolops",        "email""baidjay@163.com"      },      "added": [      ],      "modified": [        "Jenkinsfile"      ],      "removed": [      ]    }  ],  "total_commits_count": 3,  "push_options": {  },  "repository": {    "name""Devops Hello World",    "url""git@192.168.205.128:root/devops-hello-world.git",    "description""",
    "homepage""http://192.168.205.128/root/devops-hello-world",
    "git_http_url""http://192.168.205.128/root/devops-hello-world.git",
    "git_ssh_url""git@192.168.205.128:root/devops-hello-world.git",
    "visibility_level": 0
  }
}

需要什么就从Request中取什么。这样就可以通过WebHook触发一条Tekton流水线。

可以看到流水线正常运行了。

到目前为止,就可以实现代码提交到Gitlab,然后通过Webhook自动触发Tekton Pipeline了。



最后,求关注。如果你还想看更多优质原创文章,欢迎关注我们的公众号「运维开发故事」。

如果我的文章对你有所帮助,还请帮忙点赞、在看、转发一下,你的支持会激励我输出更高质量的文章,非常感谢!

你还可以把我的公众号设为「星标」,这样当公众号文章更新时,你会在第一时间收到推送消息,避免错过我的文章更新。

文末抽奖

为感谢各位粉丝的关注,今天给大家发个小红包,四个50元的红包,再送一张价值5800元的WOT峰会门票,扫描小程序码抽奖,下午五点截止

红包抽奖

门票抽奖





我是 乔克,《运维开发故事》公众号团队中的一员,一线运维农民工,云原生实践者,这里不仅有硬核的技术干货,还有我们对技术的思考和感悟,欢迎关注我们的公众号,期待和你一起成长!



文章转载自运维开发故事,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论