配置 EventListener 自动暴露规则

本文档帮助您完成的工作

本文档帮助您通过自动暴露功能配置 EventListener 的自动外部暴露。您将学习:

  • 如何配置导出规则,通过 Ingress 自动暴露 EventListener
  • 如何设置将在 UI 中展示的 webhook URL
  • 如何为不同命名空间或环境配置不同的暴露策略
  • 如何验证 EventListener 是否正确暴露

使用场景:当您希望系统自动为 EventListener 创建 Ingress 资源,避免手动创建和管理 Ingress 资源时使用此功能。特别适用于需要统一 webhook URL 规范的生产环境。

前提条件:您应具备集群管理员权限以配置 TektonConfig 资源,并对 Kubernetes Ingress 和网络概念有基本了解。

功能概述

自动暴露控制器(内部名为 trigger-wrapper)会读取 Tekton 系统命名空间(默认:tekton-pipelines)中的 trigger-wrapper-config ConfigMap。该 ConfigMap 中定义的 export-rules 决定了哪些 EventListener 需要对外暴露(Service、Ingress 等),并将生成的端点填充到 EventListener/Trigger 的状态中。

INFO

技术说明:内部组件名为 trigger-wrapper,但您无需记住此名称。只需通过 TektonConfig 配置导出规则,系统会自动处理后续工作。

配置入口

在 Alauda Tekton 中,建议通过 TektonConfig 自定义资源管理此配置。将规则定义嵌入到 spec.pipeline.options.configMaps.trigger-wrapper-config.data.config 下,例如:

apiVersion: operator.tekton.dev/v1alpha1
kind: TektonConfig
metadata:
  name: config
spec:
  pipeline:
    options:
      configMaps:
        trigger-wrapper-config:
          data:
            config: |
              export-rules:
                - name: test-webhooks
                  host: webhooks.example.com  # 确保已配置 DNS 解析(或测试时添加到 /etc/hosts)
                  ingressClass: nginx
                  urlPathPrefix: /triggers
                  externalHosts:
                    - "https://webhooks.example.com"
                    - "https://backup.webhooks.example.com"
                  namespaceSelector:
                    matchNames:
                      - "*"

Operator 会将该 spec 同步到 Tekton 系统命名空间(默认:tekton-pipelines)中的 trigger-wrapper-config ConfigMap。更新后,自动暴露控制器会刷新缓存并根据新规则进行资源调和。

INFO

注意:ConfigMap 名称 trigger-wrapper-config 是内部技术名称。您通过上述方式管理配置,无需直接操作 ConfigMap。

字段参考

