Envoy Gateway — это контроллер Gateway API для Kubernetes, который использует Envoy Proxy для обработки входящего трафика. С его помощью можно публиковать HTTP, HTTPS, gRPC, TCP и UDP-сервисы, настраивать маршрутизацию по доменам и путям, управлять TLS и применять политики трафика через стандартные Kubernetes-ресурсы.
Gateway API можно рассматривать как развитие Ingress. Вместо одного ресурса Ingress используются несколько объектов с разными зонами ответственности:
-
GatewayClass— указывает, какой контроллер будет обслуживать шлюзы. -
Gateway— описывает точку входа: порты, протоколы и TLS-настройки. -
HTTPRoute— задает правила маршрутизации HTTP-трафика к сервисам. -
GRPCRoute,TCPRoute,UDPRoute,TLSRoute— используются для других типов трафика.
Envoy Gateway отслеживает эти ресурсы и на их основе создает Envoy Proxy, который принимает внешний трафик и направляет его к сервисам внутри кластера.
Установка
Для установки Envoy Gateway откройте панель управления кластером, перейдите во вкладку «Дополнения» и выберите Envoy Gateway.
В открывшемся мастере установки можно оставить параметры по умолчанию или включить продвинутую установку и изменить values.yaml. Для начала работы достаточно настроек по умолчанию.
Нажмите «Установить» и дождитесь завершения установки. После этого проверьте, что поды Envoy Gateway запущены:
kubectl get pods -n envoy-gateway-system
Все поды должны находиться в статусе Running.
Также можно проверить, что в кластере появились ресурсы Gateway API:
kubectl api-resources | grep gateway.networking.k8s.io
Пример использования
Рассмотрим пример, в котором Envoy Gateway будет принимать HTTP-трафик на одном внешнем IP-адресе и направлять запросы в два разных сервиса:
-
http://app.example.com/service1— в сервисservice1; -
http://app.example.com/service2— в сервисservice2.
Для примера создадим отдельный неймспейс:
kubectl create namespace envoy-example
Создание ConfigMap
Создайте файл configmap.yaml с HTML-страницами для двух сервисов:
apiVersion: v1
kind: ConfigMap
metadata:
name: nginx-pages
namespace: envoy-example
data:
service1.html: |
<html>
<head><title>Service 1</title></head>
<body><h1>Service 1</h1></body>
</html>
service2.html: |
<html>
<head><title>Service 2</title></head>
<body><h1>Service 2</h1></body>
</html>
Примените манифест:
kubectl apply -f configmap.yaml
Создание Deployment и Service
Создайте файл service1.yaml:
apiVersion: apps/v1
kind: Deployment
metadata:
name: service1
namespace: envoy-example
spec:
replicas: 2
selector:
matchLabels:
app: service1
template:
metadata:
labels:
app: service1
spec:
containers:
- name: nginx
image: nginx:latest
ports:
- containerPort: 80
volumeMounts:
- name: html
mountPath: /usr/share/nginx/html
volumes:
- name: html
configMap:
name: nginx-pages
items:
- key: service1.html
path: index.html
---
apiVersion: v1
kind: Service
metadata:
name: service1
namespace: envoy-example
spec:
selector:
app: service1
ports:
- name: http
port: 80
targetPort: 80
type: ClusterIP
Создайте файл service2.yaml:
apiVersion: apps/v1
kind: Deployment
metadata:
name: service2
namespace: envoy-example
spec:
replicas: 2
selector:
matchLabels:
app: service2
template:
metadata:
labels:
app: service2
spec:
containers:
- name: nginx
image: nginx:latest
ports:
- containerPort: 80
volumeMounts:
- name: html
mountPath: /usr/share/nginx/html
volumes:
- name: html
configMap:
name: nginx-pages
items:
- key: service2.html
path: index.html
---
apiVersion: v1
kind: Service
metadata:
name: service2
namespace: envoy-example
spec:
selector:
app: service2
ports:
- name: http
port: 80
targetPort: 80
type: ClusterIP
Примените манифесты:
kubectl apply -f service1.yaml kubectl apply -f service2.yaml
Проверьте, что поды запущены:
kubectl get pods -n envoy-example
Создание GatewayClass
GatewayClass связывает Gateway API с контроллером Envoy Gateway. Создайте файл gatewayclass.yaml:
apiVersion: gateway.networking.k8s.io/v1
kind: GatewayClass
metadata:
name: envoy-gateway
spec:
controllerName: gateway.envoyproxy.io/gatewayclass-controller
Примените манифест:
kubectl apply -f gatewayclass.yaml
Проверьте статус:
kubectl get gatewayclass envoy-gateway
В колонке ACCEPTED должно быть значение True. Это означает, что Envoy Gateway принял GatewayClass и будет обслуживать связанные с ним ресурсы Gateway.
Создание Gateway
Gateway описывает внешний вход в приложение. Создайте файл gateway.yaml:
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
name: app-gateway
namespace: envoy-example
spec:
gatewayClassName: envoy-gateway
listeners:
- name: http
protocol: HTTP
port: 80
allowedRoutes:
namespaces:
from: Same
Примените манифест:
kubectl apply -f gateway.yaml
Когда Gateway будет создан, Envoy Gateway развернет Envoy Proxy и балансировщик нагрузки. Создание балансировщика можно отследить в панели управления или проверить командой:
kubectl get gateway app-gateway -n envoy-example
Дождитесь, когда в колонке PROGRAMMED появится значение True, а в колонке ADDRESS — внешний IP-адрес.
Также можно посмотреть созданный сервис:
kubectl get svc -n envoy-gateway-system \ -l gateway.envoyproxy.io/owning-gateway-namespace=envoy-example,gateway.envoyproxy.io/owning-gateway-name=app-gateway
Envoy Gateway по умолчанию создает балансировщик для каждого Gateway. Поэтому отдельный манифест Service типа LoadBalancer, как в классическом сценарии с Ingress-контроллером, не требуется.
Создание HTTPRoute
HTTPRoute задает правила маршрутизации. Создайте файл httproute.yaml:
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: app-route
namespace: envoy-example
spec:
parentRefs:
- name: app-gateway
hostnames:
- app.example.com
rules:
- matches:
- path:
type: PathPrefix
value: /service1
filters:
- type: URLRewrite
urlRewrite:
path:
type: ReplacePrefixMatch
replacePrefixMatch: /
backendRefs:
- name: service1
port: 80
- matches:
- path:
type: PathPrefix
value: /service2
filters:
- type: URLRewrite
urlRewrite:
path:
type: ReplacePrefixMatch
replacePrefixMatch: /
backendRefs:
- name: service2
port: 80
Примените манифест:
kubectl apply -f httproute.yaml
Проверьте, что маршрут принят:
kubectl get httproute app-route -n envoy-example -o yaml
В статусе ресурса должно быть:
status: "True" type: Accepted
В этом манифесте HTTPRoute принимает запросы с доменом app.example.com и направляет их в разные сервисы по префиксу пути. Фильтр URLRewrite заменяет префиксы /service1 и /service2 на /, чтобы Nginx внутри каждого сервиса отдавал свою главную страницу.
Проверка работы
Получите внешний IP-адрес Gateway:
kubectl get gateway app-gateway -n envoy-example
Пропишите этот IP-адрес в DNS-настройках домена app.example.com в виде A-записи. После обновления DNS проверьте доступность сервисов:
curl http://app.example.com/service1 curl http://app.example.com/service2
Если DNS еще не обновился, можно выполнить проверку по IP-адресу, передав заголовок Host:
curl -H "Host: app.example.com" http://<EXTERNAL_IP>/service1
curl -H "Host: app.example.com" http://<EXTERNAL_IP>/service2
В ответе должны отображаться страницы Service 1 и Service 2.
Удаление примера
Чтобы удалить ресурсы, созданные в примере, выполните:
kubectl delete namespace envoy-example kubectl delete gatewayclass envoy-gateway
Дополнение Envoy Gateway при этом останется установленным в кластере. Удалить его можно во вкладке «Дополнения» в панели управления кластером.
Миграция с Nginx Ingress на Envoy Gateway
Envoy Gateway можно развернуть рядом с Nginx Ingress и переносить маршруты постепенно. Такой подход позволяет сначала проверить ресурсы Gateway API на отдельном внешнем IP-адресе, а затем переключить DNS-записи или трафик на новый Gateway.
Для автоматической конвертации Ingress-ресурсов можно использовать утилиту ingress2gateway. Она читает существующие Ingress-ресурсы из кластера и выводит эквивалентные ресурсы Gateway API: Gateway, HTTPRoute и другие объекты.
ingress2gateway помогает подготовить миграцию, но не заменяет ручную проверку. Некоторые аннотации Nginx Ingress могут быть не поддержаны или потребовать ручной настройки после конвертации.
Требования
Перед миграцией подготовьте кластер:
-
установите Envoy Gateway;
-
создайте GatewayClass для Envoy Gateway;
-
проверьте, что исходные Ingress-ресурсы работают через Nginx Ingress.
Проверьте, что в кластере есть нужные классы:
kubectl get ingressclass kubectl get gatewayclass
В выводе должны быть:
-
IngressClassс именемnginx; -
GatewayClassс именемenvoy-gateway.
Установка ingress2gateway
Если на локальной машине установлен Go, установите ingress2gateway командой:
go install github.com/kubernetes-sigs/ingress2gateway@v1.0.0
После установки бинарный файл будет доступен в директории $(go env GOPATH)/bin. Убедитесь, что эта директория добавлена в PATH.
Также можно установить ingress2gateway через Homebrew:
brew install ingress2gateway
Или скачать готовый бинарный файл со страницы релизов проекта.
Исходный пример
В примере ниже миграция выполняется для приложения, которое уже опубликовано через Nginx Ingress.
В кластере есть неймспейс ingress-migration-demo. В нем находятся:
-
Ingress
migration-source; -
Service
service1иservice2; -
два правила маршрутизации для домена
ingress-migration.example.com: -
/service1направляет трафик вservice1; -
/service2направляет трафик вservice2.
Проверьте исходный Ingress:
kubectl get ingress -n ingress-migration-demo
В колонке CLASS должно быть значение nginx.
Конвертация Ingress-ресурсов
Чтобы сконвертировать этот Ingress в ресурсы Gateway API, выполните:
ingress2gateway print \
--providers=ingress-nginx \
--emitter=envoy-gateway \
--ingress-nginx-ingress-class=nginx \
--namespace=ingress-migration-demo > gateway-migration.yaml
В этой команде:
-
print— режим, в котором ingress2gateway выводит сгенерированные ресурсы в стандартный вывод. За счет перенаправления>результат сохраняется в файлgateway-migration.yaml. -
--providers=ingress-nginx— указывает тип исходного Ingress-контроллера. В этом примере исходные маршруты обслуживает Nginx Ingress, поэтому используется значениеingress-nginx. -
--emitter=envoy-gateway— указывает, для какого Gateway API-контроллера подготовить результат. В этом примере целевой контроллер — Envoy Gateway. -
--ingress-nginx-ingress-class=nginx— выбирает только Ingress-ресурсы классаnginx. Такой класс создает аддон Nginx Ingress в Timeweb Cloud. -
--namespace=ingress-migration-demo— ограничивает чтение ресурсов неймспейсомingress-migration-demo, где находится исходный Ingress из примера.
Откройте файл gateway-migration.yaml и проверьте сгенерированные ресурсы перед применением.
Проверьте gatewayClassName у ресурса Gateway. ingress2gateway может сгенерировать это значение на основе имени исходного IngressClass. Например, если исходный Ingress использует класс nginx, в сгенерированном Gateway может появиться:
spec:
gatewayClassName: nginx
Envoy Gateway не будет обрабатывать такой Gateway, если в кластере нет GatewayClass с именем nginx. Для GatewayClass из примера замените значение на envoy-gateway:
spec:
gatewayClassName: envoy-gateway
Применение ресурсов Gateway API
После проверки примените файл:
kubectl apply -f gateway-migration.yaml
Проверьте, что Gateway создан и получил внешний IP-адрес:
kubectl get gateway -A
Тестирование перед переключением трафика
Пока DNS-записи указывают на старый Nginx Ingress, новый Gateway можно проверить по внешнему IP-адресу с заголовком Host:
curl -H "Host: app.example.com" http://<EXTERNAL_IP>/<path>
Где:
-
app.example.com— домен изHTTPRoute; -
<EXTERNAL_IP>— IP-адрес нового Gateway; -
<path>— путь, который должен обрабатываться маршрутом.
Сравните ответы старого Ingress и нового Gateway.
Если все работает корректно, можно изменить DNS-записи на IP нового балансировщика.