生产环境 DevOps 实战 | 第 13 天:Tekton 事件驱动 CI——给流水线接入 GitHub/GitLab 事件

第 13/60 天

引言

在上一篇文章中,我们学习了 Tekton Triggers 的核心组件——TriggerBinding、TriggerTemplate、EventListener 和 Interceptor,并通过一个简单的 Webhook 示例触发了流水线。但生产环境的 CI 要求远不止于此:我们需要真正接入 GitHub 或 GitLab 的事件,比如 pushpull_requesttag 创建等,然后根据事件内容动态决定构建参数、分支信息、镜像标签等。

本篇文章将带你从零到一,为 Tekton 流水线接入真实的 GitHub/GitLab Webhook 事件,实现代码提交即触发构建 + 镜像推送 + 通知的完整事件驱动 CI 流程。核心目标包括:

  • 部署 EventListener 并暴露为 Ingress
  • 配置 GitHub/GitLab Webhook 到 EventListener
  • 使用 Interceptor 解析事件载荷并过滤分支
  • 根据事件数据动态生成流水线参数
  • 实现 PR 触发校验流水线、Push 触发构建流水线的多事件路由

核心概念

事件驱动 CI 的通信模型

GitHub/GitLab          Tekton EventListener          Trigger        PipelineRun
    │                        │                           │               │
    │  push/Pull Request     │                           │               │
    │───────────────────────►│                           │               │
    │                        │  Interceptor 检查事件      │               │
    │                        │  (过滤分支/事件类型)       │               │
    │                        │ 绑定 TriggerBinding        │               │
    │                        │ 实例化 TriggerTemplate     │               │
    │                        │──────────────────────────►│               │
    │                        │                           │ 创建           │
    │                        │                           │──────────────►│
    │                        │                           │               │ 执行
    │                        │                           │               │────►

关键组件回顾

组件 在本场景中的作用
EventListener 监听 HTTP Webhook 请求的入口,可配置多个 Trigger
Interceptor 在事件到达 Trigger 前执行预处理,支持过滤、校验、变量提取
TriggerBinding 从 Webhook 载荷中提取字段(如分支名、提交 SHA、仓库 URL)
TriggerTemplate 使用提取的变量生成 PipelineRun 或 TaskRun 的 YAML

内置 Interceptor 类型

Tekton 提供三种内置 Interceptor:

  1. GitHub Interceptor — 自动校验 GitHub Webhook 签名(HMAC),解析事件载荷
  2. GitLab Interceptor — 自动校验 GitLab Webhook 的 Secret Token,解析事件载荷
  3. CEL Interceptor — 使用 Common Expression Language 编写过滤条件,支持分支名匹配、事件类型过滤等

生产环境的事件路由策略

