OSEN-НИЙ SAAALEСкидка 50% на виртуальный хостинг и VDS
до 30.11.2025 Подробнее
Выберите продукт

gRPC и HTTP API через Envoy в Kubernetes-кластере на VDS

Разбираем, как построить API gateway на Envoy в Kubernetes-кластере на VDS: совместить gRPC и HTTP API через единый HTTPS-listener, настроить маршруты и кластеры, TLS, health-check'и, логирование и базовую observability для продовой нагрузки.
gRPC и HTTP API через Envoy в Kubernetes-кластере на VDS

Если вы уже перевели часть сервисов в Kubernetes на облачный VDS, то рано или поздно упрётесь в один и тот же вопрос: чем аккуратно и предсказуемо терминировать входящий трафик, когда у вас одновременно есть gRPC и обычный HTTP API, несколько версий сервисов и требования по observability? В какой‑то момент стандартного ingress‑контроллера становится мало, и на сцену выходит Envoy proxy как универсальный API gateway.

В этой статье посмотрим, как использовать Envoy в роли API gateway для gRPC и HTTP API внутри Kubernetes‑кластера на VDS: какую архитектуру выбрать, как описывать listeners, clusters и маршруты, чтобы не запутаться, и какие грабли подстерегают на проде. Никаких сервис‑мэшей «целиком» — только то, что нужно на входе в кластер.

Зачем использовать Envoy как API gateway в Kubernetes

Envoy исторически появился как высокопроизводительный L7‑прокси, и вокруг него уже построено множество решений: Istio, Consul Connect, AWS App Mesh и т.д. Но вам совсем не обязательно тащить весь сервис‑мэш, чтобы использовать Envoy как API gateway на входе в кластер.

Базовые задачи, которые удобно решать через Envoy:

  • Единая точка входа для gRPC и HTTP API, без разделения на «специальный» gRPC‑ингресс и классический HTTP‑ингресс.
  • Чёткий контроль над маршрутизацией по путям, заголовкам, доменам и режимам HTTP/HTTP2/gRPC.
  • Гибкая конфигурация таймаутов, ретраев, circuit breaker'ов, лимитов по подключению и запросам.
  • Нормальное логирование и метрики: access‑логи, statsd/Prometheus‑метрики из коробки.
  • Постепенный rollout новых версий сервисов (canary, weighted routing) без отдельного ingress‑контроллера.

В отличие от многих ingress‑контроллеров, Envoy вы конфигурируете напрямую (через статический YAML или через xDS). Это усложняет старт, но зато даёт полный контроль над тем, как ходит трафик внутри вашего VDS‑кластера.

Базовая архитектура: Envoy как entrypoint в кластер

Рассмотрим типичную минималистичную схему для одного VDS с Kubernetes (k3s/k0s/managed‑k8s — не принципиально).

Снаружи мир видит только Envoy (NodePort, hostPort или LoadBalancer). Внутри Envoy проксирует запросы на сервисы в кластере: gRPC‑сервисы и HTTP API. TLS можно терминировать на Envoy или пробрасывать до бэкендов.

Условно это выглядит так:

  • Клиенты → TCP:443 → Envoy (Deployment + Service типа LoadBalancer/NodePort).
  • Envoy listener 0.0.0.0:443 с tls_context и http_connection_manager.
  • Маршрут 1: gRPC API по хосту grpc.example.com и/или по префиксу /grpc.
  • Маршрут 2: HTTP REST API по хосту api.example.com или /api.
  • Upstream‑сервисы: grpc-user-service, http-order-service и т.п. как обычные Kubernetes Services.

Важно понимать, что в таком сетапе Envoy — не «ещё один слой» поверх ingress‑контроллера, а замена классическому ingress. Это уменьшает магию и повышает предсказуемость: вы сами контролируете, как именно кластера Kubernetes на VDS общаются с внешним миром.

Схема сетевого потока через Envoy API gateway к сервисам в Kubernetes

HTTP API и gRPC через один listener

Главный вопрос: нужно ли поднимать отдельные listeners/порты для gRPC и HTTP API? В большинстве сценариев достаточно одного HTTPS‑listener'а с http_connection_manager, который умеет одновременно в HTTP/1.1 и HTTP/2.

Ключевые моменты при совмещении протоколов:

  • Для gRPC нужен HTTP/2 end‑to‑end (или хотя бы до gRPC‑бэкенда); Envoy это отлично поддерживает.
  • Один и тот же listener может обслуживать и классический HTTP API (REST/JSON), и gRPC с помощью маршрутов.
  • Envoy автоматически выбирает протокол по ALPN (например, h2 для gRPC, http/1.1 для браузерного трафика).

Минимальный пример listener с http_connection_manager в статическом конфиге Envoy (упрощённо):

static_resources:
  listeners:
  - name: ingress_https
    address:
      socket_address:
        address: 0.0.0.0
        port_value: 443
    filter_chains:
    - filter_chain_match: {}
      transport_socket:
        name: envoy.transport_sockets.tls
        typed_config:
          "@type": type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.DownstreamTlsContext
          common_tls_context:
            alpn_protocols: ["h2", "http/1.1"]
            tls_certificates:
            - certificate_chain:
                filename: "/etc/envoy/certs/fullchain.pem"
              private_key:
                filename: "/etc/envoy/certs/privkey.pem"
      filters:
      - name: envoy.filters.network.http_connection_manager
        typed_config:
          "@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager
          stat_prefix: ingress_http
          route_config:
            name: local_route
            virtual_hosts:
            - name: grpc_services
              domains: ["grpc.example.com"]
              routes:
              - match:
                  prefix: "/"
                route:
                  cluster: grpc_user_svc
                  timeout: 5s
            - name: http_api
              domains: ["api.example.com"]
              routes:
              - match:
                  prefix: "/"
                route:
                  cluster: http_api_svc
                  timeout: 5s
          http_filters:
          - name: envoy.filters.http.router

Здесь уже видно разделение по доменам: gRPC‑клиенты ходят на grpc.example.com, HTTP‑клиенты — на api.example.com. Внутри виртуальных хостов вы дальше можете разделять по путям, заголовкам и т.п.

Настройка кластеров dla gRPC и HTTP API

Разница между кластерами для gRPC и HTTP API в Envoy не космическая, но один нюанс критичен: для gRPC очень желательно включить http2_protocol_options на upstream‑кластере, чтобы соединение до бэкенда было HTTP/2.

Примеры двух кластеров (через DNS‑дискавери Kubernetes Services):

  clusters:
  - name: grpc_user_svc
    type: STRICT_DNS
    connect_timeout: 0.25s
    lb_policy: ROUND_ROBIN
    http2_protocol_options: {}
    load_assignment:
      cluster_name: grpc_user_svc
      endpoints:
      - lb_endpoints:
        - endpoint:
            address:
              socket_address:
                address: grpc-user-service.default.svc.cluster.local
                port_value: 50051

  - name: http_api_svc
    type: STRICT_DNS
    connect_timeout: 0.25s
    lb_policy: ROUND_ROBIN
    load_assignment:
      cluster_name: http_api_svc
      endpoints:
      - lb_endpoints:
        - endpoint:
            address:
              socket_address:
                address: http-api-service.default.svc.cluster.local
                port_value: 8080

Что важно помнить:

  • STRICT_DNS отлично дружит с Kubernetes + kube-dns/CoreDNS: Envoy периодически резолвит имя сервиса и видит все Pod IP.
  • Для gRPC‑кластера указываем http2_protocol_options, иначе upstream будет ходить по HTTP/1.1, и часть фич (streaming) может не работать корректно.
  • connect_timeout, lb_policy, circuit breaker'ы и retry policy настраивайте отдельно для gRPC и HTTP API: у них часто разные ожидания по ретраям.

Envoy в Kubernetes: Deployment и Service

С конфигом всё понятно, но как именно запускать Envoy в Kubernetes‑кластере на VDS? Чаще всего это отдельный Deployment в namespace, например, edge или ingress.

Базовый подход:

  • Deployment с Envoy‑контейнером, конфиг монтируется как ConfigMap.
  • Service типа LoadBalancer, NodePort или ClusterIP + hostPort (в зависимости от того, как вы публикуете кластер во внешний мир на VDS).
  • Сертификаты TLS монтируются из Secret (или из файловой системы, если вы интегрируете с cert-manager через volume).

Упрощённый пример манифеста Deployment и Service (без TLS‑секретов и readiness‑hooks, только суть):

apiVersion: apps/v1
kind: Deployment
metadata:
  name: envoy-gateway
  namespace: edge
spec:
  replicas: 2
  selector:
    matchLabels:
      app: envoy-gateway
  template:
    metadata:
      labels:
        app: envoy-gateway
    spec:
      containers:
      - name: envoy
        image: envoyproxy/envoy:v1.32-latest
        args:
        - "-c"
        - "/etc/envoy/envoy.yaml"
        ports:
        - containerPort: 443
        volumeMounts:
        - name: envoy-config
          mountPath: /etc/envoy
      volumes:
      - name: envoy-config
        configMap:
          name: envoy-config
---
apiVersion: v1
kind: Service
metadata:
  name: envoy-gateway
  namespace: edge
spec:
  type: NodePort
  selector:
    app: envoy-gateway
  ports:
  - name: https
    port: 443
    targetPort: 443
    nodePort: 30443

На VDS этот Service типа NodePort вы можете подсветить наружу через iptables или nftables, либо через L4‑балансировщик, если у вас несколько нод. Для одиночного узла часто проще пробросить порт на host‑сети (через hostPort или MetalLB), но это уже детали конкретной инсталляции Kubernetes.

FastFox VDS
Облачный VDS-сервер в России
Аренда виртуальных серверов с моментальным развертыванием инфраструктуры от 195₽ / мес

Маршрутизация gRPC‑методов и HTTP путей

Для HTTP API всё привычно: match по prefix или path, заголовкам, хосту. Для gRPC есть отдельный фильтр envoy.filters.http.grpc_web (если вы используете grpc-web) и поддержка маршрутизации по служебным заголовкам.

Несколько практических паттернов маршрутизации:

  • Использовать разные домены для gRPC и HTTP API (grpc.example.com и api.example.com) — меньше путаницы.
  • Если домен один, разделяйте по префиксам: /grpc/... и /api/....
  • Для grpc-web добавляйте фильтр grpc_web перед router.

Пример маршрутизации по префиксам:

          route_config:
            name: local_route
            virtual_hosts:
            - name: main
              domains: ["api.example.com"]
              routes:
              - match:
                  prefix: "/grpc/user."
                route:
                  cluster: grpc_user_svc
              - match:
                  prefix: "/api/"
                route:
                  cluster: http_api_svc

gRPC‑клиент указывает метод в виде /package.Service/Method. Envoy может маршрутизировать по этому строковому пути (если вы хотите, например, разные бэкенды для разных версий API). Но на практике чаще используют разделение по доменам или префиксам, чтобы не городить сложные safe_regex‑матчи.

Если нужна именно grpc-web‑схема, можно дополнительно посмотреть материал про интеграцию в статье grpc-web через Envoy: конфигурация и подводные камни.

Таймауты, ретраи и circuit breakers

Для API gateway на основе Envoy особо важны таймауты и лимиты — вы становитесь «вратами» в свой кластер, и именно здесь легче всего отрезать «шумные» или ошибочные запросы, чем давать им заваливать бэкенды.

Ключевые места настройки:

  • Таймаут на уровне маршрута (route.route.timeout) — общий лимит жизни запроса.
  • Retry policy для отдельных маршрутов (например, для идемпотентных GET).
  • Лимиты подключений и запросов на уровне кластера (circuit_breakers).

Простейший пример повышенного таймаута для медленного gRPC‑метода и запрета ретраев:

              routes:
              - match:
                  prefix: "/grpc/report."
                route:
                  cluster: grpc_report_svc
                  timeout: 60s
                  retry_policy:
                    num_retries: 0

Для HTTP API наоборот часто хотят ретраи для 5xx и сетевых ошибок, но только для идемпотентных методов:

              - match:
                  prefix: "/api/"
                route:
                  cluster: http_api_svc
                  timeout: 10s
                  retry_policy:
                    retry_on: "5xx,connect-failure,refused-stream"
                    num_retries: 2
                    per_try_timeout: 3s

Не забывайте, что ретраи на уровне Envoy плюс ретраи в клиенте и в приложении легко превращаются в «шквал» запросов при деградации, поэтому политику нужно продумывать для каждого маршрута отдельно.

Observability: логирование и метрики

Одно из главных преимуществ Envoy как API gateway — прозрачное наблюдение за всем, что приходит в ваш кластер Kubernetes на VDS: и gRPC, и HTTP API.

Минимальный набор, который стоит включить сразу:

  • Access‑лог в JSON для дальнейшей отправки в Loki, ELK или ClickHouse.
  • Статистика Envoy (Prometheus или StatsD) — RPS, ошибки, latency по кластерам.
  • grpc‑специфичные метрики (например, коды ошибок gRPC).

Пример JSON access‑лога в http_connection_manager:

          access_log:
          - name: envoy.access_loggers.file
            typed_config:
              "@type": type.googleapis.com/envoy.extensions.access_loggers.file.v3.FileAccessLog
              path: "/var/log/envoy/access.log"
              log_format:
                json_format:
                  protocol: "%PROTOCOL%"
                  method: "%REQ(:METHOD)%"
                  path: "%REQ(X-ENVOY-ORIGINAL-PATH?:PATH)%"
                  authority: "%REQ(:AUTHORITY)%"
                  response_code: "%RESPONSE_CODE%"
                  grpc_status: "%GRPC_STATUS%"
                  duration_ms: "%DURATION%"
                  upstream_cluster: "%UPSTREAM_CLUSTER%"
                  upstream_host: "%UPSTREAM_HOST%"
                  user_agent: "%REQ(USER-AGENT)%"
                  x_request_id: "%REQ(X-REQUEST-ID)%"

Такой формат удобно парсить любым лог‑коллектором, и, что важно, здесь сразу есть grpc_status и обычный HTTP‑код. Это позволяет различать, например, gRPC UNAVAILABLE и HTTP 503 на уровне дашбордов.

Наблюдаемость Envoy: метрики и логи по gRPC и HTTP трафику

Типичные грабли и отладка

С gRPC и HTTP API через Envoy обычно всплывают одни и те же проблемы. Ниже — наиболее частые и что с ними делать.

1. gRPC не работает, а HTTP API работает

Чаще всего причины такие:

  • Нет HTTP/2 на upstream‑кластере — забыли http2_protocol_options.
  • Клиент не договаривается по ALPN (например, старый gRPC‑клиент без TLS или с неправильными настройками).
  • Маршрут ловит gRPC‑запрос как обычный HTTP и ломает заголовки.

Что проверить в первую очередь:

  • В access‑логах поля protocol и grpc_status.
  • В stats Envoy — счётчики cluster.<name>.upstream_cx_protocol_error.
  • На бэкенде — видит ли он HTTP/2 (например, через debug‑лог сервера приложения).

2. Внезапные таймауты и обрывы стримов

Особенно это заметно для долго живущих gRPC‑стримов. Возможные источники:

  • Слишком маленький idle_timeout или общий timeout маршрута.
  • Load balancer или firewall перед Envoy, который режет долгие соединения.
  • Переиспользование соединения с изменением конфигурации Envoy (reload без учёта активных стримов).

Что можно сделать:

  • Увеличить или отключить idle_timeout для конкретных gRPC‑маршрутов.
  • Явно задать max_connection_duration и учитывать его поведение на клиенте.
  • Аккуратно планировать rolling update Envoy, следя за drain‑процессом и метриками соединений.

3. Высокая латентность при первом запросе

Классика: первый gRPC‑ или HTTP‑запрос после простоя долго идёт. Возможные причины:

  • DNS‑резолвинг кластера (STRICT_DNS) и холодные TCP‑коннекты.
  • Низкое значение preconnect_ratio или его отсутствие.
  • Connection pool Envoy простаивал и теперь собирает новые соединения.

Отладка и смягчение:

  • Посмотреть метрики connection pool на upstream‑кластерах (active, ready, busy коннекты).
  • Включить пререндеринг коннектов или увеличить минимальное количество соединений.
  • При необходимости оптимизировать схему HTTP/2 и h2c, в том числе на стороне бэкендов; детальнее это разобрано в статье HTTP/2 и h2c для upstream‑сервисов за Envoy и Nginx.
FastFox SSL
Надежные SSL-сертификаты
Мы предлагаем широкий спектр SSL-сертификатов от GlobalSign по самым низким ценам. Поможем с покупкой и установкой SSL бесплатно!

Стратегия развертывания и обновлений

Так как Envoy — точка входа в весь кластер, его обновления на VDS особенно чувствительны. Пара практических рекомендаций:

  • Используйте Deployment с типом обновления RollingUpdate и небольшим шагом (один pod за раз), чтобы не отрезать весь трафик при проблеме с новым образом.
  • Перед выкатыванием новой версии конфигурации гоняйте её через envoy --mode validate -c path/to/envoy.yaml в CI.
  • Добавьте readinessProbe, который проверяет внутренний endpoint Envoy или факт загрузки конфигурации.
  • Сохраняйте обратную совместимость маршрутов (например, не удаляйте старые кластеры, пока вы не убедились, что весь трафик переведён).

Для более продвинутых сценариев (динамическая маршрутизация, canary‑релизы без правки YAML) имеет смысл посмотреть в сторону xDS‑серверов или сервис‑мэш‑решений, но это уже отдельная тема.

Итоги

Использование Envoy как API gateway для gRPC и HTTP API в Kubernetes‑кластере на VDS позволяет получить предсказуемый, управляемый входной слой: единый listener, точную маршрутизацию, понятные логи и метрики. Да, придётся повозиться с конфигами и tooling'ом, но взамен вы получите API‑вход, который легко масштабировать и эволюционировать вместе с вашим кластером.

Если вы только начинаете, стартуйте с простого статического конфига: один listener, пара кластеров, минимальный набор маршрутов и логов. Когда это стабилизируется на прогоне нагрузки, постепенно внедряйте таймауты, retry‑policy, circuit breaker'ы и продвинутые паттерны маршрутизации. В этом подходе главное — не пытаться «сделать Istio за вечер», а шаг за шагом превращать Envoy в надёжный фасад вашего Kubernetes‑кластера на VDS. А сами кластера при этом можно безболезненно переносить между тарифами или площадками, так как внешний entrypoint остаётся единым.

Поделиться статьей

Вам будет интересно

PHP на VDS: как latency и MTU ломают rsync и деплой OpenAI Статья написана AI (GPT 5)

PHP на VDS: как latency и MTU ломают rsync и деплой

Latency и MTU часто остаются «серой зоной» при настройке VDS: сайт то «плавает», то rsync висит, то PHP внезапно ловит таймауты. Р ...
Laravel и Symfony cache с Redis: теги, инвалидация и подводные камни OpenAI Статья написана AI (GPT 5)

Laravel и Symfony cache с Redis: теги, инвалидация и подводные камни

Разбираемся, как правильно настроить Laravel cache и Symfony cache с Redis, использовать теги, избегать гонок и утечек памяти. Ста ...
HTTP 4xx и 5xx: как диагностировать и чинить ошибки на Nginx и Apache OpenAI Статья написана AI (GPT 5)

HTTP 4xx и 5xx: как диагностировать и чинить ошибки на Nginx и Apache

Практическое руководство для админов и девопсов по диагностике и устранению HTTP ошибок 4xx и 5xx: от 500 до 502, 503 и 504. Разбе ...