Как APISIX Ingress Controller поддерживает тысячи реплик Pod?

Xin Rong

October 21, 2022

Technology

1,000+ подов Kubernetes

Поды — это наименьшие развертываемые объекты в Kubernetes. Мы используем под для запуска одного экземпляра приложения, поэтому выделяем поду ограниченные ресурсы из-за масштабируемости. Однако, если мы сталкиваемся с высоконагруженными сценариями, мы будем использовать горизонтальное масштабирование для их обработки.

Например, для онлайн-ритейлеров Black Friday вызывает резкий рост трафика. Чтобы справиться с этим сценарием, нам необходимо автоматически масштабировать сервисы для обработки большего объема трафика. Мы будем развертывать больше репликаций на основе стратегии автоматического масштабирования, что приведет к увеличению количества подов.

Каждый под имеет динамический IP-адрес. API Endpoints предоставляет простой способ отслеживания сетевых конечных точек в Kubernetes, что позволяет нам достичь балансировки нагрузки, своевременно отслеживая изменения IP-адресов подов. Однако, по мере роста кластеров Kubernetes и сервисов для обработки большего объема трафика к большему количеству подов, например, в сценарии Black Friday, упомянутом выше, количество подов продолжает увеличиваться, и API Endpoints становится больше. В результате ограничения API Endpoints становятся более заметными, и он даже становится узким местом производительности.

Чтобы решить проблему ограничений API Endpoints, Kubernetes начинает поддерживать API EndpointSlice в версии v1.21. API EndpointSlice помогает решить проблему производительности при обработке огромного количества сетевых конечных точек в API Endpoints и обладает отличной масштабируемостью и расширяемостью.

Мы можем напрямую увидеть различия между ними на диаграмме ниже:

  • Изменения Endpoints во время всплеска трафика

Endpoints во время всплеска трафика

  • Изменения Endpointslices во время всплеска трафика

Endpointslices во время всплеска трафика

В Kubernetes, как приложения взаимодействуют друг с другом? Каковы конкретные различия между Endpoints и EndpointSlice? Какова связь между подом и Endpoints/EndpointSlice? Как APISIX поддерживает эти функции, и как их установить и использовать? Мы сосредоточимся на этих вопросах в этой статье.

Как получить доступ к приложениям в Kubernetes

Через Service

Каждый под имеет свой уникальный IP-адрес в Kubernetes. Обычно Service устанавливает соединения с подом с помощью selector, предоставляет одинаковое DNS-поддоменное имя и достигает балансировки нагрузки. Кроме того, приложения внутри кластера Kubernetes могут использовать DNS для взаимодействия друг с другом.

Когда Service создается, Kubernetes связывает Service с ресурсом Endpoints. Однако, если Service не указал никаких селекторов, Kubernetes не будет автоматически создавать Endpoints для Service.

Что такое Endpoints и какова связь с подом

Endpoints — это объект ресурса в Kubernetes, хранящийся в etcd, и включает ссылки на набор адресов доступа к подам, которые соответствуют Service. Таким образом, каждый Service может иметь только один ресурс Endpoints. Ресурс Endpoints будет отслеживать кластеры подов и синхронно обновляться при любом изменении пода в Service.

  1. Разверните 3 репликации httpbin и проверьте статус подов, включая информацию об IP
$ kubectl get pods -o wide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES httpbin-deployment-fdd7d8dfb-8sxxq 1/1 Running 0 49m 10.1.36.133 docker-desktop <none> <none> httpbin-deployment-fdd7d8dfb-bjw99 1/1 Running 4 (5h39m ago) 23d 10.1.36.125 docker-desktop <none> <none> httpbin-deployment-fdd7d8dfb-r5nf9 1/1 Running 0 49m 10.1.36.131 docker-desktop <none> <none>
  • создайте сервис httpbin и проверьте состояние конечных точек Endpoints
$ kubectl get endpoints httpbin NAME ENDPOINTS AGE httpbin 10.1.36.125:80,10.1.36.131:80,10.1.36.133:80 23d

Из приведенных выше примеров видно, что каждая сетевая конечная точка ресурса httpbin в Endpoints соответствует IP-адресу пода.

Недостатки Endpoints

  1. Endpoints имеет ограничение на хранение: если любой ресурс Endpoints содержит более 1000 конечных точек, то контроллер Endpoints обрежет конечные точки до 1000.
  2. Сервис может иметь только один ресурс Endpoints, что означает, что ресурс Endpoints должен хранить IP-адреса и другую сетевую информацию для каждого пода, поддерживающего соответствующий Service. В результате ресурс API Endpoints становится огромным, и он должен обновляться при изменении одной сетевой конечной точки в ресурсе. Когда бизнесу требуются частые изменения конечных точек, огромный ресурс API будет передаваться между компонентами, что влияет на производительность компонентов Kubernetes.

Что такое Endpointslices

Endpointslices — это более масштабируемая и расширяемая альтернатива Endpoints, которая помогает справиться с проблемой производительности, вызванной обработкой огромного количества сетевых конечных точек. Она также предоставляет расширяемую платформу для дополнительных функций, таких как топологическая маршрутизация. Эта функция поддерживается в Kubernetes v1.21.

