Перейти к содержимому

Envoy Gateway: как я перестал бояться annotations и полюбил Gateway API

Константин Потапов
25 мин

История о том, как 47 строк YAML-магии Nginx Ingress превратились в 15 строк понятной конфигурации. Envoy Gateway — это не просто новый инструмент, это избавление от боли.

История: как я потратил 6 часов на одну annotation

Это было летом 2024 года. Пятница, 18:30. У меня в production упал canary deployment.

Задача казалась простой: направить 10% трафика на новую версию API, остальное — на старую. Тестирование перед полным раскатом. Стандартная практика.

Реальность оказалась жестокой.

Я использовал Nginx Ingress. Нашёл в документации раздел про canary deployments через annotations. Скопировал пример:

# ❌ То, что я думал будет работать
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: api-canary
  annotations:
    nginx.ingress.kubernetes.io/canary: "true"
    nginx.ingress.kubernetes.io/canary-weight: "10"
spec:
  rules:
    - host: api.company.com
      http:
        paths:
          - path: /v2
            backend:
              service:
                name: api-v2
                port:
                  number: 8080

Применил. Проверил. 100% трафика идёт на новую версию.

"Странно, — подумал я, — наверное опечатка в weight". Поменял на 90. Перезапустил. Всё ещё 100% на v2.

Следующие 4 часа я:

  • Перечитывал документацию 7 раз
  • Гуглил "nginx ingress canary not working" (53 результата, ни один не помогал)
  • Проверял версию Nginx Ingress Controller (оказалось, надо 0.22+, у меня 0.21)
  • Обновлял контроллер (сломал ещё 2 Ingress-ресурса в процессе)
  • Обнаружил, что для canary нужен отдельный Ingress ресурс с тем же host, но другим именем
  • Понял, что я неправильно указал path matching (нужен regex, а не prefix)

В 23:00 я наконец заставил это работать. 47 строк YAML + 12 annotations. Половину смысла я не понимал.

А утром в понедельник: "Слушай, давайте ещё добавим JWT-авторизацию на этот endpoint?"

Я понял, что мне конец.


Триумф: 15 строк вместо 47, и всё понятно

Через месяц я узнал про Envoy Gateway. Скептически отнёсся: "Ещё один инструмент, который надо учить".

Но решил попробовать на dev-кластере.

Тот же canary deployment на Envoy Gateway:

# ✅ То, что работает с первого раза
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: api-route
spec:
  parentRefs:
    - name: my-gateway
  hostnames:
    - api.company.com
  rules:
    - matches:
        - path:
            type: PathPrefix
            value: /v2
      backendRefs:
        - name: api-v1 # 90% трафика
          port: 8080
          weight: 90
        - name: api-v2 # 10% трафика (canary)
          port: 8080
          weight: 10

15 строк. Ноль annotations. Заработало с первого раза.

Я смотрел на этот YAML и не верил. Это было слишком просто.

Но самое магическое произошло дальше.

Через неделю Product Owner: "Добавь JWT-авторизацию".

С Nginx Ingress это означало бы: ещё 5 annotations, внешний auth service, настройка CORS, дебаггинг почему токены не проходят.

С Envoy Gateway:

# Добавил 12 строк — и JWT работает
apiVersion: gateway.envoyproxy.io/v1alpha1
kind: SecurityPolicy
metadata:
  name: jwt-policy
spec:
  targetRef:
    kind: HTTPRoute
    name: api-route
  jwt:
    providers:
      - name: auth0
        issuer: https://company.auth0.com/
        audiences:
          - api://myapp
        remoteJWKS:
          uri: https://company.auth0.com/.well-known/jwks.json

Применил. Заработало. С первого раза.

Никаких магических строк в annotations. Никакого гугления "как правильно экранировать URL в YAML-строке". Всё типизировано, всё валидируется, всё понятно.

В тот момент я понял: я больше никогда не вернусь к Nginx Ingress annotations.


