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

    Чем поможет этот документ

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

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

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

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

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

    Контроллер автоматического экспонирования (внутреннее имя — trigger-wrapper) читает ConfigMap trigger-wrapper-config в системном пространстве имён Tekton (по умолчанию: tekton-pipelines). Правила export-rules, определённые в этом ConfigMap, определяют, какие 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:
                          - "*"

    Оператор синхронизирует этот spec в ConfigMap trigger-wrapper-config внутри системного пространства имён Tekton (по умолчанию tekton-pipelines). После обновления контроллер автоматического экспонирования обновит кэш и выполнит согласование ресурсов согласно новым правилам.

    INFO

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

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

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

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

    • ingressClass (необязательно) – контроллер Ingress, например nginx, traefik.

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

    • externalHosts (необязательно) – Что делает: Определяет 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 платформы + путь к кластеру"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 вебхука для отображения пользователю в UIstatus.addresses EventListenerhttps://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 (необязательно) – префикс пути; по умолчанию /triggers. Итоговый путь в Ingress: ${urlPathPrefix}/${eventlistener-namespace}/${eventlistener-name}. Всегда начинайте с / и избегайте завершающих слэшей.

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

    • labelSelector (необязательно) – Kubernetes LabelSelector для фильтрации EventListener.

    • tls (необязательно) – TLS-конфигурация для Ingress. Каждый элемент указывает hosts (список имён хостов) и secretName (имя TLS Secret с сертификатом).

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

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

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

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

    Поле правила экспортаПоле ресурса IngressОписание
    namemetadata.nameИмя ресурса Ingress совпадает с именем правила
    ingressClassspec.ingressClassNameУказывает, какой контроллер Ingress обрабатывает этот Ingress
    hostspec.rules[].hostИмя хоста для правила Ingress. Если пустое или "*", совпадает со всеми хостами. Примечание: 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Используется для фильтрации EventListener, не отображается напрямую в Ingress
    labelSelectorN/AИспользуется для фильтрации EventListener, не отображается напрямую в Ingress
    externalHostsN/AИспользуется для заполнения status.addresses EventListener, не отображается напрямую в 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-записи настроены для разрешения домена в IP вашего контроллера Ingress. Для локального тестирования можно добавить записи в /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: универсальный хост с пользовательским префиксом

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

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

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

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

    Результат: экспонируются только EventListener в team-a по адресу /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}.
    • 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  # Убедитесь, что настроено разрешение DNS (или добавьте в /etc/hosts для тестирования)
          urlPathPrefix: /triggers
          ingressClass: nginx
          tls:
            - hosts:
                - webhooks.example.com
              secretName: webhooks-tls-secret
          namespaceSelector:
            matchNames:
              - "*"

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

    Вариант 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"
          # Опционально: дополнительные настройки SSL nginx
          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. Дождитесь, пока Оператор распространит 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

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

    # Замените <namespace> на пространство имён, где развернут ваш EventListener
    # Например, если EventListener в namespace 'tekton-triggers-demo':
    kubectl get ingress -n tekton-triggers-demo

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

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

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

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

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

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

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

    # Замените <el-name> на имя вашего EventListener и <namespace> на пространство имён, где он развернут
    # Например, если EventListener называется 'hello-listener' в namespace '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 содержит URL, соответствующие конфигурации externalHosts
    • URL имеют формат: <externalHost>/<urlPathPrefix>/<eventlistener-namespace>/<eventlistener-name>
    • Если addresses пуст или отсутствует, EventListener может не подходить ни под одно правило экспорта

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

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

    # Замените <trigger-name> на имя вашего Trigger и <namespace> на пространство имён, где он развернут
    # Например, если Trigger называется 'my-trigger' в namespace '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
    • Каждая запись включает поля name, namespace, endpoints и relevance
    • Массив endpoints совпадает с status.addresses EventListener
    • relevance.score показывает, насколько хорошо EventListener подходит Trigger (чем выше, тем лучше)
    • Если аннотация отсутствует, Trigger мог не найти подходящих EventListener

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

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

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

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

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

      • Проблема: Kubernetes Ingress не поддерживает IP-адреса в поле host. Если указать IP в host (например, 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"  # IP в externalHosts для ссылок клиентов
            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, так как используется только для заполнения status.addresses EventListener и не влияет на создание Ingress. Однако Ingress должен использовать корректное имя хоста (или быть пустым) в поле host.

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