API EndpointSlice был разработан для решения этой проблемы с подходом, похожим на шардирование. Вместо отслеживания всех IP-адресов подов для Service с помощью одного ресурса Endpoints, мы разделяем их на несколько меньших EndpointSlices.

По умолчанию контрольная плоскость создает и управляет EndpointSlices так, чтобы в каждом было не более 100 конечных точек. Вы можете настроить это с помощью флага --max-endpoints-per-slice в kube-controller-manager, до 1000.

Зачем это нужно

Рассмотрим сценарий

Предположим, есть Service, поддерживаемый 2000 подами, что может привести к ресурсу Endpoints размером 1.0 МБ. В производственной среде, если этот Service выполняет rolling updates или миграцию конечных точек, ресурсы Endpoints будут часто обновляться. Подумайте о rolling updates, которые приведут к замене всех подов из-за ограничения максимального размера запроса в etcd. Kubernetes установил максимальное ограничение в 1000 конечных точек для Endpoints. Если конечных точек больше 1000, ресурс Endpoints не будет содержать ссылок на дополнительные сетевые конечные точки.

Если Service требует нескольких rolling updates из-за некоторых особых потребностей, то огромный объект ресурса API будет передаваться между компонентами Kubernetes, что значительно влияет на производительность компонентов Kubernetes.

Что, если мы используем EndpointSlice

Предположим, есть Service, поддерживаемый 2000 подами, и мы назначаем 100 конечных точек для каждого EndpointSlice в конфигурации, тогда у нас будет 20 EndpointSlices. Теперь, когда под добавляется или удаляется, нужно обновить только один маленький EndpointSlice. Очевидно, это значительное улучшение в масштабируемости и сетевой расширяемости. Если каждый Service имеет требование автоматического масштабирования, то Service будет развертывать больше подов, и ресурс Endpoints будет часто обновляться для обработки увеличивающегося трафика при всплеске трафика, и разница станет более заметной. Более важно, что теперь все IP-адреса подов для Service не нужно хранить в одном ресурсе, и нам не нужно беспокоиться о ограничении размера объектов, хранящихся в etcd.

Заключение Endpoints VS EndpointSlice

Поскольку EndpointSlice поддерживается с Kubernetes v1.21, все выводы относятся к Kubernetes v1.21.

Сценарии использования Endpoints:

  • Есть необходимость в автоматическом масштабировании, но количество подов относительно небольшое, и передача ресурсов не вызовет огромного сетевого трафика и дополнительных потребностей в обработке.
  • Нет необходимости в автоматическом масштабировании, и количество подов не будет огромным. Однако, даже если количество подов фиксировано, Service не может избежать rolling updates и сбоев.

Сценарии использования EndpointSlice:

  • Есть необходимость в автоматическом масштабировании, и количество подов огромное (сотни подов).
  • Количество подов огромное (сотни подов) из-за ограничения максимального количества конечных точек в Endpoints, равного 1000; любой под, имеющий более 1000 конечных точек, должен использовать EndpointSlice.

Практика в APISIX Ingress Controller

APISIX Ingress Controller достигает балансировки нагрузки и проверки работоспособности, отслеживая изменения ресурса Endpoints или EndpointSlice. Для поддержки Kubernetes v1.16+ APISIX Ingress Controller по умолчанию будет использовать Endpoints при установке.

Если версия вашего кластера — Kubernetes v1.21+, то вам нужно указать флаг watchEndpointSlice=true для поддержки функции EndpointSlice при установке APISIX Ingress Controller.

Примечание: В кластерах с Kubernetes v1.21+ мы рекомендуем использовать функцию Endpointslice, иначе, когда количество подов превышает значение конфигурации флага --max-endpoints-per-slice, конфигурация будет потеряна, так как APISIX Ingress Controller отслеживает объект ресурса Endpoints.

Создание Service с 20 репликациями подов

Настройте сервис приложения httpbin в Kubernetes и создайте 20 репликаций подов.

  • - kubectl apply -f httpbin-deploy.yaml
# htppbin-deploy.yaml apiVersion: apps/v1 kind: Deployment metadata: name: httpbin-deployment spec: replicas: 20 selector: matchLabels: app: httpbin-deployment strategy: rollingUpdate: maxSurge: 50% maxUnavailable: 1 type: RollingUpdate template: metadata: labels: app: httpbin-deployment spec: terminationGracePeriodSeconds: 0 containers: - livenessProbe: failureThreshold: 3 initialDelaySeconds: 2 periodSeconds: 5 successThreshold: 1 tcpSocket: port: 80 timeoutSeconds: 2 readinessProbe: failureThreshold: 3 initialDelaySeconds: 2 periodSeconds: 5 successThreshold: 1 tcpSocket: port: 80 timeoutSeconds: 2 image: "kennethreitz/httpbin:latest" imagePullPolicy: IfNotPresent name: httpbin-deployment ports: - containerPort: 80 name: "http" protocol: "TCP" --- apiVersion: v1 kind: Service metadata: name: httpbin spec: selector: app: httpbin-deployment ports: - name: http port: 80 protocol: TCP targetPort: 80 type: ClusterIP

