• Русский
  • Настройка правил автоматического экспонирования EventListener

    Что поможет вам сделать этот документ

    Этот документ поможет вам настроить автоматическое внешнее экспонирование EventListener с помощью функции автоматического экспонирования. Вы узнаете:

    • Как настроить правила экспорта, чтобы автоматически публиковать EventListener через Ingress
    • Как настроить webhook URL, которые будут отображаться в UI
    • Как настроить разные стратегии экспонирования для разных namespace или окружений
    • Как проверить, что EventListener корректно экспонированы

    Когда это использовать: Используйте эту функцию, если хотите, чтобы система автоматически создавала ресурсы Ingress для ваших EventListener, избавляя от необходимости вручную создавать и управлять ресурсами Ingress. Это особенно полезно в production-окружениях, где нужны единообразные шаблоны webhook URL.

    Предварительные требования: У вас должны быть права cluster administrator для настройки ресурсов TektonConfig, а также базовое понимание Kubernetes Ingress и сетевых концепций.

    Обзор функции

    Контроллер автоматического экспонирования (внутреннее имя — trigger-wrapper) читает ConfigMap trigger-wrapper-config в системном namespace Tekton (по умолчанию: tekton-pipelines). Определённые в этой ConfigMap export-rules задают, какие EventListener должны быть экспонированы внешне (Service, Ingress и т. д.), и заполняют status EventListener/Trigger сгенерированными endpoint.

    INFO

    Техническая заметка: Внутреннее имя компонента — trigger-wrapper, но запоминать его не требуется. Вам нужно только настроить правила экспорта через TektonConfig, а остальное система выполнит автоматически.

    Точка входа для конфигурации

    В Alauda Tekton рекомендуется управлять этой конфигурацией через custom resource 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  # Ensure DNS resolution is configured (or add to /etc/hosts for testing)
                      ingressClass: nginx
                      urlPathPrefix: /triggers
                      externalHosts:
                        - "https://webhooks.example.com"
                        - "https://backup.webhooks.example.com"
                      namespaceSelector:
                        matchNames:
                          - "*"

    Operator синхронизирует эту спецификацию в ConfigMap trigger-wrapper-config внутри системного namespace Tekton (по умолчанию: tekton-pipelines). После обновления контроллер автоматического экспонирования обновит свой cache и выполнит reconcile ресурсов в соответствии с новыми правилами.

    INFO

    Примечание: Имя ConfigMap trigger-wrapper-config — это внутреннее техническое имя. Вы управляете конфигурацией через TektonConfig, как показано выше, и не должны напрямую взаимодействовать с ConfigMap.

    Справочник по полям

    Каждая запись в export-rules представляет стратегию публикации. Важные поля:

    • name – имя правила, также используется при генерации имён Service/Ingress.

    • ingressClass (optional) – Ingress controller, который нужно использовать, например nginx, traefik.

    • host (optional) – hostname, сопоставляемый Ingress. Оставьте пустым, чтобы принимать все hosts. Важно: при настройке доменного имени убедитесь, что DNS resolution настроен корректно (или добавьте запись в /etc/hosts для локального тестирования). Домен должен быть разрешаемым с систем, которые будут отправлять webhooks.

    • externalHosts (optional) – Что делает: задаёт webhook URL, которые будут отображаться пользователям в UI и попадут в поле status.addresses у EventListener.

      Можно считать это: «публичным адресом», который внешние системы (например, GitHub, GitLab) будут использовать для отправки webhooks в ваш EventListener.

      Как это работает:

      • Контроллер объединяет каждый URL из externalHosts с сгенерированным путём: ${externalHost}/<urlPathPrefix>/<eventlistener-namespace>/<eventlistener-name>
      • Например: externalHosts: ["https://webhooks.example.com"] + urlPathPrefix: /triggers → Итоговый URL: https://webhooks.example.com/triggers/my-namespace/my-listener
      • Эти URL отображаются в поле status.addresses EventListener, что позволяет легко копировать их в конфигурацию webhook в GitHub/GitLab

      Типовые сценарии:

      СценарийЧто указать в externalHostsПример
      Стандартный домен с HTTPSВаш публичный домен с https://"https://webhooks.example.com"
      LoadBalancer с кастомным портомДомен/IP с номером порта"https://webhooks.example.com:8443"
      Несколько точек доступаМассив резервных URL["https://primary.com", "https://backup.com"]
      Доступ по IP (без домена)HTTP с IP-адресом"http://192.168.1.100" (но оставьте поле host пустым)
      Платформа ACPURL платформы + путь к cluster"https://192.168.1.100/clusters-rewrite/test"

      Что произойдёт, если указать неверно?

      • ✅ Ingress по-прежнему будет работать корректно (это поле не влияет на создание Ingress)
      • ❌ Пользователи увидят некорректные webhook URL в UI
      • ❌ Копирование URL из status.addresses в GitHub/GitLab завершится ошибкой
      • 🔧 Исправление: обновите значение externalHosts в TektonConfig, и контроллер обновит status EventListener

      Ключевые отличия от поля host:

      ПолеНазначениеИспользуетсяПример
      hostПравило маршрутизации Ingress (сопоставление HTTP Host header)Kubernetes Ingresswebhooks.example.com (только домен, без protocol)
      externalHostswebhook URL для отображения в UIEventListener status.addresseshttps://webhooks.example.com (полный URL с protocol)

      Практическое правило:

      • Если webhook доступен по адресу https://webhooks.example.com:8443/triggers/ns/el, тогда укажите: externalHosts: ["https://webhooks.example.com:8443"]
      • Контроллер автоматически добавит path

      Важные замечания:

      • Всегда указывайте protocol (http:// или https://)
      • Указывайте custom ports, если ваш LoadBalancer использует нестандартные порты
      • Не включайте path в urlPathPrefix (например, /triggers) — контроллер автоматически добавит его в конец externalHosts
      • Если вы не уверены, оставьте поле пустым и сначала проверьте фактически доступный URL, а затем обновите конфигурацию
    • urlPathPrefix (optional) – префикс path; по умолчанию /triggers. Итоговый path, формируемый в Ingress, имеет вид ${urlPathPrefix}/${eventlistener-namespace}/${eventlistener-name}. Всегда начинайте с / и избегайте завершающих слэшей.

    • namespaceSelector.matchNames (optional) – namespace, разрешённые этим правилом. Используйте "*" для выбора всех namespace.

    • labelSelector (optional) – Kubernetes LabelSelector, используемый для фильтрации EventListener.

    • tls (optional) – TLS configuration для Ingress. Каждая запись задаёт hosts (список hostnames) и secretName (имя TLS Secret, содержащего сертификат).

    • annotations (optional) – дополнительные аннотации для Ingress. Полезно для cert-manager, специфичных настроек nginx и т. д. Аннотации, управляемые controller'ом (например, nginx.ingress.kubernetes.io/rewrite-target), будут объединены с аннотациями, заданными пользователем.

    Сопоставление namespace сейчас поддерживает только matchNames. Если вам нужен выбор namespace по label, перечислите namespace явно.

    Соответствие полей ресурсам Ingress

    В следующей таблице показано, как поля export rule сопоставляются с сгенерированным ресурсом Ingress:

    Поле export ruleПоле ресурса IngressОписание
    namemetadata.nameИмя ресурса Ingress задаётся именем правила
    ingressClassspec.ingressClassNameУказывает, какой Ingress controller должен обрабатывать этот Ingress
    hostspec.rules[].hostHostname для правила Ingress. Если поле пустое или равно "*", сопоставляются все hosts. Примечание: IP-адреса не поддерживаются как значения host. Если используется IP, оставьте host пустым или настройте доменное имя, которое разрешается в этот IP.
    urlPathPrefixspec.rules[].http.paths[].pathОбъединяется с namespace и именем EventListener для формирования path: ${urlPathPrefix}/${namespace}/${eventlistener-name}
    tlsspec.tlsTLS configuration для HTTPS. Каждая запись сопоставляется с spec.tls[].hosts и spec.tls[].secretName
    annotationsmetadata.annotationsАннотации, заданные пользователем, объединяются с аннотациями, управляемыми controller'ом
    namespaceSelectorN/AИспользуется для фильтрации EventListener, напрямую не сопоставляется с Ingress
    labelSelectorN/AИспользуется для фильтрации EventListener, напрямую не сопоставляется с Ingress
    externalHostsN/AИспользуется для заполнения status.addresses EventListener, напрямую не сопоставляется с Ingress

    Пример сопоставления:

    Для такого export rule:

    export-rules:
      - name: test-webhooks
        host: webhooks.example.com  # Ensure DNS resolution is configured (or add to /etc/hosts for testing)
        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-записи настроены так, чтобы домен разрешался в IP вашего Ingress controller. Для локального тестирования можно добавить записи в /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 и аннотации, управляемые controller'ом

    Диаграмма потока запросов

    externalHosts сообщает внешним клиентам, по какому URL обращаться. Ingress по-прежнему сопоставляет запросы по host и ${urlPathPrefix}/${namespace}/${eventlistener}, а backend Service получает ровно этот path.

    Примеры конфигурации

    Пример 1: wildcard host с custom prefix

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

    Результат: Ingress экспонирует /hooks/default/${namespace}/${eventlistener}. Поскольку host пустой, будет принят любой hostname — это удобно, когда внешний gateway назначает публичный домен.

    Пример 2: общий hostname и prefix

    export-rules:
      - name: all-listeners
        host: webhooks.example.com  # Ensure DNS resolution is configured (or add to /etc/hosts for testing)
        urlPathPrefix: /triggers
        ingressClass: nginx
        namespaceSelector:
          matchNames:
            - "*"

    Результат: каждый EventListener будет доступен по https://webhooks.example.com/triggers/${namespace}/${eventlistener}; backend увидит тот же path.

    Пример 3: правила для разных окружений

    export-rules:
      - name: staging-gitlab
        host: gitlab-staging.example.com  # Ensure DNS resolution is configured (or add to /etc/hosts for testing)
        urlPathPrefix: /staging/gitlab
        namespaceSelector:
          matchNames:
            - staging-tools
        labelSelector:
          matchLabels:
            webhook-type: gitlab
    
      - name: prod-github
        host: github-prod.example.com  # Ensure DNS resolution is configured (or add to /etc/hosts for testing)
        urlPathPrefix: /prod/github
        ingressClass: traefik
        namespaceSelector:
          matchNames:
            - prod-tools
        labelSelector:
          matchLabels:
            webhook-type: github

    Результат:

    • GitLab webhooks: https://gitlab-staging.example.com/staging/gitlab/${namespace}/${eventlistener}
    • GitHub webhooks: https://github-prod.example.com/prod/github/${namespace}/${eventlistener}

    Пример 4: публикация в рамках team с default prefix

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

    Результат: публикуются только EventListener в team-a, по адресу /triggers/team-a/${eventlistener}.

    Пример 5: несколько внешних endpoint и скорректированный prefix

    export-rules:
      - name: multi-endpoints
        host: webhook.internal.local  # Ensure DNS resolution is configured (or add to /etc/hosts for testing)
        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}.
    • Backend 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. Настройте export rule с TLS:

      export-rules:
        - name: secure-webhooks
          host: webhooks.example.com  # Ensure DNS resolution is configured (or add to /etc/hosts for testing)
          urlPathPrefix: /triggers
          ingressClass: nginx
          tls:
            - hosts:
                - webhooks.example.com
              secretName: webhooks-tls-secret
          namespaceSelector:
            matchNames:
              - "*"

    Контроллер автоматически настроит Ingress с TLS, используя указанный Secret.

    Вариант B: использование cert-manager для автоматического управления сертификатами

    Настройте export rule с аннотациями cert-manager:

    export-rules:
      - name: cert-manager-webhooks
        host: webhooks.example.com  # Ensure DNS resolution is configured (or add to /etc/hosts for testing)
        urlPathPrefix: /triggers
        ingressClass: nginx
        annotations:
          cert-manager.io/cluster-issuer: "letsencrypt-prod"
          # Optional: additional nginx SSL settings
          nginx.ingress.kubernetes.io/ssl-protocols: "TLSv1.2 TLSv1.3"
        namespaceSelector:
          matchNames:
            - "*"

    cert-manager автоматически выполнит:

    • Создание ресурса Certificate
    • Получение сертификата от Let's Encrypt (или вашего настроенного issuer)
    • Создание TLS Secret
    • Обновление Ingress с TLS configuration

    Вариант C: комбинирование TLS и аннотаций

    Можно сочетать ручную настройку TLS с дополнительными аннотациями:

    export-rules:
      - name: custom-tls-with-annotations
        host: webhooks.example.com  # Ensure DNS resolution is configured (or add to /etc/hosts for testing)
        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; после этого контроллер автоматического экспонирования автоматически выполнит reconcile новых ресурсов.

    Проверка и устранение неполадок

    Проверка содержимого 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  # Ensure DNS resolution is configured (or add to /etc/hosts for testing)
            ingressClass: nginx
            urlPathPrefix: /triggers
            externalHosts:
              - "https://webhooks.example.com"
              - "https://backup.webhooks.example.com"
            namespaceSelector:
              matchNames:
                - "*"

    Что проверять:

    • ConfigMap существует и содержит ключ config
    • Массив export-rules соответствует спецификации TektonConfig
    • Синтаксис YAML корректен (нет ошибок разбора)

    Проверка объектов Ingress

    Проверьте, что ресурсы Ingress созданы для подходящих EventListener:

    # Replace <namespace> with the namespace where your EventListener is deployed
    # For example, if your EventListener is in the 'tekton-triggers-demo' namespace:
    kubectl get ingress -n tekton-triggers-demo

    Важно: <namespace> в команде должен быть namespace, где развернут ваш EventListener, а не системный namespace (tekton-pipelines). Функция автоматического экспонирования создаёт ресурсы Ingress в том же namespace, что и EventListener.

    Ожидаемый вывод (нормально):

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

    Что проверять:

    • Объекты Ingress существуют для EventListener, которые соответствуют export rules
    • Поле HOSTS соответствует host, заданному в export rule
    • Ingress имеет назначенный ADDRESS (это может занять несколько минут)
    • Если Ingress не появился, проверьте, что namespace соответствует matchNames, а labels EventListener соответствуют labelSelector

    Проверка addresses EventListener

    Убедитесь, что status EventListener содержит сгенерированные webhook addresses:

    # Replace <el-name> with your EventListener name and <namespace> with the namespace where it's deployed
    # For example, if your EventListener is named 'hello-listener' in the 'tekton-triggers-demo' namespace:
    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 содержит URL, соответствующие конфигурации externalHosts
    • URL следуют шаблону: <externalHost>/<urlPathPrefix>/<eventlistener-namespace>/<eventlistener-name>
    • Если addresses пуст или отсутствует, возможно, EventListener не соответствует ни одному export rule

    Проверка аннотаций Trigger

    Проверьте метаданные экспорта, сохранённые в аннотациях Trigger:

    # Replace <trigger-name> with your Trigger name and <namespace> with the namespace where it's deployed
    # For example, if your Trigger is named 'my-trigger' in the 'tekton-triggers-demo' namespace:
    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
    • Каждый элемент включает поля name, namespace, endpoints и relevance
    • Массив endpoints соответствует status.addresses EventListener
    • relevance.score показывает, насколько хорошо EventListener соответствует Trigger (чем выше, тем лучше)
    • Если аннотация отсутствует, возможно, Trigger не нашёл ни одного подходящего EventListener

    Советы по устранению неполадок

    • Если правило не применяется:

      • Убедитесь, что namespace указан в matchNames (или используйте "*" для всех namespace)
      • Проверьте, что labels EventListener удовлетворяют требованиям labelSelector
      • Убедитесь, что EventListener находится в состоянии Ready
    • Неверно настроенные label selector:

      • Отображаются в логах controller как ошибки разбора
      • Проверьте логи controller: kubectl logs -n tekton-pipelines -l app=tektoncd-enhancement-controller
    • Удаление правила:

      • Вызывает каскадное удаление сгенерированных ресурсов (Ingress, Service и т. д.)
      • Установка export-rules в пустой массив отключает всё внешнее экспонирование
      • status.addresses EventListener будет очищено, если ни одно правило не совпадает
    • Использование IP-адресов вместо доменных имён:

      • Проблема: ресурсы Kubernetes Ingress не поддерживают IP-адреса в качестве значений host. Если вы укажете host как IP-адрес (например, host: 192.168.1.100), Ingress не будет создан или не будет работать корректно.

      • Решение 1: оставьте host пустым или задайте "*" для принятия всех hosts. Ingress будет сопоставлять запросы независимо от host header:

        export-rules:
          - name: ip-based-webhooks
            host: ""  # or omit the host field entirely
            urlPathPrefix: /triggers
            externalHosts:
              - "http://192.168.1.100"  # Use IP in externalHosts for client reference
            namespaceSelector:
              matchNames:
                - "*"
      • Решение 2: настройте доменное имя, которое разрешается в ваш IP-адрес, а затем используйте этот домен в поле host:

        1. Настройте DNS resolution: добавьте A record, указывающую ваш домен на IP-адрес (например, webhooks.example.com192.168.1.100)

        2. Настройте export rule с доменным именем:

          export-rules:
            - name: domain-webhooks
              host: webhooks.example.com  # Domain that resolves to your IP. Ensure DNS resolution is configured (or add to /etc/hosts for testing)
              urlPathPrefix: /triggers
              externalHosts:
                - "http://192.168.1.100"  # Or use the domain: "http://webhooks.example.com"
              namespaceSelector:
                matchNames:
                  - "*"
      • Примечание: externalHosts может содержать IP-адреса или URL, поскольку используется только для заполнения status.addresses EventListener и не влияет на создание Ingress. Однако сам Ingress должен использовать корректный hostname (или быть пустым) в поле host.

    Поддерживая ConfigMap через TektonConfig, вы можете гибко управлять тем, как EventListener Tekton публикуются для внешних систем. Следите за логами controller во время обновлений, чтобы подтвердить, что reconcile завершился успешно.