[Перевод] Основное про API-шлюз в Kubernetes
Существует множество альтернатив для доступа к модулю извне кластера. Шлюз 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 с помощью ярких, гибких и клиентоориентированных интерфейсов, которые уже реализуются и поддерживаются многими крупными компаниями.
— Kubernetes Gateway API Introduction
Исходя из вышеприведенного определения, важно упомянуть об одной из актуальных организационных проблем: разные роли должны управлять разным набором объектов.
Действительно, задачи оператора кластера и девелопера довольно сильно отличаются друг от друга. Это чем-то напоминает старые серверы приложений 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-apisix
pod/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 9180/TCP
service/apisix-etcd ClusterIP 10.96.226.79 2379/TCP,2380/TCP
service/apisix-etcd-headless ClusterIP None 2379/TCP,2380/TCP
service/apisix-gateway NodePort 10.96.101.224 80:30800/TCP#4
service/apisix-ingress-controller ClusterIP 10.96.141.230 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: добро пожаловать к нам в комьюнити)