Что такое Envoy Gateway (без воды)

Envoy Gateway — это Kubernetes-native API Gateway, построенный на трёх китах:

1. Envoy Proxy — движок, который не тупит

Это высокопроизводительный proxy от Lyft, который используют Google, Uber, Netflix. Тот самый Envoy, на котором работает Istio.

Что умеет из коробки:

  • HTTP/1.1, HTTP/2, HTTP/3, gRPC, WebSocket
  • Load balancing с умными алгоритмами (consistent hashing, least request)
  • Circuit breaking, retry, timeout — без плагинов
  • Rate limiting, JWT validation — нативно
  • Observability — метрики в Prometheus, трейсы в Jaeger, всё автоматически

Аналогия: Nginx — это Toyota Corolla. Надёжная, проверенная, но базовая. Envoy — это Tesla Model S. Современная, напичканная технологиями, но сложнее в освоении. Envoy Gateway — это Tesla с автопилотом. Вся мощь Envoy, но управление простое.

2. Gateway API — стандарт вместо хаоса

Представьте: Kubernetes выпустил новый официальный API для управления входящим трафиком. Не Ingress (ему уже 7 лет, и он устарел). Gateway API — это Ingress 2.0.

Ключевое отличие:

Ingress (старый)Gateway API (новый)
Строковые annotations (без проверок)Типизированные поля (валидация на лету)
Каждый контроллер — свой синтаксисЕдиный стандарт для всех
Переезд = переписывание annotationsПереезд = смена gatewayClassName
Advanced фичи = костылиAdvanced фичи = нативные CRD

Простыми словами: Ingress — это как слать письма с инструкциями курьеру. "Если увидишь дом с красной крышей, передай посылку Ивану". Gateway API — это API с чётким контрактом. { "recipient": "Ivan", "address": { "color": "red" } }. Валидируется, не сломается.

3. Control Plane — оркестр вместо хаоса

Это мозг системы. Вы пишете декларативную конфигурацию (Gateway, HTTPRoute). Control Plane:

  • Создаёт и управляет Envoy Proxy pods
  • Транслирует ваши манифесты в конфигурацию Envoy (xDS протокол)
  • Обновляет конфигурацию без рестарта proxy (hot reload)
  • Интегрируется с cert-manager, external-dns, Prometheus

Вы описываете "что хотите". Он делает "как достичь".

Envoy ProxyKubernetesGateway APIcert-manager

Три кейса, когда Envoy Gateway спасёт вашу задницу

Кейс 1: Canary Deployment (уже рассказал, но повторю)

Без Envoy Gateway:

  • 47 строк YAML
  • 12 annotations
  • 6 часов дебаггинга
  • Документация противоречит реальности
  • Один символ не в том месте — всё ломается

С Envoy Gateway:

  • 15 строк YAML
  • 0 annotations
  • Работает с первого раза
  • Если ошиблись — Kubernetes API выдаст ошибку до применения
Nginx Ingress
Envoy Gateway
Строк YAML
47 строк
15 строк
68%
Annotations
12 магических строк
0
100%
Время на настройку
6 часов + гугл
10 минут
67%

Кейс 2: JWT + Rate Limiting за 5 минут

Задача: API должен проверять JWT токены и лимитировать 100 запросов в минуту на пользователя.

Nginx Ingress: Добавляете 3 annotations для JWT (если контроллер это поддерживает). Для rate limiting — разворачиваете Redis, настраиваете Lua-скрипт, молитесь чтобы заработало.

Envoy Gateway: Два манифеста. Всё из коробки.

# JWT — 12 строк
apiVersion: gateway.envoyproxy.io/v1alpha1
kind: SecurityPolicy
metadata:
  name: jwt-policy
spec:
  targetRef:
    kind: HTTPRoute
    name: api-route
  jwt:
    providers:
      - name: auth0
        issuer: https://mycompany.auth0.com/
        audiences:
          - api://myapp
        remoteJWKS:
          uri: https://mycompany.auth0.com/.well-known/jwks.json
 
---
# Rate Limiting — 15 строк
apiVersion: gateway.envoyproxy.io/v1alpha1
kind: BackendTrafficPolicy
metadata:
  name: rate-limit
spec:
  targetRef:
    kind: HTTPRoute
    name: api-route
  rateLimit:
    type: Local
    local:
      rules:
        - clientSelectors:
            - headers:
                - name: x-user-id
                  type: Distinct
          limit:
            requests: 100
            unit: Minute

Применили. Заработало.

Envoy Gateway:

  • Проверяет JWT на каждом запросе
  • Кеширует публичные ключи (JWKS) автоматически
  • Лимитирует запросы в памяти (без Redis!)
  • Экспортирует метрики (сколько отклонено, сколько прошло)

И всё это без единой строки кода на вашей стороне.

Кейс 3: gRPC с метриками и health checks

Проблема: У вас gRPC-сервис. Nginx Ingress поддерживает gRPC, но:

  • Нет gRPC health checks (придётся писать костыль)
  • Метрики — вручную
  • Load balancing — базовый round-robin

Envoy Gateway понимает gRPC нативно:

apiVersion: gateway.networking.k8s.io/v1
kind: GRPCRoute
metadata:
  name: user-service
spec:
  parentRefs:
    - name: my-gateway
  hostnames:
    - grpc.example.com
  rules:
    - matches:
        - method:
            service: myapp.v1.UserService
            method: GetUser
      backendRefs:
        - name: user-service
          port: 9090

Бонусы из коробки:

  • Метрики per gRPC method (latency GetUser, error rate CreateUser)
  • gRPC health checks (настраиваются автоматически)
  • Retry для failed запросов
  • Circuit breaking при перегрузке

Envoy изначально создавался в Lyft для gRPC-сервисов. Это его родная стихия. Nginx добавил поддержку gRPC позже, как "дополнительную фичу".


Когда Envoy Gateway НЕ нужен (честно)

Я не евангелист. Envoy Gateway — мощный инструмент, но не для всех.

НЕ используйте Envoy Gateway, если:

У вас монолит на 1-2 сервиса — Nginx Ingress проще и быстрее настроить

Kubernetes < 1.25 — Gateway API v1 появился только в 1.25

Команда не готова учить новое — переход требует переписывания всех Ingress в HTTPRoute

Нужна полноценная Service Mesh — если вам нужен mTLS между всеми сервисами, возьмите Istio

Критична максимальная простота — "один Ingress на весь кластер" проще, чем разбираться в Gateway/HTTPRoute/Policy

Используйте Envoy Gateway, если:

Нужны advanced фичи — canary, A/B testing, JWT, rate limiting, circuit breaking

Важна портируемость — сегодня Envoy Gateway, завтра Istio Gateway, манифесты одинаковые

Устали от vendor lock-in — annotations каждого Ingress Controller уникальны

Планируете расти — Envoy Gateway — хороший шаг перед полноценной Service Mesh

Нужна observability — метрики, трейсы, логи из коробки


Архитектура: как это работает внутри

Envoy Gateway — это два слоя: Control Plane (мозг) и Data Plane (мускулы).