分支模式 事件 触发动作
feature/* push 启动校验流水线(lint + test)
main push 启动构建 + 推送镜像 + 更新 staging 环境
v* tag 创建 启动构建 + 推送镜像 + 打版本标签
任意 pull_request 启动 PR 校验流水线(不推送镜像)

实战步骤

Step 1:部署 EventListener 并暴露为 Ingress

首先创建一个 EventListener,监听 /tekton/events 路径:

# eventlistener-github.yaml
apiVersion: triggers.tekton.dev/v1beta1
kind: EventListener
metadata:
  name: github-listener
  namespace: tekton-pipelines
spec:
  serviceAccountName: tekton-triggers-admin
  triggers:
    - name: push-to-main
      interceptors:
        - ref:
            name: github
          params:
            - name: secretRef
              value:
                secretName: github-webhook-secret
                secretKey: secretToken
            - name: eventTypes
              value: ["push"]
        - ref:
            name: cel
          params:
            - name: filter
              value: "body.ref == 'refs/heads/main'"
      bindings:
        - ref: github-push-binding
      template:
        ref: build-and-deploy-template
    - name: pr-validation
      interceptors:
        - ref:
            name: github
          params:
            - name: eventTypes
              value: ["pull_request"]
        - ref:
            name: cel
          params:
            - name: filter
              value: "body.action in ['opened', 'synchronize']"
      bindings:
        - ref: github-pr-binding
      template:
        ref: pr-validation-template
  resources:
    kubernetesResource:
      spec:
        template:
          spec:
            containers:
              - resources:
                  requests:
                    memory: "64Mi"
                    cpu: "50m"
                  limits:
                    memory: "128Mi"
                    cpu: "200m"
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: github-listener-ingress
  namespace: tekton-pipelines
  annotations:
    nginx.ingress.kubernetes.io/ssl-redirect: "true"
    cert-manager.io/cluster-issuer: "letsencrypt-prod"
spec:
  ingressClassName: nginx
  tls:
    - hosts:
        - tekton-webhook.stellardata.top
      secretName: tekton-webhook-tls
  rules:
    - host: tekton-webhook.stellardata.top
      http:
        paths:
          - path: /tekton/events
            pathType: Prefix
            backend:
              service:
                name: el-github-listener
                port:
                  number: 8080

Webhook Secret 需要通过 Kubernetes Secret 提供:

# 创建 Webhook Secret(与 GitHub 中配置的相同)
kubectl create secret generic github-webhook-secret 
  --namespace tekton-pipelines 
  --from-literal=secretToken="your-github-webhook-secret-here"

Step 2:创建 TriggerBinding 提取事件字段

TriggerBinding 从 Webhook 载荷中提取关键字段,传递给 TriggerTemplate:

# triggerbinding-github-push.yaml
apiVersion: triggers.tekton.dev/v1beta1
kind: TriggerBinding
metadata:
  name: github-push-binding
  namespace: tekton-pipelines
spec:
  params:
    - name: git_repo_url
      value: $(body.repository.clone_url)
    - name: git_revision
      value: $(body.after)
    - name: git_branch
      value: $(body.ref)
    - name: git_commit_message
      value: $(body.head_commit.message)
    - name: git_committer
      value: $(body.head_commit.committer.name)
    - name: git_commit_timestamp
      value: $(body.head_commit.timestamp)
    - name: repository_full_name
      value: $(body.repository.full_name)
---
# triggerbinding-github-pr.yaml
apiVersion: triggers.tekton.dev/v1beta1
kind: TriggerBinding
metadata:
  name: github-pr-binding
  namespace: tekton-pipelines
spec:
  params:
    - name: git_repo_url
      value: $(body.repository.clone_url)
    - name: git_revision
      value: $(body.pull_request.head.sha)
    - name: git_branch
      value: $(body.pull_request.head.ref)
    - name: pr_number
      value: $(body.number)
    - name: pr_title
      value: $(body.pull_request.title)
    - name: git_commit_message
      value: $(body.pull_request.title)
    - name: repository_full_name
      value: $(body.repository.full_name)

GitLab 版本的 TriggerBinding 参数路径略有不同,GitLab 的 Webhook 载荷中仓库 URL 在 $(body.project.git_http_url),分支在 $(body.ref),提交 SHA 在 $(body.checkout_sha)。使用 GitLab Interceptor 时自动解析。

Step 3:创建 TriggerTemplate 生成 PipelineRun

以下是构建部署流水线的模板,根据事件参数动态生成流水线运行:

# triggertemplate-build-deploy.yaml
apiVersion: triggers.tekton.dev/v1beta1
kind: TriggerTemplate
metadata:
  name: build-and-deploy-template
  namespace: tekton-pipelines
spec:
  params:
    - name: git_repo_url
    - name: git_revision
    - name: git_branch
    - name: git_commit_message
    - name: repository_full_name
  resourcetemplates:
    - apiVersion: tekton.dev/v1
      kind: PipelineRun
      metadata:
        name: build-deploy-$(uid)
        labels:
          triggertemplate: build-and-deploy
          repo: $(tt:params.repository_full_name)
          branch: $(tt:params.git_branch)
      spec:
        pipelineRef:
          name: ci-pipeline
        params:
          - name: repo-url
            value: $(tt:params.git_repo_url)
          - name: revision
            value: $(tt:params.git_revision)
          - name: branch
            value: $(tt:params.git_branch)
          - name: commit-message
            value: $(tt:params.git_commit_message)
          - name: image-tag
            value: $(tt:params.git_revision)[0:7]
        workspaces:
          - name: shared-workspace
            persistentVolumeClaim:
              claimName: tekton-workspace-pvc
          - name: dockerconfig
            secret:
              secretName: harbor-robot-secret

PR 校验模板只运行测试和 lint,不构建镜像:

# triggertemplate-pr-validation.yaml
apiVersion: triggers.tekton.dev/v1beta1
kind: TriggerTemplate
metadata:
  name: pr-validation-template
  namespace: tekton-pipelines
spec:
  params:
    - name: git_repo_url
    - name: git_revision
    - name: git_branch
    - name: pr_number
    - name: pr_title
    - name: repository_full_name
  resourcetemplates:
    - apiVersion: tekton.dev/v1
      kind: PipelineRun
      metadata:
        name: pr-validation-$(uid)
        labels:
          triggertemplate: pr-validation
          pr-number: $(tt:params.pr_number)
          repo: $(tt:params.repository_full_name)
      spec:
        pipelineRef:
          name: pr-validation-pipeline
        params:
          - name: repo-url
            value: $(tt:params.git_repo_url)
          - name: revision
            value: $(tt:params.git_revision)
          - name: pr-number
            value: $(tt:params.pr_number)
        workspaces:
          - name: shared-workspace
            persistentVolumeClaim:
              claimName: tekton-workspace-pvc

Step 4:配置 ServiceAccount 与 RBAC

EventListener 需要足够的权限来创建 PipelineRun 和其他资源:

# rbac-tekton-triggers.yaml
apiVersion: v1
kind: ServiceAccount
metadata:
  name: tekton-triggers-admin
  namespace: tekton-pipelines
secrets:
  - name: harbor-robot-secret
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: tekton-triggers-admin-clusterrole
rules:
  - resources: ["pipelines", "pipelineruns", "taskruns", "tasks"]
    apiGroups: ["tekton.dev"]
    verbs: ["create", "get", "list", "watch", "update", "patch", "delete"]
  - resources: ["pipelineresources"]
    apiGroups: ["tekton.dev"]
    verbs: ["create", "get", "list", "watch"]
  - resources: ["eventlisteners", "triggerbindings", "triggertemplates", "triggers"]
    apiGroups: ["triggers.tekton.dev"]
    verbs: ["get", "list", "watch"]
  - resources: ["configmaps", "secrets"]
    apiGroups: [""]
    verbs: ["get", "list", "watch"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: tekton-triggers-admin-binding
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: tekton-triggers-admin-clusterrole
subjects:
  - kind: ServiceAccount
    name: tekton-triggers-admin
    namespace: tekton-pipelines

Step 5:在 GitHub/GitLab 配置 Webhook

GitHub 配置步骤:

1. 打开仓库 → Settings → Webhooks → Add webhook
2. Payload URL: https://tekton-webhook.stellardata.top/tekton/events
3. Content type: application/json
4. Secret: 输入与 github-webhook-secret 中一致的密钥
5. SSL verification: Enable SSL verification
6. Which events: 勾选 "Just the push event" 或 "Let me select individual events"
   - 选择: Pushes, Pull requests, Tag creation
7. Active: ✅ 勾选

GitLab 配置步骤:

# 如果使用 GitLab Interceptor,EventListener 配置如下:
# 注意 GitLab 使用 Secret Token 而非 HMAC 签名验证
apiVersion: triggers.tekton.dev/v1beta1
kind: EventListener
metadata:
  name: gitlab-listener
  namespace: tekton-pipelines
spec:
  triggers:
    - name: gitlab-push
      interceptors:
        - ref:
            name: gitlab
          params:
            - name: secretRef
              value:
                secretName: gitlab-webhook-secret
                secretKey: secretToken
            - name: eventTypes
              value: ["Push Hook"]
      bindings:
        - ref: gitlab-push-binding
      template:
        ref: build-and-deploy-template

Step 6:验证 Webhook 接入

部署完成后,通过以下方式验证:

# 1. 检查 EventListener Pod 是否正常运行
kubectl get pods -n tekton-pipelines -l eventlistener=github-listener

# 2. 查看 EventListener 日志
kubectl logs -n tekton-pipelines -l eventlistener=github-listener --tail=50

# 3. 手动模拟 Webhook 请求(测试用)
curl -k -X POST 
  https://tekton-webhook.stellardata.top/tekton/events 
  -H "Content-Type: application/json" 
  -H "X-GitHub-Event: push" 
  -H "X-Hub-Signature-256: sha256=..." 
  -d '{
    "ref": "refs/heads/main",
    "after": "abc123def456",
    "repository": {
      "clone_url": "https://github.com/example/my-app.git",
      "full_name": "example/my-app"
    },
    "head_commit": {
      "message": "feat: add new feature",
      "committer": {"name": "developer"},
      "timestamp": "2026-08-24T00:00:00Z"
    }
  }'

# 4. 查看生成的 PipelineRun
kubectl get pipelineruns -n tekton-pipelines --sort-by=.metadata.creationTimestamp

# 5. 在 GitHub 仓库 Webhook 页面查看最近投递记录
#    Settings → Webhooks → 点击你的 webhook → Recent Deliveries

Step 7:高级 CEL Interceptor 过滤示例

CEL Interceptor 支持复杂的表达式过滤,以下是几个生产场景示例:

# CEL 过滤示例:仅处理 main 分支、排除机器人提交、匹配特定路径
apiVersion: triggers.tekton.dev/v1beta1
kind: Trigger
metadata:
  name: cel-filter-trigger
  namespace: tekton-pipelines
spec:
  interceptors:
    - ref:
        name: cel
      params:
        - name: filter
          value: >
            body.ref == 'refs/heads/main' &&
            body.head_commit.committer.name != 'dependabot[bot]' &&
            !has(body.head_commit.modified) || 
            body.head_commit.modified.exists(f, f.startsWith('src/'))
        - name: overlays
          - name: short_sha
            expression: "body.after.substring(0, 7)"
          - name: image_tag
            expression: "'v' + string(timestamp(body.head_commit.timestamp).getDate().toString())"
  template:
    ref: build-and-deploy-template

CEL 表达式说明:

表达式 作用
body.ref == 'refs/heads/main' 只匹配 main 分支的推送
body.head_commit.committer.name != 'dependabot[bot]' 排除机器人提交
body.head_commit.modified.exists(f, f.startsWith('src/')) 仅当修改了 src/ 目录下的文件
body.after.substring(0, 7) 提取提交 SHA 前 7 位作为短标识
overlays 在 CEL 中计算新变量,附加到 TriggerBinding 参数中

常见问题

Q1: Webhook 配置后 EventListener 没有收到请求,怎么办?

排查步骤:
1. 确认 Ingress 外部域名 DNS 解析正确,nslookup tekton-webhook.stellardata.top
2. 检查 SSL/TLS 证书是否有效,openssl s_client -connect tekton-webhook.stellardata.top:443
3. 查看 EventListener Pod 日志是否有错误信息
4. 在 GitHub Webhook 页面查看 Recent Deliveries 是否有投递失败记录
5. 检查 Ingress 是否配置了正确的 backend service 名称和端口(默认 8080)

Q2: Webhook 签名验证失败,403 错误?

GitHub Interceptor 要求 Webhook Secret 必须一致:
– 确认 kubectl get secret github-webhook-secret -n tekton-pipelines -o jsonpath='{.data.secretToken}' | base64 -d 的值与 GitHub 仓库设置的 Secret 完全一致
– 注意 Secret 中不要有多余的换行符或空格
– 使用 echo -n "your-secret" 而不是 echo "your-secret" 创建 Secret,避免多余的换行

Q3: CEL Interceptor 过滤后流水线没有触发?

CEL 表达式返回 false 时不会触发。可以使用 celoverlays 输出调试信息:

- name: debug_output
  expression: "'debug: ref=' + body.ref + ' action=' + body.action"

在日志中查看 debug_output 的值,确认事件数据是否符合预期。

Q4: 如何区分 Push 事件和 Tag 事件?

Push 事件中 ref 字段格式不同:
– 分支推送:refs/heads/main
– 标签推送:refs/heads/v1.0.0

CEL 过滤:

# 只匹配标签事件
- name: filter
  value: "body.ref.startsWith('refs/tags/')"

Q5: 多仓库复用同一个 EventListener 如何区分?

可以在 EventListener 中配置多个 Trigger,每个 Trigger 通过 CEL Interceptor 匹配不同的仓库 URL:

- name: app-a-trigger
  interceptors:
    - ref:
        name: cel
      params:
        - name: filter
          value: "body.repository.full_name == 'team-a/app-a'"
- name: app-b-trigger
  interceptors:
    - ref:
        name: cel
      params:
        - name: filter
          value: "body.repository.full_name == 'team-b/app-b'"

总结

本文详细介绍了如何为 Tekton 流水线接入 GitHub/GitLab 事件,实现真正的事件驱动 CI。以下是核心要点:

  1. 三层拦截体系:GitHub/GitLab Interceptor 负责签名验证和事件解析,CEL Interceptor 负责分支/事件类型过滤,TriggerBinding 负责变量提取,形成完整的事件处理链
  2. 多事件路由:通过一个 EventListener 配置多个 Trigger,实现 Push 触发构建、PR 触发校验、Tag 触发版本发布的不同路由策略,避免为每种事件类型部署多个入口
  3. 动态参数注入:TriggerBinding 从 Webhook 载荷中提取分支名、提交 SHA、仓库 URL 等参数,TriggerTemplate 将这些参数注入到 PipelineRun 中,实现完全动态的流水线运行
  4. 生产级过滤:CEL Interceptor 支持复杂的逻辑表达式,可以排除机器人提交、过滤特定文件路径、提取时间戳作为镜像标签等高级场景

下一篇文章将介绍 tkn CLI 完全指南,带你掌握用命令行管理 Tekton 资源的所有技巧。

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享
评论 抢沙发
头像
欢迎您留下宝贵的见解!
提交
头像

昵称

取消
昵称表情代码图片快捷回复

    暂无评论内容