
Существует множество альтернатив для доступа к модулю извне кластера. Шлюз API - это определенно новинка этой области, и потому выбран темой этой статьи.
Ранее мы описывали несколько способов доступа к модулям Kubernetes. Так, например, доступ к модулю pods можно получить через его IP-адрес, но важно учитывать, что поды по своей сути являются временными. Штатный способ - настроить Service: в этом случае IP-адрес стабилен, а задача Kubernetes - обеспечивать мапироание между Service и соответствующими ей подами. В настоящий момент доступны различные виды сервисов: только внутренние, NodePort, позволяющий открыть доступа извне кластера, и LoadBalancer, который полагается на сторонний компонент - обычно это на облачный провайдер. Не будем забывать и об Ingress, обеспечивающем маршрутизацию.
Ну а API-шлюз, как новинку в этой области, мы оставили на десерт, решив посвятить ему целый пост.
От Ingress к API-шлюзу
Внешний доступ к подам Kubernetes прошел несколько эволюционных этапов. Так, например, Ingress - это ответ на проблему отсутствия маршрутизации в LoadBalancer. Но самой большой проблемой Ingress, в свою очередь, является его зависимость от "проприетарных" объектов. В качестве напоминания, приведем в пример фрагмент для создания маршрутизации с использованием Apache APISIX:
apiVersion: apisix.apache.org/v2beta3            #1
kind: ApisixRoute                                #1
metadata:
  name: apisix-route
spec:
  http:
  - name: left
    match:
      paths:
      - "/left"
    backends:
      - serviceName: left
        servicePort: 80
  - name: right
    match:
      paths:
        - "/right"
    backends:
      - serviceName: right
        servicePort: 80#1: Проприетарные объекты
Проприетарные объекты определенно являются проблемой при осуществлении миграции. Хотя миграция от одного поставщика к другому встречается довольно редко, тем не менее она должна быть максимально плавной. При использовании проприетарных объектов сначала необходимо сопоставить старые объекты с новыми. Существует большая вероятность того, что мапирование "one-to-one" в данном случае может не получиться. Затем важно перевести спецификацию в новую модель, что превращает весь процесс в полноценный сложный проект.
Идея, лежащая в основе Gateway API, заключается в том, чтобы иметь четкое разделение между стандартными объектами и проприетарной реализацией.
API-шлюз
Шлюз API - это проект с открытым исходным кодом, управляемый сообществом SIG-NETWORK. Это набор ресурсов, которые моделируют сервисную сеть в Kubernetes. Такие ресурсы - GatewayClass, Gateway, HTTPRoute, TCPRoute, Service и т.д. - направлены на развитие сервисной сети Kubernetes с помощью ярких, гибких и клиентоориентированных интерфейсов, которые уже реализуются и поддерживаются многими крупными компаниями.
Исходя из вышеприведенного определения, важно упомянуть об одной из актуальных организационных проблем: разные роли должны управлять разным набором объектов.

Действительно, задачи оператора кластера и девелопера довольно сильно отличаются друг от друга. Это чем-то напоминает старые серверы приложений Java EE, которые предлагали спецификацию, организованную вокруг ролей: девелоперы, deploy-специалисты и операторы. ИМХО, наиболее существенное отличие заключается в том, что спецификация была ориентирована в основном на опыт девелоперов; остальное зависело от исполнителей. Шлюз API, в свою очередь, не оставляет без внимания ни одну сторону.
Настройка доступа к поду через API-шлюз
Давайте заменим упомянутый ранее Ingress на API-шлюз. Для этого необходимо выполнить следующие действия.
Установите новые CRD для шлюза
k apply -f https://github.com/kubernetes-sigs/gateway-api/releases/download/v0.5.0/standard-install.yamlУстановите Implementation
Я буду использовать Apache APISIX. Список возможных альтернатив представлен на сайте SIG.
helm install apisix apisix/apisix \
  --namespace ingress-apisix \
  --create-namespace \
  --devel \                                                                #1
  --set gateway.type=NodePort \                                            #2
  --set gateway.http.nodePort=30800 \                                      #2
  --set ingress-controller.enabled=true \                                  #2
  --set ingress-controller.config.kubernetes.enableApiGateway=true \       #3
  --set ingressPublishService="ingress-apisix/apisix-gateway"              #4#1: Без опции --devel Helm устанавливает последнюю версию, которая не работает с API-шлюза.
#2: Шлюз в любом случае должен быть доступен за пределами кластера.
#3: Здесь происходит волшебство!
#4: Мы вернемся к этому позже.
Проверим, что все работает:
k get all -n ingress-apisixpod/apisix-5fc9b45c69-cf42m                      1/1     Running   0          14m         #1
pod/apisix-etcd-0                                1/1     Running   0          14m         #2
pod/apisix-etcd-1                                1/1     Running   0          14m         #2
pod/apisix-etcd-2                                1/1     Running   0          14m         #2
pod/apisix-ingress-controller-6f8bd94d9d-wkzfn   1/1     Running   0          14m         #3
NAME                                TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)
service/apisix-admin                ClusterIP   10.96.69.19     <none>        9180/TCP
service/apisix-etcd                 ClusterIP   10.96.226.79    <none>        2379/TCP,2380/TCP
service/apisix-etcd-headless        ClusterIP   None            <none>        2379/TCP,2380/TCP
service/apisix-gateway              NodePort    10.96.101.224   <none>        80:30800/TCP#4
service/apisix-ingress-controller   ClusterIP   10.96.141.230   <none>        80/TCP#1: Непосредственно сам Apache API SIX.
#2: Apache API SIX хранит свою конфигурацию в etcd. На диаграмме по умолчанию запланировано три пода, что вполне практично для разрешения неполадок в распределенных системах.
#3: Контроллер Apache API SIX: Контроллер Kubernetes - это цикл управления, который преобразовывает существующее состояние в желаемое.
#4: Служба Apache APISIX: Это служба NodePortService, которую мы установили через Helm Chart. Это также имя, на которое мы ссылались во время установки ingressPublishService в Helm Chart. На данном этапе вся инфраструктура готова.
Реализация
Как уже упоминалось выше, API четко разделяет спецификацию и реализацию. Однако их необходимо как-то связать. Это ответственность объекта GatewayClass:
apiVersion: gateway.networking.k8s.io/v1alpha2          #1
kind: GatewayClass                                      #2
metadata:
  name: apisix-gateway-class                            #3
spec:
  controllerName: apisix.apache.org/gateway-controller  #4#1: Мы не используем последнюю версию специально, так как Apache API SIX работает с этой версией. Но даже не сомневайтесь, что в самом ближайшем будущем все обновится.
#2: Объект GatewayClass.
#3: Назовите его так, как вы хотите; однако позже мы будем использовать его для ссылки на класс шлюза.
#4: Имя контроллера зависит от реализации. В данном случае мы используем Apache APISIX.
Обратите внимание, что GatewayClass имеет область действия в масштабе всего кластера. Эта модель позволяет нам объявлять различные реализации API-шлюза и использовать их параллельно внутри одного и того же кластера.
Создание шлюза
Благодаря Apache API SIX здесь все довольно просто:
apiVersion: gateway.networking.k8s.io/v1alpha2          #1
kind: Gateway                                           #2
metadata:
  name: apisix-gateway
spec:
  gatewayClassName: apisix-gateway-class                #3
  listeners:                                            #4
    - name: http
      protocol: HTTP
      port: 80#1: Тот же namespace, что и выше.
#2: Объект Gateway.
#3: Ссылка на класс шлюза, обозначенная ранее.
# 4: Разрешите некоторые ограничения на этом уровне, чтобы оператор кластера имел возможность избежать нежелательного использования.
Предупреждение: API-шлюз предоставляет возможность динамического изменения порта на стороне оператора. На момент написания этой статьи распределение портов Apache APISIX является статическим. Очевидно, что динамическим он станет уже в ближайшем будущем - советуем следить за выпусками GitHub, чтобы быть в курсе изменений.
Маршрутизация, маршрутизация и еще раз маршрутизация
До этого момента речь велась об инфраструктуре, и наконец-то мы добрались до маршрутизации.
Я хочу поработать с тем же маршрутом, что и в предыдущем посте: бранчи  /left и right. Опустим описание последнего для краткости.
apiVersion: gateway.networking.k8s.io/v1alpha2          #1
kind: HTTPRoute                                         #2
metadata:
  name: left
spec:
  parentRefs:
    - name: apisix-gateway                              #3
  rules:
    - matches:                                          #4
      - path:                                           #4
          type: PathPrefix                              #4
          value: /left
      backendRefs:                                      #5
        - name: left                                    #5
          port: 80                                      #5- То же пространство имен, что и выше. 
- Объект HTTPRoute. 
- Ссылка на Gateway, созданный выше. 
- Совпадение правил (rules). В нашем случае мы сопоставляем префикс пути, но возможны разные вариации правил. Вы можете сопоставлять их на базе параметра запроса, заголовка и т.д. 
- "Вышестоящий" сервер для переадресации. В предыдущем посте мы как раз давали определение leftService. 
Проверяем в работе
Отстроив процессы маршрутизации, самое время проверить как все работает.
curl localhost:30800/leftВо время установки Helm chart, мы дали команду Apache APISIX создать службу NodePort на порту 30800. Таким образом, мы можем использовать порт для доступа к сервису за пределами кластера.
leftПодведем итоги
Существует множество вариантов для доступа к модулю извне кластера. CNCF осветили большую часть актуальных на данный момент альтернатив.
API-шлюз - это новинка в индустрии. Спецификация все еще находится на стадии разработки, а продукты - на разных этапах внедрения. По этой причине еще слишком рано переносить все свое производство на API. Тем не менее, мы настоятельно рекомендуем следить за процессами обновления и модернизации, ибо мы убедились в списке очевидных преимуществ по сравнению с предыдущими подходами.
Полный исходный код этого поста можно найти на GitHub.
P.S.: Кстати, подписывайтесь на наш телеграм-канал DevOps FM, кроме переводов мы публикуем там много авторских статей и новостей по теме DevOps: добро пожаловать к нам в комьюнити)
 
          