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

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

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

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

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

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

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

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

    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  # 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 синхронизирует этот spec в ConfigMap trigger-wrapper-config внутри системного namespace Tekton (по умолчанию: tekton-pipelines). После обновления контроллер автоматического экспонирования обновит свой кэш и выполнит reconciliation ресурсов согласно новым правилам.

    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 для локального тестирования). Домен должен быть разрешим с систем, которые будут отправлять вебхуки.

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

      Можно воспринимать это как: "публичный адрес", который внешние системы (например, GitHub, GitLab) будут использовать для отправки вебхуков в ваш 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, что упрощает их копирование и вставку в конфигурацию вебхуков 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 path"https://192.168.1.100/clusters-rewrite/test"

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    Следующая таблица показывает, как поля правила экспонирования отображаются в сгенерированном ресурсе Ingress:

    Поле правила экспонированияПоле ресурса 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 формирует путь: ${urlPathPrefix}/${namespace}/${eventlistener-name}
    tlsspec.tlsTLS-конфигурация для HTTPS. Каждая запись сопоставляется с spec.tls[].hosts и spec.tls[].secretName
    annotationsmetadata.annotationsАннотации, заданные пользователем, объединяются с аннотациями, управляемыми контроллером
    namespaceSelectorN/AИспользуется для фильтрации EventListeners, напрямую не сопоставляется с Ingress
    labelSelectorN/AИспользуется для фильтрации EventListeners, напрямую не сопоставляется с Ingress
    externalHostsN/AИспользуется для заполнения status.addresses EventListener, напрямую не сопоставляется с Ingress

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

    Для такого правила экспонирования:

    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 и аннотации, управляемые контроллером

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

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

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

    Пример 1: wildcard host с кастомным префиксом

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

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

    Пример 2: общий hostname и префикс

    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 видит тот же путь.

    Пример 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: https://gitlab-staging.example.com/staging/gitlab/${namespace}/${eventlistener}
    • Вебхуки GitHub: https://github-prod.example.com/prod/github/${namespace}/${eventlistener}

    Пример 4: публикация в рамках team с префиксом по умолчанию

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

    Результат: только EventListeners в team-a будут экспонированы по адресу /triggers/team-a/${eventlistener}.

    Пример 5: несколько внешних endpoint'ов и изменённый префикс

    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. Настройте правило экспонирования с 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 для автоматического управления сертификатами

    Настройте правило экспонирования с annotations 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-конфигурацией

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

    Вы можете сочетать ручную TLS-конфигурацию с дополнительными annotations:

    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 и annotations cert-manager, приоритет имеет конфигурация tls. Для автоматического управления сертификатами используйте annotations cert-manager без конфигурации tls.

    Порядок настройки

    1. Отредактируйте ресурс TektonConfig (см. Точка входа в конфигурацию).
    2. Примените изменения: kubectl apply -f tektonconfig.yaml.
    3. Дождитесь, пока Operator распространит ConfigMap; после этого контроллер автоматического экспонирования автоматически выполнит reconciliation новых ресурсов.

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

    Проверка содержимого 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 создаются для подходящих EventListeners:

    # 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 существуют для EventListeners, которые соответствуют правилам экспонирования
    • Поле HOSTS соответствует host, указанному в правиле экспонирования
    • У Ingress назначен ADDRESS (это может занять несколько минут)
    • Если Ingress не появился, проверьте, что namespace соответствует matchNames, а labels EventListener соответствуют labelSelector

    Проверка адресов EventListener

    Проверьте, что статус EventListener содержит сгенерированные URL вебхуков:

    # 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 не соответствует ни одному правилу экспонирования

    Проверка annotations Trigger

    Проверьте метаданные экспонирования, сохранённые в annotations 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"
        }
      }
    ]

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

    • Annotation содержит массив информации об EventListener
    • Каждая запись включает поля name, namespace, endpoints и relevance
    • Массив endpoints соответствует status.addresses EventListener
    • relevance.score показывает, насколько хорошо EventListener соответствует Trigger (чем выше, тем лучше)
    • Если annotation отсутствует, возможно, Trigger не нашёл подходящих EventListeners

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

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

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

      • Отображаются в логах контроллера как ошибки разбора
      • Проверьте логи контроллера: 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-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, вы можете гибко управлять тем, как EventListeners Tekton экспонируются внешним системам. Во время обновлений следите за логами контроллера, чтобы подтвердить успешное завершение reconciliation.