export-rules 中的每条记录代表一种发布策略。重要字段:

  • name – 规则名称,同时用于生成 Service/Ingress 名称。

  • ingressClass(可选)– 使用的 Ingress 控制器,例如 nginxtraefik

  • host(可选)– Ingress 匹配的主机名。留空表示接受所有主机。重要:配置域名时,请确保 DNS 解析正确(或测试时添加到 /etc/hosts)。域名必须能被发送 webhook 的系统解析。

  • externalHosts(可选)– 作用:定义将在 UI 中展示给用户的 webhook URL,并填充到 EventListener 的 status.addresses 字段。

    理解为:外部系统(如 GitHub、GitLab)调用 EventListener 时使用的“公网地址”。

    工作原理

    • 控制器将每个 externalHosts URL 与生成的路径组合:${externalHost}/<urlPathPrefix>/<eventlistener-namespace>/<eventlistener-name>
    • 例如:externalHosts: ["https://webhooks.example.com"] + urlPathPrefix: /triggers → 最终 URL:https://webhooks.example.com/triggers/my-namespace/my-listener
    • 这些 URL 会显示在 EventListener 的 status.addresses 字段,方便复制粘贴到 GitHub/GitLab webhook 配置中

    常见场景

    场景externalHosts 填写示例说明
    标准 HTTPS 域名"https://webhooks.example.com"使用带 https:// 的公网域名
    带自定义端口的 LoadBalancer"https://webhooks.example.com:8443"域名或 IP 带端口号
    多个访问入口["https://primary.com", "https://backup.com"]多个备用 URL
    基于 IP 访问(无域名)"http://192.168.1.100"(host 置空)仅 IP 地址,host 字段留空
    ACP 平台"https://192.168.1.100/clusters-rewrite/test"平台 URL + 集群路径

    填写错误会怎样?

    • ✅ Ingress 仍能正常工作(该字段不影响 Ingress 创建)
    • ❌ UI 中显示的 webhook URL 不正确
    • ❌ 从 status.addresses 复制 URL 到 GitHub/GitLab 会失败
    • 🔧 解决方法:更新 TektonConfig 中的 externalHosts,控制器会刷新 EventListener 状态

    host 字段的关键区别

    字段作用使用方示例
    hostIngress 路由规则(HTTP Host 头匹配)Kubernetes Ingresswebhooks.example.com(仅域名,无协议)
    externalHostsUI 显示的用户 webhook URLEventListener status.addresseshttps://webhooks.example.com(带协议的完整 URL)

    经验法则

    • 如果您能通过 https://webhooks.example.com:8443/triggers/ns/el 访问 webhook,则填写:externalHosts: ["https://webhooks.example.com:8443"]
    • 控制器会自动追加路径

    重要提示

    • 始终包含协议(http://https://
    • 如果 LoadBalancer 使用非标准端口,需包含端口号
    • 不要在 urlPathPrefix 中包含路径(如 /triggers),控制器会自动追加
    • 不确定时可先留空,确认实际可访问 URL 后再更新配置
  • urlPathPrefix(可选)– 路径前缀,默认 /triggers。Ingress 中最终路径为 ${urlPathPrefix}/${eventlistener-namespace}/${eventlistener-name}。必须以 / 开头,避免尾部斜杠。

  • namespaceSelector.matchNames(可选)– 规则允许的命名空间。使用 "*" 表示所有命名空间。

  • labelSelector(可选)– Kubernetes LabelSelector,用于筛选 EventListener。

  • tls(可选)– Ingress 的 TLS 配置。每条记录指定 hosts(主机名列表)和 secretName(包含证书的 TLS Secret 名称)。

  • annotations(可选)– 额外的 Ingress 注解。适用于 cert-manager、nginx 特定设置等。控制器管理的注解(如 nginx.ingress.kubernetes.io/rewrite-target)会与用户注解合并。

命名空间匹配当前仅支持 matchNames。若需基于标签选择命名空间,请显式列举命名空间。

字段与 Ingress 资源映射

下表展示导出规则字段如何映射到生成的 Ingress 资源:

导出规则字段Ingress 资源字段说明
namemetadata.nameIngress 资源名称设为规则名称
ingressClassspec.ingressClassName指定由哪个 Ingress 控制器处理该 Ingress
hostspec.rules[].hostIngress 规则的主机名。为空或 "*" 时匹配所有主机。**注意:**不支持 IP 地址作为 host 值。若使用 IP,请留空或配置可解析到该 IP 的域名。
urlPathPrefixspec.rules[].http.paths[].path与命名空间和 EventListener 名称组合形成路径:${urlPathPrefix}/${namespace}/${eventlistener-name}
tlsspec.tlsHTTPS 的 TLS 配置。每条记录映射到 spec.tls[].hostsspec.tls[].secretName
annotationsmetadata.annotations用户提供的注解与控制器管理的注解合并
namespaceSelector用于筛选 EventListener,不直接映射到 Ingress
labelSelector用于筛选 EventListener,不直接映射到 Ingress
externalHosts用于填充 EventListener status.addresses,不直接映射到 Ingress

示例映射:

给定以下导出规则:

export-rules:
  - name: test-webhooks
    host: webhooks.example.com  # 确保已配置 DNS 解析(或测试时添加到 /etc/hosts)
    ingressClass: nginx
    urlPathPrefix: /triggers
    tls:
      - hosts:
          - webhooks.example.com
        secretName: webhooks-tls-secret
    annotations:
      cert-manager.io/cluster-issuer: "letsencrypt-prod"
WARNING

DNS 配置host 字段使用域名时,请确保 DNS 记录正确解析到 Ingress 控制器 IP。测试时可添加 /etc/hosts(Linux/Mac)或 C:\Windows\System32\drivers\etc\hosts(Windows)条目。

生成的 Ingress 包含:

  • metadata.name: test-webhooks
  • spec.ingressClassName: nginx
  • spec.rules[0].host: webhooks.example.com
  • spec.rules[0].http.paths[].path: /triggers/${namespace}/${eventlistener-name}(针对每个匹配的 EventListener)
  • spec.tls[0].hosts: ["webhooks.example.com"]
  • spec.tls[0].secretName: webhooks-tls-secret
  • metadata.annotations: 包含 cert-manager.io/cluster-issuer 和控制器管理的注解

请求流程图

externalHosts 告诉外部客户端调用哪个 URL。Ingress 仍通过 host${urlPathPrefix}/${namespace}/${eventlistener} 匹配请求,后端 Service 接收的路径完全相同。

配置示例

示例 1:通配符 host 和自定义前缀

export-rules:
  - name: wildcard-host
    urlPathPrefix: /hooks/default
    ingressClass: nginx
    namespaceSelector:
      matchNames:
        - cicd

结果:Ingress 暴露路径为 /hooks/default/${namespace}/${eventlistener}。由于 host 为空,接受任意主机名,适合外部网关分配公网域名的场景。

示例 2:共享主机名和前缀

export-rules:
  - name: all-listeners
    host: webhooks.example.com  # 确保已配置 DNS 解析(或测试时添加到 /etc/hosts)
    urlPathPrefix: /triggers
    ingressClass: nginx
    namespaceSelector:
      matchNames:
        - "*"

结果:所有 EventListener 均可通过 https://webhooks.example.com/triggers/${namespace}/${eventlistener} 访问,后端路径保持一致。

示例 3:环境特定规则

export-rules:
  - name: staging-gitlab
    host: gitlab-staging.example.com  # 确保已配置 DNS 解析(或测试时添加到 /etc/hosts)
    urlPathPrefix: /staging/gitlab
    namespaceSelector:
      matchNames:
        - staging-tools
    labelSelector:
      matchLabels:
        webhook-type: gitlab

  - name: prod-github
    host: github-prod.example.com  # 确保已配置 DNS 解析(或测试时添加到 /etc/hosts)
    urlPathPrefix: /prod/github
    ingressClass: traefik
    namespaceSelector:
      matchNames:
        - prod-tools
    labelSelector:
      matchLabels:
        webhook-type: github

结果:

  • GitLab webhook 地址为 https://gitlab-staging.example.com/staging/gitlab/${namespace}/${eventlistener}
  • GitHub webhook 地址为 https://github-prod.example.com/prod/github/${namespace}/${eventlistener}

示例 4:团队范围发布,使用默认前缀

export-rules:
  - name: team-a
    urlPathPrefix: /triggers
    namespaceSelector:
      matchNames:
        - team-a

结果:仅 team-a 命名空间中的 EventListener 被暴露,路径为 /triggers/team-a/${eventlistener}

示例 5:多个外部端点及调整前缀

export-rules:
  - name: multi-endpoints
    host: webhook.internal.local  # 确保已配置 DNS 解析(或测试时添加到 /etc/hosts)
    urlPathPrefix: /internal/hooks
    externalHosts:
      - https://webhooks.example.com/hooks/
      - https://backup.example.com/api/hooks
    namespaceSelector:
      matchNames:
        - ci-tools

结果:

  • Ingress 内部服务地址为 webhook.internal.local/internal/hooks/${namespace}/${eventlistener}
  • 外部可发布的地址为 https://webhooks.example.com/hooks/internal/hooks/${namespace}/${eventlistener}https://backup.example.com/api/hooks/internal/hooks/${namespace}/${eventlistener}
  • 后端 Service 始终接收 /internal/hooks/${namespace}/${eventlistener} 路径

示例 6:配置 TLS/HTTPS

方案 A:手动 TLS,预先创建 Secret

  1. 创建包含证书的 TLS Secret:

    kubectl create secret tls webhooks-tls-secret \
      --cert=path/to/cert.pem \
      --key=path/to/key.pem \
      -n tekton-pipelines
  2. 在导出规则中配置 TLS:

    export-rules:
      - name: secure-webhooks
        host: webhooks.example.com  # 确保已配置 DNS 解析(或测试时添加到 /etc/hosts)
        urlPathPrefix: /triggers
        ingressClass: nginx
        tls:
          - hosts:
              - webhooks.example.com
            secretName: webhooks-tls-secret
        namespaceSelector:
          matchNames:
            - "*"

控制器会自动使用指定 Secret 配置 Ingress TLS。

方案 B:使用 cert-manager 自动证书管理

在导出规则中添加 cert-manager 注解:

export-rules:
  - name: cert-manager-webhooks
    host: webhooks.example.com  # 确保已配置 DNS 解析(或测试时添加到 /etc/hosts)
    urlPathPrefix: /triggers
    ingressClass: nginx
    annotations:
      cert-manager.io/cluster-issuer: "letsencrypt-prod"
      # 可选:额外的 nginx SSL 设置
      nginx.ingress.kubernetes.io/ssl-protocols: "TLSv1.2 TLSv1.3"
    namespaceSelector:
      matchNames:
        - "*"

cert-manager 会自动:

  • 创建 Certificate 资源
  • 从 Let’s Encrypt(或配置的颁发者)获取证书
  • 创建 TLS Secret
  • 更新 Ingress 的 TLS 配置

方案 C:TLS 与注解组合

您也可以结合手动 TLS 和额外注解:

export-rules:
  - name: custom-tls-with-annotations
    host: webhooks.example.com  # 确保已配置 DNS 解析(或测试时添加到 /etc/hosts)
    urlPathPrefix: /triggers
    ingressClass: nginx
    tls:
      - hosts:
          - webhooks.example.com
        secretName: custom-tls-secret
    annotations:
      nginx.ingress.kubernetes.io/ssl-protocols: "TLSv1.2 TLSv1.3"
      nginx.ingress.kubernetes.io/ssl-ciphers: "HIGH:!aNULL:!MD5"
    namespaceSelector:
      matchNames:
        - "*"

注意:当同时配置了 tls 和 cert-manager 注解时,以 tls 配置优先。若需自动证书管理,请仅使用 cert-manager 注解,不配置 tls

配置流程

  1. 编辑 TektonConfig 资源(参见 配置入口)。
  2. 应用变更:kubectl apply -f tektonconfig.yaml
  3. 等待 Operator 同步 ConfigMap,自动暴露控制器将自动调和新资源。

验证与排查

验证 ConfigMap 内容

检查 ConfigMap 是否包含预期配置:

kubectl get configmap trigger-wrapper-config -n tekton-pipelines -o yaml

预期输出(正常):

apiVersion: v1
kind: ConfigMap
metadata:
  name: trigger-wrapper-config
  namespace: tekton-pipelines
data:
  config: |
    export-rules:
      - name: test-webhooks
        host: webhooks.example.com  # 确保已配置 DNS 解析(或测试时添加到 /etc/hosts)
        ingressClass: nginx
        urlPathPrefix: /triggers
        externalHosts:
          - "https://webhooks.example.com"
          - "https://backup.webhooks.example.com"
        namespaceSelector:
          matchNames:
            - "*"

检查点:

  • ConfigMap 存在且包含 config
  • export-rules 数组与 TektonConfig 规范一致
  • YAML 语法正确(无解析错误)

验证 Ingress 对象

检查是否为匹配的 EventListener 创建了 Ingress 资源:

# 替换 <namespace> 为 EventListener 所在命名空间
# 例如,EventListener 在 'tekton-triggers-demo' 命名空间:
kubectl get ingress -n tekton-triggers-demo

重要:命令中的 <namespace> 应为 EventListener 所在命名空间,而非系统命名空间(tekton-pipelines)。自动暴露功能会在 EventListener 所在命名空间创建 Ingress。

预期输出(正常):

NAME                              CLASS   HOSTS                    ADDRESS   PORTS   AGE
el-<eventlistener-name>           nginx   webhooks.example.com     ...        80      5m

检查点:

  • 存在匹配导出规则的 EventListener 的 Ingress 对象
  • HOSTS 字段与导出规则中的 host 匹配
  • Ingress 已分配 ADDRESS(可能需几分钟)
  • 若无 Ingress,确认命名空间符合 matchNames,EventListener 标签符合 labelSelector

检查 EventListener 地址

验证 EventListener 状态中是否包含生成的 webhook 地址:

# 替换 <el-name> 为 EventListener 名称,<namespace> 为其所在命名空间
# 例如,EventListener 名为 'hello-listener',命名空间为 'tekton-triggers-demo':
kubectl get eventlistener hello-listener -n tekton-triggers-demo \
  -o jsonpath='{.status.addresses}' | jq

预期输出(正常):

[
  {
    "url": "https://webhooks.example.com/triggers/<namespace>/<el-name>"
  },
  {
    "url": "https://backup.webhooks.example.com/triggers/<namespace>/<el-name>"
  }
]

检查点:

  • addresses 数组包含符合 externalHosts 配置的 URL
  • URL 格式为 <externalHost>/<urlPathPrefix>/<eventlistener-namespace>/<eventlistener-name>
  • addresses 为空或缺失,可能 EventListener 未匹配任何导出规则

检查 Trigger 注解

查看 Trigger 注解中存储的导出元数据:

# 替换 <trigger-name> 为 Trigger 名称,<namespace> 为其所在命名空间
# 例如,Trigger 名为 'my-trigger',命名空间为 'tekton-triggers-demo':
kubectl get trigger my-trigger -n tekton-triggers-demo \
  -o jsonpath='{.metadata.annotations.triggers\.tekton\.dev/eventlistener-info}' | jq

预期输出(正常):

[
  {
    "name": "my-eventlistener",
    "namespace": "my-namespace",
    "endpoints": [
      "https://webhooks.example.com/triggers/my-namespace/my-eventlistener",
      "https://backup.webhooks.example.com/triggers/my-namespace/my-eventlistener"
    ],
    "relevance": {
      "score": 1000,
      "namespaceScore": 1000,
      "labelScore": 1000,
      "namespaceSelector": {
        "matchNames": ["my-namespace"]
      },
      "matchType": "direct"
    }
  }
]

检查点:

  • 注解包含 EventListener 信息数组
  • 每条记录包含 namenamespaceendpointsrelevance 字段
  • endpoints 数组与 EventListener 的 status.addresses 匹配
  • relevance.score 表示 Trigger 与 EventListener 的匹配度(越高越好)
  • 若注解缺失,可能 Trigger 未找到匹配的 EventListener

排查建议

  • 规则未生效时:

    • 确认命名空间包含在 matchNames 中(或使用 "*" 表示所有命名空间)
    • 检查 EventListener 标签是否满足 labelSelector 条件
    • 确保 EventListener 处于 Ready 状态
  • 标签选择器配置错误:

    • 控制器日志中会显示解析错误
    • 查看控制器日志:kubectl logs -n tekton-pipelines -l app=tektoncd-enhancement-controller
  • 删除规则:

    • 会级联删除生成的资源(Ingress、Service 等)
    • export-rules 设为空数组可禁用所有外部暴露
    • EventListener 的 status.addresses 会在无匹配规则时被清空
  • 使用 IP 地址代替域名:

    • 问题:Kubernetes Ingress 资源不支持 IP 地址作为 host 值。如果将 host 配置为 IP(如 host: 192.168.1.100),Ingress 创建会失败或无法正常工作。

    • 解决方案 1:将 host 留空或设为 "*",接受所有主机。Ingress 会匹配所有请求的 Host 头:

      export-rules:
        - name: ip-based-webhooks
          host: ""  # 或完全省略 host 字段
          urlPathPrefix: /triggers
          externalHosts:
            - "http://192.168.1.100"  # externalHosts 中使用 IP 供客户端参考
          namespaceSelector:
            matchNames:
              - "*"
    • 解决方案 2:配置解析到该 IP 的域名,并在 host 字段使用该域名:

      1. 配置 DNS 解析:添加 A 记录,将域名指向 IP(如 webhooks.example.com192.168.1.100

      2. 在导出规则中使用域名:

        export-rules:
          - name: domain-webhooks
            host: webhooks.example.com  # 解析到 IP 的域名,确保 DNS 配置正确(或测试时添加到 /etc/hosts)
            urlPathPrefix: /triggers
            externalHosts:
              - "http://192.168.1.100"  # 或使用域名:"http://webhooks.example.com"
            namespaceSelector:
              matchNames:
                - "*"
    • 注意externalHosts 可包含 IP 地址或 URL,仅用于填充 EventListener status.addresses,不影响 Ingress 创建。但 Ingress 的 host 字段必须是有效主机名或为空。

通过使用 TektonConfig 维护 ConfigMap,您可以灵活控制 Tekton EventListener 如何对外暴露。更新时请关注控制器日志,确保调和成功。