┌─────────────────────────────────────────────────────┐
│  Kubernetes Cluster                                 │
├─────────────────────────────────────────────────────┤
│                                                     │
│  ┌─────────────────────────────────┐                │
│  │ Control Plane (envoy-gateway)   │                │
│  │                                 │                │
│  │  ┌──────────────────────────┐   │                │
│  │  │ Gateway API Controller   │   │                │
│  │  │ (watches Gateway, Route) │   │                │
│  │  └────────┬─────────────────┘   │                │
│  │           │                     │                │
│  │           ▼                     │                │
│  │  ┌──────────────────────────┐   │                │
│  │  │ xDS Translator           │   │                │
│  │  │ (Gateway API → Envoy cfg)│   │                │
│  │  └────────┬─────────────────┘   │                │
│  │           │ xDS (gRPC)          │                │
│  └───────────┼─────────────────────┘                │
│              │                                      │
│              ▼                                      │
│  ┌─────────────────────────────────┐                │
│  │ Data Plane (envoy-proxy pods)   │                │
│  │                                 │                │
│  │  ┌────────┐  ┌────────┐         │                │
│  │  │ Envoy  │  │ Envoy  │  ...    │                │
│  │  │ Pod 1  │  │ Pod 2  │         │                │
│  │  └───┬────┘  └───┬────┘         │                │
│  │      │           │              │                │
│  └──────┼───────────┼──────────────┘                │
│         │           │                               │
│         │  Ingress Traffic (HTTP/gRPC)              │
│         ▼           ▼                               │
│  ┌─────────────────────────────────┐                │
│  │ Backend Services (Pods)         │                │
│  │  app-v1, app-v2, user-service   │                │
│  └─────────────────────────────────┘                │
│                                                     │
└─────────────────────────────────────────────────────┘

Control Plane (один pod в namespace envoy-gateway-system):

  • Следит за вашими Gateway, HTTPRoute, GRPCRoute манифестами
  • Транслирует их в конфигурацию Envoy (xDS протокол)
  • Управляет lifecycle Envoy Proxy pods (создаёт, обновляет, удаляет)

Data Plane (N pods Envoy Proxy):

  • Принимают трафик из интернета
  • Применяют routing rules, rate limiting, JWT validation
  • Проксируют на backend сервисы
  • Экспортируют метрики, трейсы, логи

Ключевое отличие от Nginx Ingress:

Nginx Ingress:

User → Nginx Pod (читает Ingress YAML) → Service → Pods

Envoy Gateway:

User → Envoy Proxy Pods (получают config от Control Plane) → Service → Pods
          ↑
    xDS config (gRPC)
          ↑
    Control Plane (читает Gateway API YAML)

Преимущества:

  • Data Plane масштабируется независимо (больше Envoy pods = больше throughput)
  • Hot reload конфигурации без рестарта proxy
  • Единый формат конфига (xDS) — можно заменить Envoy Gateway на другой контроллер

Практика: от нуля до canary за 15 минут

Хватит теории. Давайте руками.

Шаг 1: Установка (3 минуты)

Требования:

  • Kubernetes 1.25+
  • kubectl настроен

Устанавливаем через kubectl:

# Gateway API CRDs
kubectl apply -f https://github.com/kubernetes-sigs/gateway-api/releases/download/v1.0.0/standard-install.yaml
 
# Envoy Gateway
kubectl apply -f https://github.com/envoyproxy/gateway/releases/download/latest/install.yaml
 
# Проверяем
kubectl get pods -n envoy-gateway-system
 
# Должен быть pod: envoy-gateway-xxxxx (STATUS: Running)

После установки появится GatewayClass с именем envoy-gateway. Это шаблон, из которого будут создаваться ваши Gateway.

Шаг 2: Деплоим тестовое приложение (2 минуты)

Создадим две версии echo-сервиса для демонстрации canary.

# Создаём файл echo-app.yaml
cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: Namespace
metadata:
  name: demo
 
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: echo-v1
  namespace: demo
spec:
  replicas: 2
  selector:
    matchLabels:
      app: echo
      version: v1
  template:
    metadata:
      labels:
        app: echo
        version: v1
    spec:
      containers:
        - name: echo
          image: hashicorp/http-echo:latest
          args: ["-text=Hello from v1"]
          ports:
            - containerPort: 5678
 
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: echo-v2
  namespace: demo
spec:
  replicas: 2
  selector:
    matchLabels:
      app: echo
      version: v2
  template:
    metadata:
      labels:
        app: echo
        version: v2
    spec:
      containers:
        - name: echo
          image: hashicorp/http-echo:latest
          args: ["-text=Hello from v2 (canary!)"]
          ports:
            - containerPort: 5678
 
---
apiVersion: v1
kind: Service
metadata:
  name: echo-v1
  namespace: demo
spec:
  selector:
    app: echo
    version: v1
  ports:
    - port: 80
      targetPort: 5678
 
---
apiVersion: v1
kind: Service
metadata:
  name: echo-v2
  namespace: demo
spec:
  selector:
    app: echo
    version: v2
  ports:
    - port: 80
      targetPort: 5678
EOF
 
# Проверяем
kubectl get pods -n demo
# Должно быть 4 пода: echo-v1-xxx (2 шт), echo-v2-xxx (2 шт)

Шаг 3: Создаём Gateway (2 минуты)

Gateway — это точка входа для трафика. Аналог LoadBalancer.

cat <<EOF | kubectl apply -f -
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
  name: demo-gateway
  namespace: demo
spec:
  gatewayClassName: envoy-gateway
  listeners:
    - name: http
      protocol: HTTP
      port: 80
      allowedRoutes:
        namespaces:
          from: Same
EOF
 
# Ждём, пока Gateway станет готовым
kubectl wait --for=condition=Programmed gateway/demo-gateway -n demo --timeout=300s
 
# Получаем IP/Hostname
export GATEWAY_IP=$(kubectl get gateway demo-gateway -n demo -o jsonpath='{.status.addresses[0].value}')
echo "Gateway IP: $GATEWAY_IP"

В облачных K8s (GKE, EKS, AKS) Gateway получит LoadBalancer с внешним IP. В локальных кластерах (minikube, kind) используйте kubectl port-forward для доступа.

Шаг 4: Создаём HTTPRoute с canary (3 минуты)

Настроим распределение трафика 90% → v1, 10% → v2.

cat <<EOF | kubectl apply -f -
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: echo-route
  namespace: demo
spec:
  parentRefs:
    - name: demo-gateway
  hostnames:
    - echo.example.com
  rules:
    - matches:
        - path:
            type: PathPrefix
            value: /
      backendRefs:
        - name: echo-v1
          port: 80
          weight: 90  # 90% трафика на v1
        - name: echo-v2
          port: 80
          weight: 10  # 10% трафика на v2 (canary)
EOF
 
# Проверяем статус
kubectl get httproute -n demo
# STATUS: Accepted

Шаг 5: Тестируем (5 минут)

Делаем 20 запросов и смотрим распределение:

# Если у вас внешний IP:
for i in {1..20}; do
  curl -H "Host: echo.example.com" http://$GATEWAY_IP/
done
 
# Если используете port-forward (локальный кластер):
kubectl port-forward -n demo svc/demo-gateway-envoy-gateway 8080:80 &
for i in {1..20}; do
  curl -H "Host: echo.example.com" http://localhost:8080/
done
 
# Результат (примерно):
# Hello from v1 (18 раз из 20 ≈ 90%)
# Hello from v2 (canary!) (2 раза из 20 ≈ 10%)

🎉 Поздравляю! Вы только что настроили canary deployment за 15 минут.

Никаких магических annotations. Никакого гугления. Всё работает.


Бонус: добавляем rate limiting за 2 минуты

Защитим наше API от DDoS. Лимит: 5 запросов в минуту на пользователя.

cat <<EOF | kubectl apply -f -
apiVersion: gateway.envoyproxy.io/v1alpha1
kind: BackendTrafficPolicy
metadata:
  name: rate-limit
  namespace: demo
spec:
  targetRef:
    group: gateway.networking.k8s.io
    kind: HTTPRoute
    name: echo-route
  rateLimit:
    type: Local
    local:
      rules:
        - clientSelectors:
            - headers:
                - name: x-user-id
                  type: Distinct
          limit:
            requests: 5
            unit: Minute
EOF
 
# Тестируем (делаем 10 запросов с одним user_id)
for i in {1..10}; do
  curl -H "Host: echo.example.com" -H "x-user-id: user123" http://$GATEWAY_IP/
done
 
# Первые 5 запросов: HTTP 200 OK
# Следующие 5: HTTP 429 Too Many Requests

Работает. Без Redis. Без внешних зависимостей.

Envoy хранит счётчики в памяти и синхронизирует между репликами.

Rate limiting работает из коробки. Для production можете переключиться на Global mode с Redis для синхронизации между несколькими Gateway pods.


Подводные камни (чтобы вы не наступили)

Подводный камень 1: Gateway API версии

Проблема: Gateway API активно развивается. Experimental фичи (SecurityPolicy, BackendTrafficPolicy) могут меняться.

Решение:

  • Используйте стабильные v1 ресурсы (Gateway, HTTPRoute, GRPCRoute)
  • Для experimental фичей проверяйте compatibility matrix
  • Фиксируйте версию Envoy Gateway в production

Подводный камень 2: TLS сертификаты

Проблема: Вы настроили HTTPS, но сертификаты нужно обновлять вручную каждые 90 дней.

Решение: Используйте cert-manager для автоматического renewal:

# Установка cert-manager
kubectl apply -f https://github.com/cert-manager/cert-manager/releases/download/v1.13.0/cert-manager.yaml
 
# ClusterIssuer для Let's Encrypt
cat <<EOF | kubectl apply -f -
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
  name: letsencrypt-prod
spec:
  acme:
    server: https://acme-v02.api.letsencrypt.org/directory
    email: admin@example.com
    privateKeySecretRef:
      name: letsencrypt-prod-key
    solvers:
      - http01:
          gatewayHTTPRoute:
            parentRefs:
              - name: demo-gateway
                namespace: demo
EOF
 
# Gateway с TLS
cat <<EOF | kubectl apply -f -
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
  name: demo-gateway
  namespace: demo
  annotations:
    cert-manager.io/cluster-issuer: letsencrypt-prod
spec:
  gatewayClassName: envoy-gateway
  listeners:
    - name: https
      protocol: HTTPS
      port: 443
      hostname: "*.example.com"
      tls:
        mode: Terminate
        certificateRefs:
          - name: example-com-tls
EOF

cert-manager автоматически создаст и будет обновлять сертификаты.

Подводный камень 3: Observability

Проблема: В production нужно видеть метрики (latency, error rate, throughput).

Решение: Envoy экспортирует метрики в Prometheus из коробки.

Ключевые метрики:

  • envoy_http_downstream_rq_total — общее количество запросов
  • envoy_http_downstream_rq_xx — запросы по статус-кодам (2xx, 4xx, 5xx)
  • envoy_http_downstream_rq_time — latency (p50, p95, p99)
  • envoy_cluster_upstream_rq_retry — количество retry

Готовый Grafana dashboard: Envoy Gateway Overview


Production Checklist (чтобы не проснуться ночью от алертов)

Перед запуском в production пройдитесь по чеклисту:

  • High Availability: минимум 2 реплики Envoy Proxy pods
  • Resource Limits: CPU/memory limits на Envoy pods (чтобы не пожрали весь кластер)
  • TLS Termination: cert-manager настроен для HTTPS
  • Rate Limiting: защита от DDoS и злоупотреблений
  • Circuit Breaking: защита backend от каскадных падений
  • Observability: метрики в Prometheus, алерты настроены
  • Graceful Shutdown: preStop hooks для завершения активных соединений
  • Security Policies: JWT validation, CORS, request validation
  • Backup Configuration: все манифесты в Git
  • Testing: integration тесты для критичных routes

Пример production Gateway

apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
  name: production-gateway
  namespace: production
  annotations:
    cert-manager.io/cluster-issuer: letsencrypt-prod
spec:
  gatewayClassName: envoy-gateway
  listeners:
    # HTTP → HTTPS redirect
    - name: http
      protocol: HTTP
      port: 80
      hostname: "*.example.com"
 
    # HTTPS с автоматическими сертификатами
    - name: https
      protocol: HTTPS
      port: 443
      hostname: "*.example.com"
      tls:
        mode: Terminate
        certificateRefs:
          - name: wildcard-tls
 
---
# Автоматический редирект на HTTPS
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: https-redirect
  namespace: production
spec:
  parentRefs:
    - name: production-gateway
      sectionName: http
  hostnames:
    - "*.example.com"
  rules:
    - filters:
        - type: RequestRedirect
          requestRedirect:
            scheme: https
            statusCode: 301

Миграция с Nginx Ingress (без боли)

Вопрос от читателя: "У меня в production 30 Ingress ресурсов. Как мигрировать?"

Ответ: Постепенно. Не в лоб.

Стратегия "параллельный запуск"

Фаза 1: Proof of Concept (неделя)

  1. Установите Envoy Gateway параллельно с Nginx Ingress
  2. Создайте Gateway с отдельным LoadBalancer IP
  3. Мигрируйте один некритичный сервис на HTTPRoute
  4. Тестируйте неделю — мониторьте метрики, error rate, latency

Фаза 2: Traffic Split (2 недели)

  1. Настройте DNS weighted routing: 10% → Envoy Gateway, 90% → Nginx Ingress
  2. Мониторьте: error rate, latency, throughput
  3. Постепенно увеличивайте вес Envoy Gateway (10% → 25% → 50% → 75% → 100%)
  4. Откатывайте на Nginx при проблемах (DNS switch за 5 минут)

Фаза 3: Full Migration (месяц)

  1. Мигрируйте все сервисы по одному
  2. Удалите Nginx Ingress после 2 недель без инцидентов
  3. Задокументируйте новые паттерны для команды

Транслируем Ingress → HTTPRoute

Было (Nginx Ingress):

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: api-ingress
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: /$2
    nginx.ingress.kubernetes.io/rate-limit: "100"
spec:
  rules:
    - host: api.example.com
      http:
        paths:
          - path: /api(/|$)(.*)
            backend:
              service:
                name: api-service
                port:
                  number: 8080

Стало (Envoy Gateway):

apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: api-route
spec:
  parentRefs:
    - name: production-gateway
  hostnames:
    - api.example.com
  rules:
    - matches:
        - path:
            type: PathPrefix
            value: /api
      filters:
        - type: URLRewrite
          urlRewrite:
            path:
              type: ReplacePrefixMatch
              replacePrefixMatch: /
      backendRefs:
        - name: api-service
          port: 8080
 
---
# Rate limiting через отдельную политику
apiVersion: gateway.envoyproxy.io/v1alpha1
kind: BackendTrafficPolicy
metadata:
  name: api-rate-limit
spec:
  targetRef:
    kind: HTTPRoute
    name: api-route
  rateLimit:
    type: Local
    local:
      rules:
        - limit:
            requests: 100
            unit: Minute

Что изменилось:

  • ✅ Annotations → типизированные поля
  • ✅ Regex в path → явный PathPrefix
  • ✅ Rate limiting → отдельная политика (переиспользуется)
  • ✅ Валидация на уровне Kubernetes API

Это не про технологию. Это про свободу.

Когда я впервые настроил Envoy Gateway, я почувствовал облегчение.

Не восторг. Не эйфорию. Именно облегчение.

Облегчение от того, что больше не надо:

  • Гуглить "как правильно написать regex в nginx annotation"
  • Перечитывать документацию 7 раз, чтобы понять один параметр
  • Молиться, чтобы после апдейта контроллера не сломались annotations
  • Объяснять джуниору, почему "просто добавить canary" займёт 4 часа

Envoy Gateway — это не про "новую технологию".

Это про избавление от боли.

Боли, которую вы даже не замечали, потому что привыкли. Как привыкаешь к скрипу дверной петли — раздражает, но терпимо.

А потом смазываешь петлю. И понимаешь: боже, как же я раньше жил с этим скрипом?

Вот в чём сила Envoy Gateway:

Не в том, что он "быстрее" (хотя он быстрее). Не в том, что он "мощнее" (хотя он мощнее).

А в том, что он понятен.

Вы читаете HTTPRoute — и видите логику. Вы пишете SecurityPolicy — и она работает с первого раза. Вы добавляете RateLimit — и спите спокойно, зная что DDoS не убьёт ваш API.

Это свобода от магии.

Свобода от "а почему эта annotation не работает?". Свобода от "а где документация для этой версии контроллера?". Свобода от "а кто-нибудь вообще знает, как это настроить?".

Gateway API — это стандарт.

А стандарт означает:

  • Документация одинаковая для всех контроллеров
  • Валидация на уровне Kubernetes API
  • Миграция между реализациями без переписывания манифестов
  • Знания переносятся между проектами и компаниями

Вы не учите "Nginx Ingress annotations". Вы учите Kubernetes Gateway API.

И это знание работает с Envoy Gateway, Istio Gateway, Cilium Gateway, Kong Gateway.

Это инвестиция в будущее, а не привязка к vendor.


Начните сегодня

Я знаю, что вы думаете прямо сейчас.

"Звучит круто, но у меня нет времени разбираться с новым инструментом."

"В production Nginx Ingress. Работает. Зачем менять?"

"Когда-нибудь попробую. Добавлю в TODO."

Я вас прекрасно понимаю. Я думал так же.

Но вот что я понял после миграции:

Каждый день, который вы откладываете переход, вы:

  • Тратите лишние часы на отладку annotations
  • Ограничиваете себя возможностями старого API
  • Увеличиваете техдолг, который потом будет мигрировать сложнее

Не нужно мигрировать весь production прямо сейчас.

Начните с одного шага:

Ваше задание на сегодня (30 минут)

  1. Поднимите локальный кластер (minikube или kind)
  2. Установите Envoy Gateway (3 команды kubectl)
  3. Повторите пример из статьи (canary deployment)
  4. Почувствуйте разницу

Не читайте дальше — откройте терминал прямо сейчас.

# 1. Локальный кластер (если нет)
minikube start
# или
kind create cluster
 
# 2. Установка Envoy Gateway
kubectl apply -f https://github.com/kubernetes-sigs/gateway-api/releases/download/v1.0.0/standard-install.yaml
kubectl apply -f https://github.com/envoyproxy/gateway/releases/download/latest/install.yaml
 
# 3. Скопируйте примеры из раздела "Практика" выше
# 4. Сделайте 20 curl запросов
# 5. Увидьте 90/10 распределение трафика
 
# Весь процесс: 15 минут

Почему это важно сделать сегодня:

Через 30 минут вы почувствуете разницу. Не прочитаете. Не поверите на слово. А ощутите на своём опыте, каково это — когда всё работает с первого раза.

И тогда вы поймёте, что Envoy Gateway — это не hype. Это эволюция.


P.S. Если вы дочитали до конца — вы уже в топ-10% инженеров, которые не игнорируют новые технологии.

Но знание без действия — это просто развлечение.

Откройте терминал. Потратьте 30 минут. Почувствуйте разницу.

И завтра на стендапе скажите: "Вчера попробовал Envoy Gateway. Ребята, это меняет правила игры."

P.P.S. Самый честный тест вашего мастерства:

Если вы не можете объяснить своему PM, почему Envoy Gateway лучше Nginx Ingress на языке бизнес-выгод (а не технических деталей) — вы ещё не понимаете инструмент достаточно глубоко.

Вернитесь к разделу "Три кейса". Перескажите их своими словами.

Потому что в конечном счёте технологии не важны.

Важно то, какие проблемы они решают и сколько времени экономят вашей команде.

Envoy Gateway экономит мне 4-6 часов в неделю на настройку и отладку.

Посчитайте свои часы. И решите, стоит ли 30 минут на эксперимент.

Я верю, что стоит.


См. также: