Руководство прикладного разработчика#

Термины и определения#

Термин/Аббревиатура

Определение

Endpoint

Сетевая точка, обеспечивающая взаимодействие с поставщиком

gRPC

Современная высокопроизводительная платформа, которая используется для развития устаревшего протокола удаленного вызова процедур (RPC)

Ingress (Egress) Gateway

Ресурс Istio, который описывает правила маршрутизации и балансировки входящих запросов. Альтернатива K8s Ingress (Egress) Gateway, настраивается через ресурсы Gateway, Virtual Service и при необходимости DestinationRule

K8s

Kubernetes, платформа с открытым исходным кодом для управления кластерами приложений и сервисами на основе контейнеров

OS

OpenShift, открытая и расширяемая платформа приложений-контейнеров

RL Operator

Компонент SRLS, обеспечивающий конфигурирование Ingress (Egress) Gateway в соответствии с CRD в runtime

RL Service

Компонент SRLS, сервис расчета лимитов, принимает gRPC-запросы от Ingress (Egress) Gateway, содержащие информацию о домене (в качестве домена используется название прикладного namespace), о вызываемом сервисе и данные из служебного заголовка, например, synapse-consumerid

SRLS (SRL)

Программный компонент Synapse Rate Limiter (Synapse Rate Limit), сервис ограничения (квотирования) входящих запросов необходим для ограничения прикладной нагрузки (payload) со стороны потребителя на защищаемые сервисы, исполняемые в рамках Synapse Service Mesh

Deploy Tools

Программный компонент, предназначенный для автоматизации развертывания и автоматической установки технологических сервисов и бизнес-приложений на тестовых и промышленных стендах (CDJE), программного продукта Platform V DevOps Tools (DOT)

Pod

Набор контейнеров внутри узла кластера Kubernetes или Red Hat OpenShift (опционально)

ТУЗ

Технологическая учетная запись

УЦ

Удостоверяющий центр

Системные требования#

Подробно системные требования описаны в документе «Руководство по установке» в разделе «Системные требования».

Подключение и конфигурирование#

В зависимости от выбранного варианта развертывания компонента SRLS (централизованный, децентрализованный) воспользуйтесь одной из инструкций:

  • конфигурирование артефактов среды контейнеризации и Istio для централизованного варианта развертывания;

  • конфигурирование артефактов среды контейнеризации и Istio для децентрализованного варианта развертывания.

Конфигурирование артефактов среды контейнеризации и Istio для централизованного варианта развертывания#

Пререквизиты#

Права доступа для Оператора Rate Limit выполнены по принципу минимальных прав для обеспечения требований безопасности. Для доступа к артефактам EnvoyFilter прикладного namespace требуется создать конфигурации ClusterRole и RoleBinding в yaml-формате.

ClusterRole:

kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: srls-role
rules:
  - verbs:
      - get
      - list
      - watch
      - create
      - update
      - patch
      - delete
    apiGroups:
      - networking.istio.io
    resources:
      - envoyfilters

RoleBinding, здесь необходимо указать ServiceAccount в namespace централизованного Rate Limit.

apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: srls-role-binding
  namespace: ${namespace}
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: srls-role
subjects:
- kind: ServiceAccount
  name: rate-limiter-service
  namespace: ${rls_namespace}

Здесь RLS-namespace — идентификатор namespace централизованного Rate Limit.

Для конфигурирования Rate Limit используется артефакт GlobalRateLimit. Для возможности его создания средствами DevOps для учетной записи Jenkins нужно добавить RoleBinding для следующей роли:

kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: pipeline-rate-limiter-service-role
rules:
  - verbs:
      - create
      - update
      - patch
      - delete
      - get
      - list
    apiGroups:
      - ratelimit.service
    resources:
      - globalratelimits

Конфигурирование для подключения с использованием NetworkPolicy#

Есть два варианта подключения к централизованному SRLS:

  • через NetworkPolicy;

  • через Egress.

Артефакт NetworkPolicy, приведенный в документе «Руководство по установке» в разделе «Сетевая видимость RL Service в рамках кластера», разрешает подключение из других namespace к Pod RL Service по порту 8081. В этом случае трафик не покидает сеть кластера Kubernetes (OpenShift опционально). Для обеспечения сетевой видимости необходимо наличие label srls: ratelimit у Pod Ingress Gateway и/или Egress Gateway, на которых выполняется квотирование. Его необходимо добавить в Deployment по пути .spec.template.metadata.labels, например:

kind: Deployment
apiVersion: apps/v1
metadata:
  name: ingress-gateway
  namespace: my-namespace
  labels:
    app: ingress-my-namespace
    istio: ingress-my-namespace
    proj: synapse-rls
    agent: srls
spec:
  replicas: 2
  selector:
    matchLabels:
      app: ingress-my-namespace
      istio: ingress-my-namespace
  template:
    metadata:
      creationTimestamp: null
      labels:
        app: ingress-my-namespace
        chart: gateways
        istio: ingress-my-namespace
        release: istio
        srls: ratelimit
      annotations:
        sidecar.istio.io/inject: 'false'
    spec:
      restartPolicy: Always

В артефакте GlobalRateLimit в поле rlserver следует указать значение rate-limiter-headless-service.${rls-namespace}.svc.cluster.local, где rls-namespace — namespace централизованного SRLS, в поле rlserverport следует указать 8081.

Настройка Egress Gateway (опционально)#

Трафик между namespace должен быть маршрутизирован через Egress namespace инициатора вызова в сторону Ingress Gateway целевого namespace через Router среды контейнеризации для обеспечения требований безопасности. Поэтому необходимо обеспечить маршрутизацию данного трафика средствами Istio. Трафик должен быть закрыт mTLS для выполнения требований безопасности.

  1. Добавить порт 12001 в Deployment вашего Egress Gateway.

В описании контейнера в блоке ports необходимо добавить:

- name: grpc-12001
  containerPort: 12001
  protocol: TCP

Название порта должно быть именно grpc-12001.

  1. Создать артефакт Service типа headless service (параметр clusterIP = None), указывающий на pod Egress Gateway. Добавить порт 12001 в артефакт Service вашего Egress Gateway.

В описании артефакта Service, который с помощью Selector указывает на pod Egress Gateway, необходимо добавить новый порт:

- name: grpc-12001
  protocol: TCP
  port: 12001
  targetPort: 12001

Название порта должно быть именно grpc-12001.

Рекомендуется использовать именно Headless Service для корректной балансировки нагрузки, в противном случае при перезапуске одного из pod Egress Gateway на pod Egress Gateway будет поступать минимальный трафик.

  1. Добавить артефакт Gateway.

Чтобы Egress Gateway начал слушать подключения к новому порту, необходимо добавить Istio артефакт Gateway:

apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
  name: egress-rate-limiter
  namespace: ${namespace}
spec:
  selector:
    app: ${app-selector-label}
  servers:
    - hosts:
        - '*'
      port:
        name: GRPC-12001
        number: 12001
        protocol: GRPC

Здесь:

  • ${namespace} необходимо заменить на идентификатор вашего namespace;

  • ${app-selector-label} необходимо заменить на значение лейбла pod Egress Gateway, помимо лейбла «app» могут быть использованы другие лейблы.

Название и протокол порта должны быть именно GRPC-12001 и GRPC.

  1. Добавить артефакт VirtualService.

Формируем правило маршрутизации с помощью артефакта Istio VirtualService:

apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: rls-virtual-service
  namespace: ${namespace}
spec:
  exportTo:
    - .
  gateways:
    - ${namespace}/egress-rate-limiter
  hosts:
    - '*'
  http:
    - match:
        - gateways:
            - ${namespace}/egress-rate-limiter
          port: 12001
      rewrite:
        authority: ${rate_limit_host_name}
      route:
        - destination:
            host: ${rate_limit_host_name}
            port:
              number: 443

Здесь:

  • ${namespace} необходимо заменить на идентификатор вашего namespace;

  • ${rate_limit_host_name} необходимо заменить на URL централизованного сервиса Rate Limit.

  1. Добавить артефакт ServiceEntry.

Для внешних ресурсов по отношению к Mesh необходимо создать артефакт ServiceEntry:

apiVersion: networking.istio.io/v1alpha3
kind: ServiceEntry
metadata:
  name: rate-limiter-se
  namespace: ${namespace}
spec:
  exportTo:
    - .
  hosts:
    - ${rate_limit_host_name}
  location: MESH_EXTERNAL
  ports:
    - name: http2
      number: 443
      protocol: http2
  resolution: DNS

Здесь:

  • ${namespace} необходимо заменить на идентификатор вашего namespace;

  • ${rate_limit_host_name} необходимо заменить на URL централизованного сервиса Rate Limit.

Название и протокол порта должны быть именно http2.

  1. Добавить артефакт DestinationRule.

Для формирования mTLS-соединения необходимо прописать сертификаты с помощью артефакта DestinationRule:

apiVersion: networking.istio.io/v1alpha3
kind: DestinationRule
metadata:
  name: mtls-rate-limiter
  namespace: ${namespace}
spec:
  exportTo:
    - .
  host: ${rate_limit_host_name}
  trafficPolicy:
    portLevelSettings:
      - connectionPool:
          http: {}
        port:
          number: 443
        tls:
          caCertificates: /etc/rls/egress/ca-root.pem
          clientCertificate: /etc/rls/egress/egress.pem
          mode: MUTUAL
          privateKey: /etc/rls/egress/egress.key
          sni: ${rate_limit_host_name}