Прокси через APISIX Ingress

  • Используйте Helm для установки APISIX Ingress Controller

Используйте --set ingress-controller.config.kubernetes.watchEndpointSlice=true для включения поддержки функции EndpointSlice.

helm repo add apisix https://charts.apiseven.com helm repo add bitnami https://charts.bitnami.com/bitnami helm repo update kubectl create ns ingress-apisix helm install apisix apisix/apisix \ --set gateway.type=NodePort \ --set ingress-controller.enabled=true \ --namespace ingress-apisix \ --set ingress-controller.config.apisix.serviceNamespace=ingress-apisix \ --set ingress-controller.config.kubernetes.watchEndpointSlice=true
  • Используйте ресурс CRD для прокси

Пользователи могут не заметить поддержку функций Endpoints и EndpointSlice в APISIX Ingress Controller, и их конфигурации одинаковы.

apiVersion: apisix.apache.org/v2 kind: ApisixRoute metadata: name: httpbin-route spec: http: - name: rule match: hosts: - httpbin.org paths: - /get backends: - serviceName: httpbin servicePort: 80
  • Проверяя под APISIX, мы можем увидеть, что поле nodes объекта upstream APISIX содержит IP-адреса 20 подов.
kubectl exec -it ${Pod for APISIX} -n ingress-apisix -- curl "http://127.0.0.1:9180/apisix/admin/upstreams" -H 'X-API-KEY: edd1c9f034335f136f87ad84b625c8f1'
{ "action": "get", "count": 1, "node": { "key": "\/apisix\/upstreams", "nodes": [ { "value": { "hash_on": "vars", "desc": "Created by apisix-ingress-controller, DO NOT modify it manually", "pass_host": "pass", "nodes": [ { "weight": 100, "host": "10.1.36.100", "priority": 0, "port": 80 }, { "weight": 100, "host": "10.1.36.101", "priority": 0, "port": 80 }, { "weight": 100, "host": "10.1.36.102", "priority": 0, "port": 80 }, { "weight": 100, "host": "10.1.36.103", "priority": 0, "port": 80 }, { "weight": 100, "host": "10.1.36.104", "priority": 0, "port": 80 }, { "weight": 100, "host": "10.1.36.109", "priority": 0, "port": 80 }, { "weight": 100, "host": "10.1.36.92", "priority": 0, "port": 80 } ... // игнорируем 13 узлов ниже // 10.1.36.118 // 10.1.36.115 // 10.1.36.116 // 10.1.36.106 // 10.1.36.113 // 10.1.36.111 // 10.1.36.108 // 10.1.36.114 // 10.1.36.107 // 10.1.36.110 // 10.1.36.105 // 10.1.36.112 // 10.1.36.117 ], "labels": { "managed-by": "apisix-ingress-controller" }, "type": "roundrobin", "name": "default_httpbin_80", "scheme": "http" }, "key": "\/apisix\/upstreams\/5ce57b8e" } ], "dir": true } }
  • Сопоставление с сетевыми конечными точками EndpointSlice
addressType: IPv4 apiVersion: discovery.k8s.io/v1 endpoints: - addresses: - 10.1.36.92 ... - addresses: - 10.1.36.100 ... - addresses: - 10.1.36.104 ... - addresses: - 10.1.36.102 ... - addresses: - 10.1.36.101 ... - addresses: - 10.1.36.103 ... - addresses: - 10.1.36.109 ... - addresses: - 10.1.36.118 ... - addresses: - 10.1.36.115 ... - addresses: - 10.1.36.116 ... - addresses: - 10.1.36.106 ... - addresses: - 10.1.36.113 ... - addresses: - 10.1.36.111 ... - addresses: - 10.1.36.108 ... - addresses: - 10.1.36.114 ... - addresses: - 10.1.36.107 ... - addresses: - 10.1.36.110 ... - addresses: - 10.1.36.105 ... - addresses: - 10.1.36.112 ... - addresses: - 10.1.36.117 ... kind: EndpointSlice metadata: labels: endpointslice.kubernetes.io/managed-by: endpointslice-controller.k8s.io kubernetes.io/service-name: httpbin name: httpbin-dkvtr namespace: default ports: - name: http port: 80 protocol: TCP

Заключение

Эта статья представляет сценарии, в которых Kubernetes необходимо развертывать огромное количество подов, и проблемы, с которыми мы сталкиваемся. Также сравниваются различия между Endpoints и EndpointSlice, и представлен способ включения функции EndpointSlice при установке APISIX Ingress Controller. Если версия вашего кластера — Kubernetes v1.21+, мы рекомендуем включить функцию EndpointSlice при установке APISIX Ingress Controller. Таким образом, можно избежать потери конфигурации, и нам не нужно беспокоиться о значении конфигурации флага --max-endpoints-per-slice.

Tags: