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

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

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

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

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

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

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

    Контроллер автоматического экспонирования (внутреннее имя trigger-wrapper) читает ConfigMap trigger-wrapper-config в системном namespace Tekton (по умолчанию: tekton-pipelines). Правила export-rules, определённые в этом ConfigMap, определяют, какие EventListener должны быть экспонированы внешне (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  # Убедитесь, что настроено разрешение DNS (или добавьте в /etc/hosts для тестирования)
                      ingressClass: nginx
                      urlPathPrefix: /triggers
                      externalHosts:
                        - "https://webhooks.example.com"
                        - "https://backup.webhooks.example.com"
                      namespaceSelector:
                        matchNames:
                          - "*"

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

    INFO

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

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

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

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

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

    • host (необязательно) – hostname, который будет сопоставляться 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 в externalHosts — контроллер добавит его автоматически
      • Если не уверены, оставьте пустым и сначала проверьте фактический доступный URL, затем обновите конфигурацию
    • urlPathPrefix (необязательно) – префикс пути; по умолчанию /triggers. Итоговый путь в Ingress: ${urlPathPrefix}/${eventlistener-namespace}/${eventlistener-name}. Всегда начинайте с / и избегайте завершающих слэшей.

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

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

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

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

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

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

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

    Поле export ruleПоле ресурса IngressОписание
    namemetadata.nameИмя ресурса Ingress совпадает с именем правила
    ingressClassspec.ingressClassNameУказывает, какой контроллер Ingress будет обрабатывать этот Ingress
    hostspec.rules[].hostХост для правила Ingress. Если пусто или "*", совпадает со всеми хостами. Примечание: IP-адреса не поддерживаются в качестве значения host. Если используется IP, оставьте host пустым или настройте домен.
    urlPathPrefixspec.rules[].http.paths[].pathКомбинируется с namespace и именем EventListener в путь: ${urlPathPrefix}/${namespace}/${eventlistener-name}
    tlsspec.tlsКонфигурация TLS для 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: wildcard host с кастомным префиксом

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

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

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

    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: несколько внешних endpoint и изменённый префикс

    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} внутри кластера.
    • Внешне доступны URL 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 (или другого настроенного issuer)
    • Создаст 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> на namespace, где развернут ваш EventListener
    # Например, если EventListener в namespace 'tekton-triggers-demo':
    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, подходящих под правила экспорта
    • Поле HOSTS совпадает с host из правила экспорта
    • Ingress имеет назначенный ADDRESS (может появиться через несколько минут)
    • Если Ingress отсутствует, проверьте, что namespace входит в matchNames, а метки EventListener соответствуют labelSelector

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

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

    # Замените <el-name> на имя вашего EventListener и <namespace> на 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> на 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 экспонируются для внешних систем. Следите за логами контроллера при обновлениях, чтобы убедиться, что согласование прошло успешно.