Здесь:

  • ${namespace} необходимо заменить на идентификатор вашего namespace;

  • ${rate_limit_host_name} необходимо заменить на URL централизованного сервиса Rate Limit.

Также необходимо прописать актуальные пути и названия файлов с сертификатами и ключом. Здесь приведены значения для примера. Должны использоваться сертификаты, подписанные УЦ.

Конфигурирование артефактов среды контейнеризации и Istio для децентрализованного варианта развертывания#

Децентрализованный вариант развертывания позволяет выбрать, как будут созданы необходимые для работы артефакты EnvoyFilter: автоматизированно или вручную.

Для автоматизированного варианта требуется предоставление соответствующих прав компоненту RL Operator.
Подробное описание приведено в документе «Руководство по установке» в разделе «Ролевая модель децентрализованного варианта развертывания».
В зависимости от выбранной ролевой модели необходимо выставить корректное значение стендозависимого параметра disable_envoy_filter_automation.
Описание параметра приведено в документе «Руководство по установке» в разделе «Параметры установки».

Для корректного отключения механизма квотирования входящих запросов при выключенном автоматизированном управлении артефактами EnvoyFilter (значение стендозависимого параметра disable_envoy_filter_automation выставлено в true) необходимо удалить как артефакт GlobalRateLimit, так и артефакты EnvoyFilter, которые были созданы по инструкции из раздела «Создание артефактов EnvoyFilter вручную».

Ниже приведена инструкция по созданию артефактов EnvoyFilter вручную.

Создание артефактов EnvoyFilter вручную#

Виды артефактов EnvoyFilter:

  • Кластер — необходим для настройки параметров подключения к компоненту RL Service.

  • Rate Limit Header — необходим для формирования запросов к RL Service в режиме работы Rate Limit Header.

  • Rate Limit Prefix — необходим для формирования запросов к RL Service в режиме работы Rate Limit Prefix.

  • Rate Limit Path — необходим для формирования запросов к RL Service в режиме работы Rate Limit Path.

Минимальный набор артефактов включает в себя один Кластер и один артефакт для любого выбранного режима. Для каждого Endpoint, сконфигурированного в артефакте GlobalRateLimit, должен быть создан артефакт EnvoyFilter для соответствующего режима работы компонента SRLS. Допускается объединение всех артефактов EnvoyFilter в один yaml-файл.

Режимы работы описаны в разделе «Режимы работы» настоящего руководства.

Ниже приведены соответствующие артефакты EnvoyFilter для разных версий Envoy: 1.14+ и 1.17+.

  1. Кластер

Ниже приведены параметры для конфигурирования артефакта EnvoyFilter для вида Кластер:

Название параметра

Описание

Пример

namespace

Идентификатор пространства имен

my-namespace

labels

Список label для определения необходимого Ingress (Egress) Gateway

app: ingress-my-namespace

GrpcTimeout

Максимальное время ожидания ответа на запрос к компоненту RL Service

1s

RlServer

Адрес для подключения к компоненту RL Service

rate-limiter-headless-service.my-namespace.svc.cluster.local

RlServerPort

Порт для подключения к компоненту RL Service

8081

Cert

Путь к клиентскому сертификату

/etc/rls/ingress/ingress.pem

Key

Путь к приватному ключу сертификата

/etc/rls/ingress/ingress.key

TrustCA

Путь к доверительному сертификату

/etc/rls/ingress/ca-root.pem

Для версии 1.14+ без закрытия соединения TLS:

apiVersion: networking.istio.io/v1alpha3
kind: EnvoyFilter
metadata:
  name: ${namespace}-rls-cluster
  namespace: ${namespace}
  labels:
    srls: srls
spec:
  workloadSelector:
    labels: 
      ${labels}
  configPatches:
    - applyTo: HTTP_FILTER
      match:
        context: GATEWAY
        listener:
          filterChain:
            filter:
              name: "envoy.http_connection_manager"
              subFilter:
                name: "envoy.router"
      patch:
        operation: INSERT_BEFORE
        value:
          name: envoy.rate_limit
          config:
            domain: ${namespace}
            failure_mode_deny: false
            rate_limit_service:
              grpc_service:
                envoy_grpc:
                  cluster_name: rate_limit_cluster
                timeout: 10s
            timeout: ${GrpcTimeout}
    - applyTo: CLUSTER
      match:
        cluster:
          service: ${RlServer}
      patch:
        operation: ADD
        value:
          name: rate_limit_cluster
          type: STRICT_DNS
          connect_timeout: 10s
          lb_policy: ROUND_ROBIN
          http2_protocol_options: {}
          load_assignment:
            cluster_name: rate_limit_cluster
            endpoints:
            - lb_endpoints:
              - endpoint:
                  address:
                    socket_address:
                      address: ${RlServer}
                      port_value: ${RlServerPort}

Для версии 1.14+ c закрытием соединения TLS при прямом подключении:

apiVersion: networking.istio.io/v1alpha3
kind: EnvoyFilter
metadata:
  name: ${namespace}-rls-cluster
  namespace: ${namespace}
  labels:
    srls: srls
spec:
  workloadSelector:
    labels:
      ${labels}
  configPatches:
    - applyTo: HTTP_FILTER
      match:
        context: GATEWAY
        listener:
          filterChain:
            filter:
              name: "envoy.http_connection_manager"
              subFilter:
                name: "envoy.router"
      patch:
        operation: INSERT_BEFORE
        value:
          name: envoy.rate_limit
          config:
            domain: ${namespace}
            failure_mode_deny: false
            rate_limit_service:
              grpc_service:
                envoy_grpc:
                  cluster_name: rate_limit_cluster
                timeout: 10s
            timeout: ${GrpcTimeout}
    - applyTo: CLUSTER
      match:
        cluster:
          service: ${RlServer}
      patch:
        operation: ADD
        value:
          name: rate_limit_cluster
          type: STRICT_DNS
          connect_timeout: 10s
          lb_policy: ROUND_ROBIN
          http2_protocol_options: {}
          load_assignment:
            cluster_name: rate_limit_cluster
            endpoints:
              - lb_endpoints:
                  - endpoint:
                      address:
                        socket_address:
                          address: ${RlServer}
                          port_value: ${RlServerPort}
          transport_socket:
            name: envoy.transport_sockets.tls
            typed_config:
              "@type": type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.UpstreamTlsContext
              sni: ${RlServer}
              common_tls_context:
                tls_certificates:
                  - certificate_chain: 
                      filename: "${Cert}"
                    private_key: 
                      filename: "${Key}"
                validation_context:
                    trusted_ca:
                      filename: ${TrustCA}

Для версии 1.17+ без закрытия соединения TLS:

apiVersion: networking.istio.io/v1alpha3
kind: EnvoyFilter
metadata:
  name: ${namespace}-rls-cluster
  namespace: ${namespace}
  labels:
    srls: srls
spec:
  workloadSelector:
    labels: 
      ${labels}
  configPatches:
    - applyTo: HTTP_FILTER
      match:
        context: GATEWAY
        listener:
          filterChain:
            filter:
              name: "envoy.filters.network.http_connection_manager"
              subFilter:
                name: "envoy.filters.http.router"
      patch:
        operation: INSERT_BEFORE
        value:
          name: envoy.filters.http.ratelimit
          typed_config:
            "@type": type.googleapis.com/envoy.extensions.filters.http.ratelimit.v3.RateLimit
            domain: ${namespace}
            failure_mode_deny: false
            rate_limit_service:
              grpc_service:
                envoy_grpc:
                  cluster_name: rate_limit_cluster
                timeout: 10s
              transport_api_version: V3
            timeout: ${GrpcTimeout}
    - applyTo: CLUSTER
      match:
        cluster:
          service: ${RlServer}
      patch:
        operation: ADD
        value:
          name: rate_limit_cluster
          type: STRICT_DNS
          connect_timeout: 10s
          lb_policy: ROUND_ROBIN
          http2_protocol_options: {}
          load_assignment:
            cluster_name: rate_limit_cluster
            endpoints:
            - lb_endpoints:
              - endpoint:
                  address:
                    socket_address:
                      address: ${RlServer}
                      port_value: ${RlServerPort}

Для версии 1.17+ с закрытием соединения TLS при прямом подключении:

apiVersion: networking.istio.io/v1alpha3
kind: EnvoyFilter
metadata:
  name: ${namespace}-rls-cluster
  namespace: ${namespace}
  labels:
    srls: srls
spec:
  workloadSelector:
    labels: 
      ${labels}
  configPatches:
    - applyTo: HTTP_FILTER
      match:
        context: GATEWAY
        listener:
          filterChain:
            filter:
              name: "envoy.filters.network.http_connection_manager"
              subFilter:
                name: "envoy.filters.http.router"
      patch:
        operation: INSERT_BEFORE
        value:
          name: envoy.filters.http.ratelimit
          typed_config:
            "@type": type.googleapis.com/envoy.extensions.filters.http.ratelimit.v3.RateLimit
            domain: ${namespace}
            failure_mode_deny: false
            rate_limit_service:
              grpc_service:
                envoy_grpc:
                  cluster_name: rate_limit_cluster
                timeout: 10s
              transport_api_version: V3
            timeout: ${GrpcTimeout}
    - applyTo: CLUSTER
      match:
        cluster:
          service: ${RlServer}
      patch:
        operation: ADD
        value:
          name: rate_limit_cluster
          type: STRICT_DNS
          connect_timeout: 10s
          lb_policy: ROUND_ROBIN
          http2_protocol_options: {}
          load_assignment:
            cluster_name: rate_limit_cluster
            endpoints:
            - lb_endpoints:
              - endpoint:
                  address:
                    socket_address:
                      address: ${RlServer}
                      port_value: ${RlServerPort}
          transport_socket:
            name: envoy.transport_sockets.tls
            typed_config:
              "@type": type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.UpstreamTlsContext
              sni: ${RlServer}
              common_tls_context:
                tls_certificates:
                  - certificate_chain:
                      filename: "${Cert}"
                    private_key:
                      filename: "${Key}"
                validation_context:
                  trusted_ca:
                    filename: ${TrustCA}
  1. Rate Limit Header

Ниже приведены параметры для конфигурирования артефакта EnvoyFilter для вида Rate Limit Header:

Название параметра

Описание

Пример

namespace

Идентификатор пространства имен

my-namespace

labels

Список label для определения необходимого Ingress (Egress) Gateway

app: ingress-my-namespace

Endpoint

Точка подключения входящего трафика

my-server-my-namespace.domain.ru:8080

Shortname

Уникальное короткое название точки подключения

myserver

Header

Название заголовка для определения потребителя

synapse-consumerid

Опциональный блок

Если в конфигурации GlobalRateLimit для данной точки подключения указано значение поля overall_limit отличное от -1, необходимо добавить данный опциональный блок

Для версии 1.14+:

apiVersion: networking.istio.io/v1alpha3
kind: EnvoyFilter
metadata:
  name: ${namespace}-${Shortname}
  namespace: ${namespace}
  labels:
    srls: srls
spec:
  workloadSelector:
    labels:
      ${labels}
  configPatches:
    - applyTo: VIRTUAL_HOST
      match:
        context: GATEWAY
        routeConfiguration:
          vhost:
            name: ${Endpoint}
            route:
              action: ANY
      patch:
        operation: MERGE
        value:
          rate_limits:
// Опциональный блок
            - actions:
                - generic_key:
                    descriptor_value: ${Shortname}.over
// Конец опционального блока
            - actions:
                - generic_key:
                    descriptor_value: ${Shortname}
                - header_value_match:
                    descriptor_value: header-absent
                    headers:
                      - name: ${Header}
                        present_match: true
                        invert_match: true
            - actions:
                - generic_key:
                    descriptor_value: ${Shortname}    
                - request_headers:
                    header_name: ${Header}
                    descriptor_key: ${Shortname}.${Header}

Для версии 1.17+:

apiVersion: networking.istio.io/v1alpha3
kind: EnvoyFilter
metadata:
  name: ${namespace}-${Shortname}
  namespace: ${namespace}
  labels:
    srls: srls
spec:
  workloadSelector:
    labels:
      ${labels}
  configPatches:
    - applyTo: VIRTUAL_HOST
      match:
        context: GATEWAY
        routeConfiguration:
          vhost:
            name: ${Endpoint}
            route:
              action: ANY
      patch:
        operation: MERGE
        value:
          rate_limits:
// Опциональный блок
            - actions:
                - generic_key:
                    descriptor_key: endpoint
                    descriptor_value: ${Shortname}.over
// Конец опционального блока
            - actions:
                - generic_key:
                    descriptor_key: endpoint
                    descriptor_value: ${Shortname}    
                - request_headers:
                    header_name: ${Header}
                    descriptor_key: ${Shortname}.${Header}
                    skip_if_absent: true
  1. Rate Limit Prefix

Ниже приведены параметры для конфигурирования артефакта EnvoyFilter для вида Rate Limit Prefix:

Название параметра

Описание

Пример

namespace

Идентификатор пространства имен

my-namespace

labels

Список label для определения необходимого Ingress (Egress) Gateway

app: ingress-my-namespace

Endpoint

Точка подключения входящего трафика

my-server-my-namespace.domain.ru:8080

Shortname

Уникальное короткое название точки подключения

myserver

Header

Название заголовка для определения потребителя

synapse-consumerid

Опциональный блок

Если в конфигурации GlobalRateLimit для данной точки подключения указано значение поля overall_limit отличное от -1, необходимо добавить данный опциональный блок

Для версии 1.14+:

apiVersion: networking.istio.io/v1alpha3
kind: EnvoyFilter
metadata:
  name: ${namespace}-${Shortname}
  namespace: ${namespace}
  labels:
    srls: srls
spec:
  workloadSelector:
    labels:
      ${labels}
  configPatches:
    - applyTo: VIRTUAL_HOST
      match:
        context: GATEWAY
        routeConfiguration:
          vhost:
            name: ${Endpoint}
            route:
              action: ANY
      patch:
        operation: MERGE
        value:
          rate_limits:
// Опциональный блок
            - actions:
                - generic_key:
                    descriptor_value: ${Shortname}.over
// Конец опционального блока
            - actions:
                - generic_key:
                    descriptor_value: ${Shortname}
                - request_headers:
                    header_name: ":path"
                    descriptor_key: ${Shortname}.prefix
                - header_value_match:
                    descriptor_value: header-absent
                    headers:
                      - name: ${Header}
                        present_match: true
                        invert_match: true
            - actions:
                - generic_key:
                    descriptor_value: ${Shortname}   
                - request_headers:
                    header_name: ":path"
                    descriptor_key: ${Shortname}.prefix
                - request_headers:
                    header_name: ${Header}
                    descriptor_key: ${Shortname}.${Header}

Для версии 1.17+:

apiVersion: networking.istio.io/v1alpha3
kind: EnvoyFilter
metadata:
  name: ${namespace}-${Shortname}
  namespace: ${namespace}
  labels:
    srls: srls
spec:
  workloadSelector:
    labels:
      ${labels}
  configPatches:
    - applyTo: VIRTUAL_HOST
      match:
        context: GATEWAY
        routeConfiguration:
          vhost:
            name: ${Endpoint}
            route:
              action: ANY
      patch:
        operation: MERGE
        value:
          rate_limits:
// Опциональный блок
            - actions:
                - generic_key:
                    descriptor_key: endpoint
                    descriptor_value: ${Shortname}.over
// Конец опционального блока
            - actions:
                - generic_key:
                    descriptor_key: endpoint
                    descriptor_value: ${Shortname} 
                - request_headers:
                    header_name: ":path"
                    descriptor_key: ${Shortname}.prefix
                - request_headers:
                    header_name: ${Header}
                    descriptor_key: ${Shortname}.${Header}
                    skip_if_absent: true
  1. Rate Limit Path

Ниже приведены параметры для конфигурирования артефакта EnvoyFilter для вида Rate Limit Prefix:

Название параметра

Описание

Пример

namespace

Идентификатор пространства имен

my-namespace

labels

Список label для определения необходимого Ingress (Egress) Gateway

app: ingress-my-namespace

Endpoint

Точка подключения входящего трафика

my-server-my-namespace.domain.ru:8080

Shortname

Уникальное короткое название точки подключения

myserver

Опциональный блок

Если в конфигурации GlobalRateLimit для данной точки подключения указано значение поля overall_limit отличное от -1, необходимо добавить данный опциональный блок

Для версии 1.14+:

apiVersion: networking.istio.io/v1alpha3
kind: EnvoyFilter
metadata:
  name: ${namespace}-${Shortname}
  namespace: ${namespace}
  labels:
    srls: srls
spec:
  workloadSelector:
    labels:
      ${labels}
  configPatches:
    - applyTo: VIRTUAL_HOST
      match:
        context: GATEWAY
        routeConfiguration:
          vhost:
            name: ${Endpoint}
            route:
              action: ANY
      patch:
        operation: MERGE
        value:
          rate_limits:
// Опциональный блок
            - actions:
                - generic_key:
                    descriptor_value: ${Shortname}.over
// Конец опционального блока
            - actions:
                - generic_key:
                    descriptor_value: ${Shortname}    
                - request_headers:
                    header_name: ":path"
                    descriptor_key: ${Shortname}.path

Для версии 1.17+:

apiVersion: networking.istio.io/v1alpha3
kind: EnvoyFilter
metadata:
  name: ${namespace}-${Shortname}
  namespace: ${namespace}
  labels:
    srls: srls
spec:
  workloadSelector:
    labels:
      ${labels}
  configPatches:
    - applyTo: VIRTUAL_HOST
      match:
        context: GATEWAY
        routeConfiguration:
          vhost:
            name: ${Endpoint}
            route:
              action: ANY
      patch:
        operation: MERGE
        value:
          rate_limits:
// Опциональный блок
            - actions:
                - generic_key:
                    descriptor_key: endpoint
                    descriptor_value: ${Shortname}.over
// Конец опционального блока
            - actions:
                - generic_key:
                    descriptor_key: endpoint
                    descriptor_value: ${Shortname}    
                - request_headers:
                    header_name: ":path"
                    descriptor_key: ${Shortname}.path
                    skip_if_absent: true

Добавление HTTP-заголовка в запрос на стороне потребителя без доработки кода (опционально)#

Данный заголовок должен формировать клиент (потребитель сервиса). Если клиент развернут в Red Hat OpenShift (опционально) и использует функционал Red Hat Service Mesh, то заголовок можно проставить на Egress Gateway namespace клиента с помощью артефакта VirtualService и блока headers, например:

apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: rldemo-server-vs
  namespace: synapse-dev-sandbox
spec:
  exportTo:
    - .
  gateways:
    - rldemo-istio-egressgateway
  hosts:
    - rldemoserver.synapse-dev-sandbox3.apps.syn-sb.local.host.ru
  http:
    - headers:
        request:
          set:
            synapse-consumerid: synapse-dev-sandbox
      match:
        - gateways:
            - rldemo-istio-egressgateway
          port: 8081
      route:
        - destination:
            host: rldemoserver.synapse-dev-sandbox3.apps.syn-sb.local.host.ru
            port:
              number: 80

Миграция на текущую версию#

Миграция на текущую версию происходит путем установки программного компонента Synapse Rate Limit, которая описана в разделе «Установка» документа «Руководство по установке».

Быстрый старт#

Ниже приведены шаги для децентрализованного варианта развертывания компонента SRLS.

  1. При настроенном Deploy Tools выполнить установку в прикладной namespace, действия описаны в подразделе «Автоматизированная установка сервиса с использованием Deploy Tools» документа «Руководство по установке».

  2. Добавить артефакт GlobalRateLimit в прикладной namespace. Пример для тестового сервиса Server-Test:

kind: GlobalRateLimit
apiVersion: ratelimit.service/v1alpha1
metadata:
  name: rate-limit-config
  namespace: ${namespace}
spec:
  envoyVersion: '1.14'
  workloadSelector:
    labels:
      istio: ingressgateway
  rlserver: rate-limiter-headless-service.${namespace}.svc.cluster.local
  rlserverport: 8081
  endpoints:
  - endpoint: test-server-${namespace}.${cluster_domain_name}:8080  # вызываемый сервис
    name: "some service"                                            # описание сервиса
    shortname: "server"                                             # краткое название сервиса (3-10 латинских букв в нижнем регистре)
    by_header:
      header: synapse-consumerid                                    # на текущий момент единственно возможный вариант
      unit: second                                                  # возможные значения: second, minute, hour, day
      value: 7                                                      # применяется для всех клиентов, не указанных в invokers
      visibility: namespace                                         # на текущий момент единственно возможный вариант
      invokers:
        - name: "header_client1"
          header_value: "client1"
          unit: minute                                              # возможные значения: second, minute, hour, day
          value: 5
        - name: "header_client2"
          header_value: "client2"
          unit: second                                              # возможные значения: second, minute, hour, day
          value: 2
  1. Тестирование работы SRLS.

  • Перед тестированием убедитесь, что в namespace:

    1. все pod поднялись;

    2. фильтры EnvoyFiltеr для сервиса (в примере Server-Test) создались;

    3. выполняется переход по ссылке в pod Ingress Gateway.

  • Добавьте ресурс kind: GlobalRateLimit name: rate-limit-config из пункта выше, заменив параметры ${namespace} и ${cluster_domain_name}.

  • C помощью утилиты Curl выполните запрос к тестовому сервису в консоли рабочей станции:

curl -v -H 'synapse-consumerid: client1'  test-server-${rls_namespace}.${cluster_domain_name} 2>&1 | grep HTTP

Здесь client1 — метка клиента (invokers) для ресурса test-server-${rls_namespace}.${cluster_domain_name}:8080, заданного в ресурсе GlobalRateLimit.

  • Выполните N запросов от трёх различных пользователей: client1, client2, client3. Убедитесь, что ограничения по каждому пользователю соответствуют указанным в настройках в ресурсе GlobalRateLimit.

При корректно выполненной настройке должен прийти ответ вида:

> GET / HTTP/1.1
< HTTP/1.1 200 OK

Согласно выставленным ограничениям для client1 (5 запросов в минуту), выполним 7 запросов к ресурсу:

for run in {1..7}; do  curl -v -H 'synapse-consumerid: client1'  test-server-${rls_namespace}.${cluster_domain_name} 2>&1 | grep HTTP; done

Ответ:

> GET / HTTP/1.1
< HTTP/1.1 200 OK
> GET / HTTP/1.1
< HTTP/1.1 200 OK
> GET / HTTP/1.1
< HTTP/1.1 200 OK
> GET / HTTP/1.1
< HTTP/1.1 200 OK
> GET / HTTP/1.1
< HTTP/1.1 200 OK
> GET / HTTP/1.1
< HTTP/1.1 429 Too Many Requests
> GET / HTTP/1.1
< HTTP/1.1 429 Too Many Requests

Выполнив повторно запрос до истечения заданного в настройках интервала (5 запросов в минуту для пользователя client1), можно убедиться, что запросы будут возвращать 429 ошибку. Это ожидаемое поведение.

Использование программного компонента#

Обращения к сервису Rate Limit формирует либо Ingress Gateway в прикладном namespace, доступ к ресурсам которого (namespace) необходимо ограничить, либо Egress Gateway в namespace, из которого делается вызов. Конфигурирование лимитов осуществляется через формирование артефакта GlobalRateLimit. Централизованный сервис Rate Limit разворачивается свой в каждом физическом кластере Kubernetes или Red Hat OpenShift (опционально).

Для возможности загрузки артефакта GlobalRateLimit необходимо создать роль K8s и привязать к ней ТУЗ Jenkins в namespace.

Роль:

kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: pipeline-rate-limiter-service-role
rules:
  - verbs:
      - create
      - update
      - patch
      - delete
      - get
      - list
    apiGroups:
      - ratelimit.service
    resources:
      - globalratelimits

Формирование и применение артефакта GlobalRateLimit#

Конфигурирование лимитов осуществляется через артефакт GlobalRateLimit. Для применения лимитов необходимо создать артефакт GlobalRateLimit в namespace, где запущены прикладные сервисы, которые указаны в секции endpoints.

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

apiVersion: ratelimit.service/v1alpha1
kind: GlobalRateLimit
metadata:
  name: rate-limit-config
  namespace: my-namespace
spec:
  endpoints:
  - endpoint: 'test-server2-endpoint.apps.stands-vdc01.solution.sbt:8080'
    name: some service1
    shortname: fserver
    overall_limit: 70
    by_header:
      header: synapse-consumerid
      unit: second
      anon_value: 3
      value: 7
      invokers:
      - header_value: synapse-dev-sandbox
        name: client from synapse-dev-sandbox namespace
        unit: second
        value: 5
      - header_value: kordon1
        name: client from kordon1 namespace
        unit: second
        value: 2
  - endpoint: 'test-server3-endpoint.apps.stands-vdc01.solution.sbt:8080'
    name: some service2
    shortname: sserver
    overall_limit: 70
    by_path:
      mask: 'rn/*:*:_'
      unit: second
      quotas:
        soft:
          value: 10
          step: 1
        flat: 15
      tenants:
      - name: server1.path
        resourceName: account-1project-1
        unit: second
        quotas:
          flat: 7
      - name: server2.path
        resourceName: account-2project-2
        unit: second
        quotas:
          soft:
            value: 5
            step: 1
          flat: 10
  - endpoint: 'test-server4-endpoint.apps.stands-vdc01.solution.sbt:8080'
    name: srls dev 02
    shortname: dev
    overall_limit: 100
    overall_schedule:
       start:
          second: '10'
          minute: '*'
          hour: '*'
          day: '*'
          month: '*'
          weekday: '*'
       stop:
          second: '30'
          minute: '*'
          hour: '*'
          day: '*'
          month: '*'
          weekday: '*'
       unit: minute
       value: 50
    by_header:
      header: synapse-consumerid
      uri_prefixes:
        - uri_prefix: "/foo"
          unit: minute
          value: 7
          anon_value: 3
          invokers:
            - header_value: foo-client
              name: client 1
              unit: minute
              value: 5
        - uri_prefix: "/bar"
          unit: minute
          value: 20
          anon_value: 2
          invokers:
            - header_value: bar-client
              name: client 2
              unit: minute
              value: 2
        - uri_prefix: "/foo/bar"
          unit: minute
          value: 13
          anon_value: 4
          invokers:
            - header_value: foo-bar-client
              name: client 3
              unit: minute
              value: 6
  - endpoint: 'test-server1-endpoint.apps.stands-vdc01.solution.sbt:8080'
    name: some service
    shortname: server
    header: synapse-consumerid
    unit: second
    value: 7
    invokers:
      - name: client1
        header_value: synapse-dev-sandbox
        unit: second
        value: 5
      - name: client2
        header_value: kordon1
        unit: second
        value: 2
  rlserver: egress-gateway-headless.my-namespace.svc.cluster.local
  rlserverport: 12001
  rlnamespace: rlservice-ns
  rlservercert:
    cert: /etc/rls/ingress/ingress.pem
    key: /etc/rls/ingress/ingress.key
    trust_ca: /etc/rls/ingress/ca-root.pem
  workloadSelector:
    labels:
      app: ingress-my-namespace
      istio: ingress-my-namespace
  visibility: cluster
  envoyVersion: '1.14'

В примере для endpoint указаны три способа задания лимитов:

  • первый вариант (test-server1) — для обратной совместимости с версией RLS 2.0, нет возможности использовать произвольный заголовок для идентификации потребителя, нет возможности указать раздельно лимит для безымянных потребителей (отсутствует указанный заголовок в запросе) и неуказанных в конфигурации;

  • второй вариант (test-server2) — применение лимитов с идентификацией потребителя в заголовке, можно указать произвольный заголовок (валидный для протокола HTTP) и раздельно указать лимиты для безымянных потребителей (отсутствует указанный заголовок в запросе) и неуказанных в конфигурации, для этого введено новое поле anon_value;

  • третий вариант (test-server3) — применение лимитов в разрезе ResourceName, новый функционал, появившийся в релизе 2.1, для идентификации потребителя (тенанта) из URL-запроса;

  • четвертый вариант (test-server4) — применение лимитов с идентификацией потребителя в заголовке, отличие от второго варианта — лимиты конфигурируются для каждого указанного префикса URL в рамках одного endpoint независимо (с релиза 2.4 префиксы /foo и /foo/bar являются независимыми с точки зрения Rate Limiter - запросы /foo/test1?param1=value1 и /foo/bar/test2 будут задействовать свои лимиты независимо друг от друга).

При формировании артефакта необходимо указать:

  • workloadSelector — набор labels для определения нужных pod Ingress (Egress) Gateway;

  • visibility — отвечает за область видимости данного CRD, возможные значения: cluster, namespace;

  • envoyVersion — отвечает за наполнение артефакта EnvoyFilter в зависимости от используемой версии Envoy, значение по умолчанию — '1.14';

  • endpoints — список ваших ресурсов;

  • rlserver — адрес RLS-сервера (для децентрализованной установки следует указать headless server rls например: «rate-limiter-headless-service», для централизованной установки здесь следует указать сервис Egress Gateway вашего namespace, рекомендованный формат — <headless_service_name>.<namespace>.svc.cluster.local);

  • rlserverport — порт RLS-сервера, по умолчанию — 12001, если не задан (для децентрализованной установки — 8081, для централизованной установки — 12001);

  • rlnamespace — namespace, в котором развернут централизованный оператор, данное поле необходимо указать для возможности развертывания нескольких экземпляров централизованного SRLS в рамках одного кластера Kubernetes или Red Hat OpenShift (опционально), если данное поле не задано, оператор проверит наличие прав на артефакт EnvoyFilter в прикладном namespace;

  • rlservercert — опциональный блок, позволяет задавать сертификаты для доступа к RLS-серверу при прямом подключении.

rlservercert состоит из следующих полей:

  • cert – путь к клиентскому (extendedKeyUsage = clientAuth) сертификату в файловой системе Ingress (Egress) Gateway;

  • key – путь к приватному ключу сертификата в файловой системе Ingress (Egress) Gateway;

  • trust_ca — путь к доверительному сертификату в файловой системе Ingress (Egress) Gateway.

Важно!

Потребитель сам должен обеспечить наличие данных сертификатов на Ingress (Egress) Gateway, подмонтировав их в необходимую директорию.

Для каждого endpoint:

  • обязательно наличие его короткого имени shortname, используется в работе, для каждого endpoint значение shortname должно быть уникальным;

  • endpoint — целевой адрес в формате host:port, здесь host — DNS адрес, на который поступает входящий трафик (определяется в артефакте Route, используется в артефактах Gateway, VirtualService для манипуляции трафиком с помощью Service Mesh), port — порт, который слушает Ingress (Egress) Gateway (задается в артефакте Gateway), например, 8080 для HTTP трафика или 8443 для HTTPS трафика;

  • overall_limit — максимальное ограничение квоты для endpoint; 0 — блокировка всех запросов, отрицательное значение — нет ограничения; если значение больше 0, дополнительно создается отдельный счетчик всех запросов на endpoint; в случае превышения запрос будет отклонен, даже если потребитель еще не исчерпал свою квоту; если используется режим работы Rate Limit Prefix, overall_limit считается общий для всех префиксов URL-запроса, указанных в конфигурации;

  • by_header — список настроек для функционала идентификации потребителя по HTTP-заголовку (подробное описание приведено в разделах «Rate Limit Header» и «Rate Limit Prefix» настоящего руководства);

  • by_path — список настроек для функционала идентификации потребителя по resourceName (подробное описание приведено в разделе «Rate Limit Path» настоящего руководства);

  • может быть задан лишь один из типов лимитов «by_header» или «by_path»;

  • overall_schedule – опциональный блок, позволяет изменять overall_limit по расписанию;

  • schedule – опциональный блок, позволяет изменять лимиты по расписанию.

Лимиты могут быть заданы в следующих единицах измерения:

  • second;

  • minute;

  • hour;

  • day.

Режимы работы#

Rate Limit Header#

Данный режим работы используется при задании лимитов с идентификацией потребителя по значению HTTP-заголовка. Если HTTP-заголовок отсутствует в запросе, идентифицировать пользователя невозможно, для таких запросов используется общая квота анонимных вызовов, определенная полем anon_value. Для конфигурирования используйте специальный блок полей by_header.

Пример:

  - endpoint: 'test-server-endpoint.apps.domain.org:8080'
    name: some service1
    shortname: fserver
    overall_limit: 70
    by_header:
      header: synapse-consumerid
      unit: minute
      anon_value: 3
      value: 5
      soft:
        value: 2
        step: 1
      invokers:
      - header_value: synapse-dev-sandbox
        name: client from synapse-dev-sandbox namespace
        unit: second
        value: 7
        soft:
          value: 3
          step: 1
      - header_value: kordon1
        name: client from kordon1 namespace
        unit: second
        value: 2
  - endpoint: 'test-endpoint.apps.domain.org:8080'
    name: some service2
    shortname: fserver2
    overall_limit: 50
    overall_schedule:
       start:
          second: '10'
          minute: '*'
          hour: '*'
          day: '*'
          month: '*'
          weekday: '*'
       stop:
          second: '30'
          minute: '*'
          hour: '*'
          day: '*'
          month: '*'
          weekday: '*'
       unit: minute
       value: 25
    by_header:
      header: synapse-consumerid
      unit: minute
      anon_value: 3
      value: 5
      soft:
        value: 2
        step: 1
      invokers:
      - header_value: synapse-test
        name: client from synapse-test namespace
        unit: second
        value: 8
        soft:
          value: 3
          step: 1
        schedule:
          start:
             second: '1'
             minute: '5'
             hour: '2'
             day: '*'
             month: '*'
             weekday: '1'
          stop:
             second: '30'
             minute: '10'
             hour: '6'
             day: '*'
             month: '*'
             weekday: '1'
          unit: second
          value: 16
          soft:
            value: 5
            step: 2

Параметры блока by_header:

  • header — произвольный http-заголовок (валидный для протокола HTTP);

  • unit — опциональное поле, по умолчанию second, единица измерения лимитов, используется при расчете overall_limit, для запросов со значениями заголовка header, не указанными в блоке invokers, и для неидентифицированных потребителей;

  • anon_value — опциональное поле, позволяет задать квоту для неидентифицированных (анонимных) потребителей, то есть в запросе отсутствует выбранный HTTP-заголовок; если поле не задано, используется значение поля value;

  • value — опциональное поле, по умолчанию 1, позволяет задать квоту для запросов со значениями заголовка header, неуказанными в блоке invokers, и для неидентифицированных потребителей;

  • soft — опциональный блок, если задан, создается метрика, показывающая приближение к лимиту. soft.value — значение квоты, после которой с шагом кратным soft.step будет инкрементирована метрика мониторинга превышения уровня soft квоты для конкретного потребителя вплоть до превышения основного лимита;

  • invokers — опциональный блок, позволяет задать квоту для определенных потребителей независимо;

  • overall_schedule – опциональный блок, позволяет изменять overall_limit по расписанию.

overall_schedule и schedule состоят из следующих полей:

  • start – блок, позволяет задать время и дату начала изменения параметров, указанных в блоке;

  • stop – блок, позволяет задать время и дату окончания изменения параметров, указанных в блоке;

  • unit — поле, по умолчанию second, единица измерения лимитов;

  • value — поле, по умолчанию 1, позволяет задать квоту;

  • soft — опциональный блок, если задан, создается метрика, показывающая приближение к лимиту. soft.value — значение квоты, после которой с шагом кратным soft.step будет инкрементирована метрика мониторинга превышения уровня soft квоты для конкретного потребителя вплоть до превышения основного лимита.

start и stop состоят из следующих полей:

  • second – блок, секунды, возможные значения – (0-59);

  • minute – блок, минуты, возможные значения – (0-59);

  • hour – блок, часы, возможные значения – (0-23);

  • day – блок, дни, возможные значения – (1-31);

  • month – блок, месяц, возможные значения – (1-12, где 1-январь);

  • weekday – блок, дни недели, возможные значения – (0-6, где 0-воскресенье).

Значение '*' для полей start и stop является допустимым и позволяет задать любую минуту, час, день, месяц, день недели.

Например:

overall_schedule в примере выше означает, что overall_limit 50 запросов в секунду будет изменен в период с 10 секунды до 30 секунды каждой минуты каждого часа каждого дня каждого месяца в течении всей недели на overall_limit 25 запросов в минуту.

Second

Minute

Hour

Day

Month

Weekday

Примечание

start

'1'

'*'

'*'

'*'

'*'

'*'

Начало каждую 1 секунду

stop

'10'

'*'

'*'

'*'

'*'

'*'

Окончание каждую 10 секунду

start

'1'

'5'

'3'

'*'

'*'

'*'

Начало каждый день в 3:05:01

stop

'10'

'20'

'6'

'*'

'*'

'*'

Окончание каждый день в 6:20:10

start

'1'

'5'

'3'

'5'

'*'

'*'

Начало каждый день в 3:05:01

stop

'10'

'20'

'6'

'7'

'*'

'*'

Окончание каждый день в 6:20:10

start

'1'

'5'

'3'

'5'

'*'

'*'

Начало 5 числа каждого месяца в 3:05:01

stop

'10'

'20'

'6'

'7'

'*'

'*'

Окончание 7 числа каждого месяца в 6:20:10

start

'1'

'5'

'3'

'5'

'11'

'*'

Начало 5 ноября в 3:05:01

stop

'10'

'20'

'6'

'7'

'11'

'*'

Окончание 7 ноября в 6:20:10

start

'1'

'5'

'3'

'*'

'*'

'1'

Начало каждый понедельник в 3:05:01

stop

'10'

'20'

'6'

'*'

'*'

'1'

Окончание каждый понедельник в 6:20:10

  • Данные в scheduler блоки start и stop должны удовлетворять следующим требованиям:

  1. start не должен срабатывать несколько раз до наступления события stop;

  2. stop не должен срабатывать несколько раз до наступления события start;

  3. start и stop не может быть задан в несуществующую дату, например, в сентябре нет 31 дня, в феврале нет 29 дня и подобные.

  • В случае установки некорректных параметров в CRD GlobalRateLimit в блоке scheduler или overall_schedule, в статусе CRD будет отражено место с указанием, где задан невалидный интервал времени и даты.

Scheduler в поле invokers: header_value: synapse-test означает, что лимит 8 запросов в секунду с soft.value=3 и soft.step=1 будет изменен каждый понедельник в период с 2 часов 5 минут 1 секунды до 6 часов 10 минут 30 секунд на 16 запросов в секунду с soft.value=5 и soft.step=2.

Для каждого invoker можно задать:

  • header_value — значение заголовка, указанного в поле header;

  • name — опциональное поле, позволяет указать метаданные для header_value;

  • unit — опциональное поле, по умолчанию second, единица измерения лимитов для header_value;

  • value — опциональное поле, по умолчанию 1, позволяет задать квоту для запросов со значением заголовка header, равным header_value;

  • soft — опциональный блок, если задан, создается метрика, показывающая приближение к лимиту. soft.value — значение квоты, после которой с шагом кратным soft.step будет инкрементирована метрика мониторинга превышения уровня soft квоты для header_value вплоть до превышения основного лимита;

  • schedule – опциональный блок, позволяет изменять лимиты по расписанию.

Rate Limit Prefix#

Данный режим является расширением режима Rate Limit Header. Применяется в случаях, когда средствами Service Mesh входящий трафик на endpoint на Ingress Gateway распределяется по сервисам этого namespace на основе префикса URL-запроса.

Для настройки распределения трафика в Service Mesh используется артефакт VirtualService.

Пример:

  exportTo:
    - .
  gateways:
    - my-namespace-02/ingress-gateway
  hosts:
    - ingress-my-namespace-02.apps.domain.org
  http:
    - match:
        - uri:
            prefix: /foo
      route:
        - destination:
            host: fooserv.my-namespace-02.svc.cluster.local
            port:
              number: 8080
    - match:
        - uri:
            prefix: /bar
      route:
        - destination:
            host: barserv.my-namespace-02.svc.cluster.local
            port:
              number: 8080
    - match:
        - uri:
            prefix: /foo/bar
      route:
        - destination:
            host: fooserv.my-namespace-02.svc.cluster.local
            port:
              number: 8080

Для того чтобы для каждого префикса указать собственные значения квоты, в артефакте GlobalRateLimit в разделе by_header необходимо поле header и блок параметров uri_prefixes, в котором необходимо указать префикс в поле uri_prefix и лимиты по аналогии с режимом by-header.
Для работы функционала overall_limit необходимо указать поле unit, по умолчанию, если поле не задано, overall_limit будет рассчитываться в секундах. Счетчик overall_limit общий для всех префиксов. Остальные поля блока by_header будут проигнорированы.

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

    - endpoint: 'ingress-my-namespace-02.apps.domain.org:8080'
      name: srls dev 02
      shortname: dev
      overall_limit: 100
      by_header:
        header: synapse-consumerid
        unit: minute
        uri_prefixes:
          - uri_prefix: "/foo"
            unit: minute
            value: 7
            anon_value: 3
            invokers:
              - header_value: foo-client
                name: client 1
                unit: minute
                value: 5
          - uri_prefix: "/bar"
            unit: minute
            value: 20
            anon_value: 2
            invokers:
              - header_value: bar-client
                name: client 2
                unit: minute
                value: 2
          - uri_prefix: "/foo/bar"
            unit: minute
            value: 13
            anon_value: 4
            invokers:
              - header_value: foo-bar-client
                name: client 3
                unit: minute
                value: 6
                schedule:
                  start:
                     second: '10'
                     minute: '*'
                     hour: '*'
                     day: '*'
                     month: '*'
                     weekday: '*'
                  stop:
                     second: '45'
                     minute: '*'
                     hour: '*'
                     day: '*'
                     month: '*'
                     weekday: '*'
                  unit: second
                  value: 10

Таким образом, для вызовов http://ingress-my-namespace-02.apps.domain.org/foo и http://ingress-my-namespace-02.apps.domain.org/bar/pruduct?param=1 будут применяться различные значения лимитов.

С релиза 2.4 префиксы /foo и /foo/bar являются независимыми с точки зрения Rate Limiter — для запросов http://ingress-my-namespace-02.apps.domain.org/foo/test1?param1=value1 и http://ingress-my-namespace-02.apps.domain.org/foo/bar/test2 также будут применяться различные значения лимитов.

Поле schedule в примере выше означает, что для префикса /foo/bar для client 3 будет изменен лимит 6 запросов в минуту в период с 10 секунды по 45 секунду каждой минуты каждого часа каждого дня каждого месяца на 10 запросов в секунду.

Если делается вызов с префиксом, для которого не указан лимит в артефакте GlobalRateLimit, то запросы на него будут идти без лимита. При этом в логах RL Service будут сообщения об ошибках no prefix found, valid prefixes: [/bar /foo/bar]", и метрика ошибок ratelimiterservice_should_rate_limit_unknown_prefix_error будет увеличиваться.

В случаях, когда нет необходимости считать лимиты для определенного префикса, можно указать для него в поле value значение -1.

    - endpoint: 'ingress-my-namespace-02.apps.domain.org:8080'
      name: srls dev 02
      shortname: dev
      overall_limit: 100
      by_header:
        header: synapse-consumerid
        unit: minute
        uri_prefixes:
          - uri_prefix: "/healthcheck"
            value: -1
          - uri_prefix: "/bar"
            unit: minute
            value: 20
            anon_value: 2
            invokers:
              - header_value: bar-client
                name: client 2
                unit: minute
                value: 2

В данном примере запросы с префиксом /healthcheck будут ограничены только лимитом на весь endpoint (значением overall_limit). При этом если будет указан блок invokers, то он будет игнорироваться.

В случаях, когда нет необходимости считать лимиты для всех префиксов, не указанных в артефакте GRL, можно для префикса / указать в поле value значение -1.

    - endpoint: 'ingress-my-namespace-02.apps.domain.org:8080'
      name: srls dev 02
      shortname: dev
      overall_limit: 100
      by_header:
        header: synapse-consumerid
        unit: minute
        uri_prefixes:
          - uri_prefix: "/"
            value: -1
          - uri_prefix: "/bar"
            unit: minute
            value: 20
            anon_value: 2
            invokers:
              - header_value: bar-client
                name: client 2
                unit: minute
                value: 2

В данном примере лимит будет считаться только для запросов с префиксом /bar. Запросы со всеми остальными префиксами будут ограничены только лимитом на весь endpoint (значением overall_limit).

Префикс / так же может быть использован для подсчета общего лимита для всех остальных префиксов, если в поле value задано конкретное значение.

    - endpoint: 'ingress-my-namespace-02.apps.domain.org:8080'
      name: srls dev 02
      shortname: dev
      overall_limit: 100
      by_header:
        header: synapse-consumerid
        unit: minute
        uri_prefixes:
          - uri_prefix: "/"
            value: 10
            unit: minute
          - uri_prefix: "/bar"
            unit: minute
            value: 20

В данном примере лимит для вызовов с префиксом /bar будет 20 запросов в минуту. Запросы со всеми остальными префиксами будут ограничены лимитом 10 запросов в минуту.

Rate Limit CN#

Данный режим является расширением режимов Rate Limit Header и Prefix. Применяется в случаях, когда требуется идентифицировать потребителя по конкретным атрибутам поля Subject сертификата.

Для добавления в запрос заголовка со значением Subject необходимо вручную загрузить артефакт EnvoyFilter.

Для Istio 1.12 (Envoy 1.20) EnvoyFilter имеет следующий вид:

apiVersion: networking.istio.io/v1alpha3
kind: EnvoyFilter
metadata:
  name: subj-filter
  namespace: ${namespace}
spec:
  configPatches:
    - applyTo: HTTP_FILTER
      match:
        context: GATEWAY
        listener:
          filterChain:
            filter:
              name: envoy.http_connection_manager
          portNumber: ${port}
      patch:
        operation: INSERT_BEFORE
        value:
          name: envoy.filters.http.lua
          typed_config:
            '@type': type.googleapis.com/envoy.extensions.filters.http.lua.v3.Lua
            inline_code: |
              function envoy_on_request(request_handle)
                local peer_subject = request_handle:streamInfo():downstreamSslConnection():subjectPeerCertificate()
                if peer_subject == nil then
                  request_handle:respond(
                    {[":status"] = "403",
                    ["info"] = "no subjectPeerCertificate in request"},
                    "nope")
                end
                request_handle:logDebug(peer_subject)
                request_handle:headers():replace("${header}", peer_subject)
              end
  workloadSelector:
    labels:
      ${labels}

Для более ранних версий Envoy необходимо использовать EnvoyFilter, который имеет следующий вид:

apiVersion: networking.istio.io/v1alpha3
kind: EnvoyFilter
metadata:
  name: subj-filter
  namespace: ${namespace}
spec:
  configPatches:
    - applyTo: HTTP_FILTER
      match:
        context: GATEWAY
        listener:
          filterChain:
            filter:
              name: envoy.http_connection_manager
          portNumber: ${port}
      patch:
        operation: INSERT_BEFORE
        value:
          name: envoy.filters.http.lua
          typed_config:
            '@type': type.googleapis.com/envoy.extensions.filters.http.lua.v3.Lua
            inline_code: |
              function envoy_on_request(request_handle)
                local peer_subject = request_handle:headers():get("x-forwarded-client-cert")

                if peer_subject == nil then
                  request_handle:respond(
                    {[":status"] = "403",
                    ["info"] = "no x-forwarded-client-cert header"},
                    "nope")
                end

                local i,k = string.find(peer_subject, 'Subject=\"')

                if i == nil then
                  request_handle:respond(
                    {[":status"] = "403",
                    ["info"] = "no subject in cert"},
                    "nope")
                end

                local j = string.find(peer_subject, "\"", k+1)

                if j == nil then
                    request_handle:respond(
                      {[":status"] = "403",
                      ["info"] = "cant parse subject"},
                      "nope")

                end
                local subj = string.sub(peer_subject, k+1, j-1)

                request_handle:logDebug(subj)
                request_handle:headers():replace("${header}", subj)
              end
  workloadSelector:
    labels:
      ${labels}

Этот фильтр менее эффективен, так как в нём значение Subject вычленяется из заголовка "x-forwarded-client-cert", но позволяет работать даже с Envoy 1.14.

В соответствии с добавленным фильтром:

  • запросы, в которых не будет данных о клиентском сертификате, будут отклонены с ошибкой 403;

  • если в запросе уже будет заголовок ${header}, то он будет перезаписан.

Ниже приведены параметры для конфигурирования данного артефакта EnvoyFilter:

Название параметра

Описание

Пример

namespace

Идентификатор пространства имен

my-namespace

labels

Список label для определения необходимого Ingress (Egress) Gateway

app: ingress-my-namespace

port

Порт, на который отправляются запросы

8443

header

Название заголовка, в который будет записываться поле Subject

synapse-consumerid

При конфигурировании лимитов можно использовать как все поле Subject целиком, так и конкретный атрибут (или набор атрибутов) из него. Для указания конкретных атрибутов необходимо добавить в артефакт GlobalRateLimit раздел modify_header.

Блок modify_header влияет на весь endpoint, указывается внутри by_header и содержит в себе два параметра:

  • type — тип преобразования заголовка (для режима Rate Limit CN необходимо указывать значение cert — преобразования в терминах сертификата);

  • rule — правило преобразования заголовка (для типа cert через запятую указываются необходимые атрибуты сертификата из поля Subject).

Правило преобразования rule поддерживает следующие атрибуты поля Subject сертификата:

  • CN: CommonName

  • OU: OrganizationalUnit

  • O: Organization

  • L: Locality

  • S или ST: StateOrProvinceName

  • C: CountryName

Пример поля Subject: CN=tribe-sy-dev-srls-dev-04, OU=R&D, O=sbertech, L=Moscow 10, S=Moscow, C=RU.

Примеры указания правила преобразования заголовка: rule: cn, rule: CN, o, rule: Ou,O

Пример конфигурации endpoint c modify_header:

- endpoint: 'ingress-my-namespace-02.apps.domain.org:8443'
  name: srls dev 02
  shortname: dev
  by_header:
    modify_header:
      type: cert
      rule: cn
    anon_value: 1
    header: synapse-consumerid
    invokers:
      - header_value: tribe-sy-dev-srls-dev-04
        name: client 1
        unit: minute
        value: 13
    unit: minute
    value: 7

Предположим, что в сертификате задан Subject="CN=tribe-sy-dev-srls-dev-04, OU=R&D, O=sbertech, C=RU". В таком случае, после применения EnvoyFilter, в пользовательский заголовок, например в synapse-consumerid, будет добавлено значение CN=tribe-sy-dev-srls-dev-04, OU=R&D, O=sbertech, C=RU. Рассмотрим для этого примера варианты указания блока modify_header и соответствующие ему header_value для задания лимитов:

  • блок modify_header не задан — преобразование заголовка не выполняется, для задания лимита используется все значение поля Subject:

 by_header:
   header: synapse-consumerid
   invokers:
    - header_value: CN=tribe-sy-dev-srls-dev-04, OU=R&D, O=sbertech, C=RU
      name: client 1
      unit: minute
      value: 13
   unit: minute
   value: 7
  • в modify_header не задано правило преобразования rule (или задано пустое значение) — преобразование заголовка не выполняется, для задания лимита используется все значение поля Subject:

 by_header:
   modify_header:
     type: cert
   header: synapse-consumerid
   invokers:
    - header_value: CN=tribe-sy-dev-srls-dev-04, OU=R&D, O=sbertech, C=RU
      name: client 1
      unit: minute
      value: 13
   unit: minute
   value: 7
  • в modify_header в правиле указан один атрибут, который присутствует в Subject — преобразование заголовка выполнится, для задания лимита используется значение указанного атрибута:

 by_header:
   modify_header:
     type: cert
     rule: cn
   header: synapse-consumerid
   invokers:
    - header_value: tribe-sy-dev-srls-dev-04
      name: client 1
      unit: minute
      value: 13
   unit: minute
   value: 7
  • в modify_header в правиле указано несколько атрибутов, которые присутствуют в Subject — преобразование заголовка выполнится, для задания лимита используется конкатенация значений указанных атрибутов:

 by_header:
   modify_header:
     type: cert
     rule: cn,o
   header: synapse-consumerid
   invokers:
    - header_value: tribe-sy-dev-srls-dev-04sbertech
      name: client 1
      unit: minute
      value: 13
   unit: minute
   value: 7
  • в modify_header в правиле указано несколько атрибутов, но не все они присутствуют в Subject — преобразование заголовка выполнится, для задания лимита используется конкатенация значений атрибутов, имеющихся в Subject:

 by_header:
   modify_header:
     type: cert
     rule: cn,l,st,o
   header: synapse-consumerid
   invokers:
    - header_value: tribe-sy-dev-srls-dev-04sbertech
      name: client 1
      unit: minute
      value: 13
   unit: minute
   value: 7
  • в modify_header в правиле указано несколько атрибутов, но они не присутствуют в Subject — преобразование заголовка выполнится с ошибкой и вернёт исходное значение. Для задания лимита в таком случае, можно использовать все значение поля Subject. Но при этом метрика ошибок модификации ratelimiterservice_should_rate_limit_modify_header_error будет постоянно увеличиваться, и в логах rate-limiter-service c уровнем debug будет выводиться ошибка типа: "Error modify header: the specified cert artifact was not found in the header: CN=tribe-sy-dev-srls-dev-04, OU=R&D, O=sbertech, C=RU"

 by_header:
   modify_header:
     type: cert
     rule: l,st
   header: synapse-consumerid
   invokers:
    - header_value: CN=tribe-sy-dev-srls-dev-04, OU=R&D, O=sbertech, C=RU
      name: client 1
      unit: minute
      value: 13
   unit: minute
   value: 7
  • EnvoyFilter не добавлен, пользователь при запросе добавляет заголовок, например synapse-consumerid: Kafka, но в артефакте GlobalRateLimit задан блок modify_header — преобразование заголовка выполнится с ошибкой и вернёт исходное значение. Для задания лимита в таком случае, можно использовать значение "Kafka". Но при этом метрика ошибок модификации ratelimiterservice_should_rate_limit_modify_header_error будет постоянно увеличиваться, и в логах rate-limiter-service c уровнем debug будет выводиться ошибка типа: "Error modify header: the specified cert artifact was not found in the header: CN=tribe-sy-dev-srls-dev-04, OU=R&D, O=sbertech, C=RU"

 by_header:
   modify_header:
     type: cert
     rule: cn
   header: synapse-consumerid
   invokers:
    - header_value: Kafka
      name: client 1
      unit: minute
      value: 13
   unit: minute
   value: 7

Rate Limit Path#

Данный режим позволяет идентифицировать потребителя (тенанта) по ResourceName из URL запроса.

Формат ResourceName состоит из трех частей: account-id, project-id, resource-id. В конфигурации Rate Limit можно задать значимую часть идентификатора потребителя с помощью маски для расчета лимита.

Варианты маски:

  • mask = "rn/::*" получим итоговое значение: account-idproject-idresource-id;

  • mask = "rn/::_" получим итоговое значение: account-idproject-id;

  • mask = "rn/*::" получим итоговое значение: account-id.

Формат URL запроса:

"http(s)://{HOST}:{PORT}/[{*Код продукта*}]/[{*версия*}]/rn/account-id:project-id:resource-id/{Контекст продукта}"

Пример конфигурации для режима Rate Limit Path:

    - endpoint: 'test-server3-endpoint:8080'
      name: some service3
      overall_limit: 70
      shortname: servert
      by_path:
        mask: 'rn/*:*:_'
        unit: second
        quotas:
          flat: 15
          soft:
            step: 1
            value: 10
        tenants:
          - name: server1.path
            quotas:
              flat: 7
            resourceName: account-1project-1
            unit: second
            schedule:
              start:
                 second: '0'
                 minute: '0'
                 hour: '2'
                 day: '1'
                 month: '1'
                 weekday: '*'
              stop:
                 second: '0'
                 minute: '0'
                 hour: '12'
                 day: '5'
                 month: '1'
                 weekday: '*'
              unit: minute
              value: 20
          - name: server2.path
            quotas:
              flat: 10
              soft:
                step: 1
                value: 5
            resourceName: account-2project-2
            unit: second

Параметры блока by_path:

  • mask — опциональное поле, по умолчанию rn/*:*:*, маска для определения значимой части идентификатора потребителя;

  • unit — опциональное поле, по умолчанию second, единица измерения лимитов, используется при расчете overall_limit и потребителей, неуказанных в блоке tenants;

  • quotas — конфигурация квоты для потребителей, неуказанных в блоке tenants;

  • tenants — опциональный блок, позволяет задать квоту для определенных потребителей независимо.

Параметры блока quotas:

  • flat — опциональное поле, по умолчанию 1, позволяет задать квоту для запросов;

  • soft — опциональный блок, если задан, создается метрика, показывающая приближение к лимиту. soft.value — значение квоты, после которой с шагом кратным soft.step будет инкрементирована метрика мониторинга превышения уровня soft квоты для конкретного потребителя вплоть до превышения основного лимита.

Для каждого tenant можно задать:

  • name — опциональное поле, позволяет указать метаданные для resourceName;

  • quotas — конфигурация квоты для потребителя, указанного в resourceName;

  • resourceName — идентификатор потребителя, значение необходимо указать в формате account-id:project-id:resource-id без разделителя, например accProjRes, если используется маска, необходимо указать только значимую часть, например accProj;

  • unit — опциональное поле, по умолчанию second, единица измерения лимитов;

  • schedule – опциональный блок, позволяет изменять лимиты по расписанию.

Поле schedule в примере выше означает, что для tenant: name: server1.path будет изменен лимит 7 запросов в секунду в период с 2 часов 1 января по 12 часов 12 января на 20 запросов в минуту.

Применение нескольких артефактов GlobalRateLimit в рамках одного namespace#

В рамках одного namespace можно создать несколько артефактов GlobalRateLimit для независимого конфигурирования лимитов для сервисов. При этом можно создавать артефакты с разным значением поля workloadSelector, например, для работы как с Ingress Gateway, так и с Egress Gateway.

После создания артефакта происходит «слияние» артефактов с одним и тем же workloadSelector, на этапе «слияния» выполняется валидация конфигурации лимитов.

Осуществляется проверка на уникальность значений полей endpoint и shortname, уникальность значения поля resourceName для одного endpoint и валидация значений полей overall_schedule и schedule.

В случае ошибки валидации необходимо скорректировать значения невалидного артефакта GlobalRateLimit или удалить артефакт.

Ограничение списка namespace для централизованного SRLS#

Ограничение списка namespace для централизованного SRLS необходимо, чтобы была возможность развернуть несколько централизованных SRLS в рамках одного кластера Kubernetes или Red Hat OpenShift (опционально).

Алгоритм следующий:

  1. Пользователь создает в своем namespace артефакт GlobalRateLimit.

  2. RL Operator считывает поле «rlnamespace», сравнивает значение с идентификатором namespace, в котором он установлен.

    1. если значение не совпадает, RL Operator не берет в работу.

  3. Если поле в GlobalRateLimit не задано, RL Operator осуществляет проверку на наличие прав доступа к артефакту EnvoyFilter в namespace пользователя, если права есть — берет GlobalRateLimit в работу, если доступа нет, не берет в работу.

Часто встречающиеся проблемы и пути их устранения#

Код ошибки

Пример ошибки

Решение

'grpc-status', '12'

2022-02-22T13:51:47.544976Z debug envoy http [external/envoy/source/common/http/conn_manager_impl.cc:1729] [C8647][S166541960535733715] encoding headers via codec (end_stream=true): ':status', '200' 'content-type', 'application/grpc' 'grpc-status', '12' 'date', 'Tue, 22 Feb 2022 13:51:47 GMT' 'server', 'istio-envoy'

Для анализа необходимо проследить цепочку от Ingress Gateway в прикладном namespace до Rate Limit в централизованном namespace. Для анализа необходимо включить расширенное логирование на Egress Gateway в прикладном namespace и Ingress Gateway в namespace централизованного Rate Limit. Это можно сделать с помощью curl -XPOST localhost:15000/logging?level=debug. Если цепочка вызовов прерывается на Egress Gateway, то необходимо проверить корректность наполнения артефактов VirtualService, ServiceEntry, DestinationRule, если цепочка вызовов прерывается на Ingress Gateway, то необходимо проверить VirtualService

Pod RL Service завершается с ошибкой

time="2022-08-04T14:30:21Z" level=warning msg="connecting to redis on mymaster,redis-sentinel-0.redis-sentinel:26379,redis-sentinel-1.redis-sentinel:26379,redis-sentinel-2.redis-sentinel:26379 with pool size 10" panic: dial tcp: lookup redis-sentinel-2.redis-sentinel on { IP_ADDRESS }:53: no such host

Необходимо удостовериться, что 3 pod StatefullSet redis-sentivel запущены корректно

Некорректная балансировка запросов от Ingress Gateway до Egress Gateway трафика в сторону RL Service

В случае перезапуска pod Egress gateway или увеличения числа pods, трафик на вновь созданный pod почти не поступает

Убедиться, что в артефакте GlobalRateLimit указан Headless Service Egress Gateway, а не обычный. Headless Service — это Service, у которого параметр clusterIP выставлен в None

Не срабатывает RateLimit

-

Проверить, что:
1) все pod RL Operator, RL Service, Redis, Sentinel запущены, в логах приложений нет ошибок;
2) загружен артефакт GlobalRateLimit (GRL) с необходимыми настройками;
3) в артефакте GRL выставлено корректное значение поля visibility в соответствии с типом установки компонента SRLS, для централизованного — cluster, для децентрализованного — namespace;
4) значение поля workloadSelector, указанное в GRL, соответствует меткам Ingress-gateway;
5) указанное значение поля envoyVersion соответствует версии Envoy, используемой в Ingress-gateway (Если используется Red Hat Service Mesh 2.0 — версия 1.14, Red Hat Service Mesh 2.1 — 1.17);
6) указанные значения настроек rlserver и rlserverport верны для соответствующей инсталляции (централизованный — в качестве host должен быть указан Headless Service RL Service, порт — 12001, децентрализованный — Headless Service RLService, порт — 8081);
7) в случае централизованного варианта установки в поле rlnamespace должен быть указан целевой namespace централизованного компонента SRLS;
8) созданы все необходимые роли и RoleBinding в соответствии с инструкцией по установке;
9) в полях endpoint указан host, на который поступает входящий трафик (из артефактов Route, Gateway, VirtualService), и порт, который слушает Ingress (задается в артефакте Gateway)

Не запускается pod

Failed to pull image "registry.mydomain.ru/ci90000055_srls/operator@sha256:9f45c61299009bf91a63514680230151e02bc2bde35f38c14b381edacd291992": rpc error: code = Unknown desc = Error reading manifest sha256:9f45c61299009bf91a63514680230151e02bc2bde35f38c14b381edacd291992 in registry.mydomain.ru/domain/srls/operator: unauthorized: authentication required

Предоставьте права на доступ к образу для пользователя, прописанного в ImagePullSecret rls-image-pull-secret

Не применяется конфигурация GlobalRateLimit

Ошибка в блоке status: endpoint [test-server1-endpoint-tribe-sy-srls-dev-03.apps.stands-vdc01.solution.sbt:8080] tenant.Name [server1.path] tenant.ResourceName [account-3] duplicate error: GlobalRateLimit manifest not valid

Значение поля resourceName должно быть уникальным при конфигурировании endpoint. Скорректируйте значение поля resourceName

Не запускается pod

Error creating: pods "rloperator-f9bc4fcdc-" is forbidden: unable to validate against any security context constraint: [provider "anyuid": Forbidden: not usable by user or serviceaccount, provider restricted: .spec.securityContext.fsGroup: Invalid value: []int64{2000}: 2000 is not an allowed group, spec.containers[1].securityContext.runAsUser: Invalid value: 1001560000: must be in the ranges: [1000900000, 1000909999], provider "mef-scc": Forbidden: not usable by user or serviceaccount, provider "nonroot": Forbidden: not usable by user or serviceaccount, provider "hostmount-anyuid": Forbidden: not usable by user or serviceaccount, provider "aqua-scc": Forbidden: not usable by user or serviceaccount, provider "machine-api-termination-handler": Forbidden: not usable by user or serviceaccount, provider "hostnetwork": Forbidden: not usable by user or

Ошибка говорит, что при развертывании в кластере OpenShift было выставлено значение True параметра шаблонизации DEPLOY_TO_KUBERNETES. Установите значение False

Не запускается pod rloperator

W0816 16:15:07.596714 1 reflector.go:424] sigs.k8s.io/controller-runtime/pkg/cache/internal/informers_map.go:262: failed to list *v1alpha1.GlobalRateLimit: globalratelimits.ratelimit.service is forbidden: User "system:serviceaccount:some-namespace:rate-limiter-service" cannot list resource "globalratelimits" in API group "ratelimit.service" at the cluster scope

Убедитесь, что созданы артефакты ClusterRole и ClusterRoleBinding, предоставляющие права на артефакт GlobalRateLimit для ServiceAccount rate-limiter-service в вашем namespace