Управление трафиком в Kubernetes: Ingress и Egress для DevOps | AdminWiki

Управление трафиком в Kubernetes: Ingress и Egress для DevOps

22 июля 2026 12 мин. чтения

Введение: зачем управлять трафиком в Kubernetes

Kubernetes по умолчанию разрешает свободное сетевое взаимодействие между всеми подами в кластере. Любой контейнер может обратиться к любому другому контейнеру в любом пространстве имен. Для разработки это удобно, для production - неприемлемо. Без контроля трафика база данных с платежными данными оказывается в одной плоской сети с фронтендом, доступным из интернета. Одна скомпрометированная зависимость в поде открывает злоумышленнику весь кластер.

Эта статья дает полный набор инструментов для управления сетевым трафиком. Вы настроите Ingress-контроллеры для приема внешних запросов, примените NetworkPolicy для изоляции микросервисов, ограничите исходящие соединения через Egress-политики и познакомитесь с продвинутыми возможностями Istio. Все примеры проверены на практике и готовы к применению в ваших кластерах.

Сетевую модель Kubernetes можно представить как три уровня. Первый - связность подов через CNI-плагин, который назначает IP-адреса и обеспечивает маршрутизацию. Второй - абстракция Service для стабильного обнаружения подов. Третий - политики и контроллеры, которые определяют, какой трафик разрешен. Именно третий уровень мы детально разберем: Ingress для входящего трафика, NetworkPolicy для изоляции, Egress для контроля исходящих соединений и сервис-меш для сценариев, выходящих за рамки стандартных возможностей Kubernetes.

Если вы проектируете кластер для продакшена, начните с полного руководства по сетям Kubernetes, где разобраны CNI-плагины и базовая связность. Для настройки Service и Ingress с готовыми манифестами используйте практическое руководство по Service и Ingress.

Ingress: маршрутизация внешних запросов к сервисам

Ingress решает задачу приема HTTP и HTTPS трафика из-за пределов кластера и маршрутизации его к нужным сервисам. Без Ingress вам пришлось бы создавать для каждого сервиса отдельный LoadBalancer, что дорого и неудобно. Один Ingress-контроллер обрабатывает все входящие соединения и направляет их по правилам, описанным в Ingress-ресурсах.

Что такое Ingress и Ingress-контроллер

Ingress - это API-объект Kubernetes, который описывает правила маршрутизации: на какой хост и путь пришел запрос, к какому сервису его направить. Сам по себе Ingress-ресурс ничего не делает. Это просто набор правил в YAML.

Ingress-контроллер - это под или набор подов, которые читают Ingress-ресурсы и применяют их. Контроллер запускает внутри себя прокси-сервер (NGINX, HAProxy, Traefik, Envoy) и динамически обновляет его конфигурацию при изменении Ingress-ресурсов или сервисов. Схема взаимодействия проста: внешний запрос приходит на IP контроллера, контроллер смотрит на Host-заголовок и URL-путь, находит подходящее правило Ingress и проксирует запрос на соответствующий Service, который уже направляет трафик к конкретным подам.

Ключевое различие, которое часто упускают: Ingress-контроллер работает на уровне L7 (HTTP/HTTPS), анализируя заголовки и пути. Service типа LoadBalancer или NodePort работает на L4 (TCP/UDP) и не разбирает HTTP. Если вам нужна маршрутизация по URL, SSL-терминация, редиректы - вам нужен Ingress.

Установка и настройка NGINX Ingress Controller

NGINX Ingress Controller - самый популярный контроллер в экосистеме Kubernetes. Он использует NGINX как прокси-движок и поддерживает практически все возможности, описанные в спецификации Ingress: SSL-терминацию, редиректы, rewrite правил, rate limiting, аутентификацию через аннотации.

Установка через Helm занимает несколько минут. Добавьте репозиторий и установите чарт:

helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx
helm repo update
helm install ingress-nginx ingress-nginx/ingress-nginx \
  --namespace ingress-nginx \
  --create-namespace \
  --set controller.service.type=LoadBalancer

Если у вас нет облачного LoadBalancer, замените тип сервиса на NodePort. После установки проверьте, что под контроллера запущен:

kubectl get pods -n ingress-nginx

Теперь создайте первый Ingress-ресурс. Предположим, у вас есть сервис web-app в пространстве имен default, который слушает порт 80. Манифест Ingress для маршрутизации запросов с домена myapp.example.com:

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: web-app-ingress
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: /
spec:
  ingressClassName: nginx
  rules:
  - host: myapp.example.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: web-app
            port:
              number: 80

Поле ingressClassName обязательно в Kubernetes 1.18+. Аннотация rewrite-target указывает NGINX переписывать URL перед отправкой в бэкенд. Проверьте, что правило применилось:

kubectl get ingress
kubectl describe ingress web-app-ingress

Для настройки TLS добавьте секцию tls в манифест. Предварительно создайте Secret с сертификатом:

kubectl create secret tls myapp-tls --cert=cert.pem --key=key.pem

Затем дополните Ingress:

spec:
  tls:
  - hosts:
    - myapp.example.com
    secretName: myapp-tls

NGINX Ingress Controller автоматически настроит SSL-терминацию для указанного хоста. Для автоматического получения сертификатов от Let's Encrypt интегрируйте cert-manager. Подробнее о мониторинге метрик NGINX Ingress читайте в руководстве по маршрутизации для SRE.

Установка и настройка Traefik как Ingress-контроллера

Traefik - это современный прокси с динамической конфигурацией. Он автоматически обнаруживает сервисы Kubernetes через API-сервер и обновляет маршруты без перезагрузки. Traefik имеет встроенную поддержку Let's Encrypt, middleware для обработки запросов и собственные CRD (Custom Resource Definitions) - IngressRoute, которые расширяют стандартный Ingress.

Установка через Helm:

helm repo add traefik https://traefik.github.io/charts
helm repo update
helm install traefik traefik/traefik \
  --namespace traefik \
  --create-namespace

Traefik использует CRD IngressRoute вместо стандартного Ingress. Пример маршрутизации с TLS от Let's Encrypt:

apiVersion: traefik.io/v1alpha1
kind: IngressRoute
metadata:
  name: web-app-route
spec:
  entryPoints:
    - websecure
  routes:
  - match: Host(`myapp.example.com`)
    kind: Rule
    services:
    - name: web-app
      port: 80
  tls:
    certResolver: letsencrypt

Для работы Let's Encrypt нужно настроить certResolver в статической конфигурации Traefik. Передайте параметры при установке Helm:

--set additionalArguments="{--certificatesresolvers.letsencrypt.acme.tlschallenge=true,--certificatesresolvers.letsencrypt.acme.email=admin@example.com,--certificatesresolvers.letsencrypt.acme.storage=/data/acme.json}"

Traefik поддерживает middleware - промежуточные обработчики запросов. Например, можно добавить Basic Auth, rate limiting или редирект с HTTP на HTTPS без правки кода приложения. Middleware определяется как отдельный CRD и ссылается в IngressRoute. Это дает гибкость, недоступную в стандартном Ingress без аннотаций.

Выбор между NGINX и Traefik сводится к приоритетам. NGINX проверен годами, имеет огромную базу знаний и предсказуемую производительность. Traefik удобен в микросервисных средах с частыми изменениями: автоматическое обнаружение сервисов сокращает объем ручной конфигурации. Если вы используете Docker и Kubernetes вместе, Traefik обеспечит единый подход к маршрутизации. Для высоконагруженных систем с жесткими требованиями к latency чаще выбирают NGINX.

NetworkPolicy: изоляция трафика между подами

Ingress решает проблему внешнего доступа, но не ограничивает трафик внутри кластера. Kubernetes по умолчанию разрешает все соединения между подами. NetworkPolicy меняет это поведение: вы явно описываете, какие входящие и исходящие соединения разрешены для группы подов. Политики действуют на уровне L3/L4 - IP-адреса, порты, протоколы.

Важное требование: NetworkPolicy реализуется CNI-плагином. Не все плагины поддерживают политики. Calico, Cilium, Weave Net поддерживают. Flannel - нет. Проверьте документацию вашего CNI перед внедрением политик. Без поддержки CNI вы можете создать NetworkPolicy, она будет висеть в кластере, но не будет применяться - трафик останется неограниченным.

Создание политик для ограничения входящего трафика

Защитим бэкенд-сервис от несанкционированного доступа. У нас есть поды с меткой app=backend, которые должны принимать запросы только от подов с меткой app=frontend на порт 8080. Все остальные входящие соединения запрещены.

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: backend-ingress-policy
  namespace: default
spec:
  podSelector:
    matchLabels:
      app: backend
  policyTypes:
  - Ingress
  ingress:
  - from:
    - podSelector:
        matchLabels:
          app: frontend
    ports:
    - protocol: TCP
      port: 8080

Разберем ключевые поля. podSelector определяет целевые поды, к которым применяется политика. policyTypes указывает направление трафика: Ingress (входящий), Egress (исходящий) или оба. Секция ingress описывает разрешенные источники. В примере разрешен только один источник - поды с меткой app=frontend. Поле ports ограничивает разрешенные порты.

Проверьте эффект политики. До применения любой под в кластере мог обратиться к backend на любой порт. После применения только frontend-поды могут подключиться к порту 8080. Запустите тестовый под и попробуйте достучаться до backend:

kubectl run test --rm -it --image=busybox -- sh
wget -O- --timeout=3 http://backend-service:8080

Если тестовый под не имеет метки app=frontend, соединение зависнет и упадет по таймауту.

Стратегия deny-all - хорошая отправная точка для production. Создайте политику, которая запрещает весь входящий трафик в пространство имен, а затем добавляйте разрешающие правила для конкретных сервисов:

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: deny-all-ingress
  namespace: production
spec:
  podSelector: {}
  policyTypes:
  - Ingress

Пустой podSelector означает «все поды в пространстве имен». Отсутствие секции ingress означает «нет разрешенных входящих соединений». Это базовый уровень изоляции, который предотвращает случайный доступ между сервисами.

Контроль исходящего трафика (Egress) с помощью NetworkPolicy

Ограничение исходящего трафика не менее важно, чем входящего. Скомпрометированный под не должен устанавливать соединения с внешними серверами злоумышленника или обращаться к внутренним сервисам, которые ему не нужны для работы. Egress-политики решают эту задачу.

Типичный сценарий: поды приложения должны обращаться только к внешнему API по определенному IP-адресу и к DNS-серверу для разрешения имен. Все остальные исходящие соединения запрещены.

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: app-egress-policy
  namespace: default
spec:
  podSelector:
    matchLabels:
      app: myapp
  policyTypes:
  - Egress
  egress:
  - to:
    - ipBlock:
        cidr: 203.0.113.0/24
    ports:
    - protocol: TCP
      port: 443
  - to:
    - namespaceSelector: {}
      podSelector:
        matchLabels:
          k8s-app: kube-dns
    ports:
    - protocol: UDP
      port: 53

Политика разрешает два исходящих направления. Первое - IP-блок 203.0.113.0/24 на порт 443 (внешний API). Второе - DNS-сервер Kubernetes (kube-dns или CoreDNS) на порт 53 UDP. Без явного разрешения DNS поды не смогут разрешать доменные имена, даже если IP-адрес API разрешен. Это частая ошибка: приложение падает с ошибкой разрешения имени, хотя доступ к API по IP работает.

Проверка Egress-политики аналогична Ingress: запустите тестовый под с нужной меткой и выполните запрос к внешнему ресурсу. Для диагностики используйте nslookup и curl:

kubectl exec -it myapp-pod -- nslookup example.com
kubectl exec -it myapp-pod -- curl -v https://203.0.113.1

Если политика работает корректно, DNS-запросы выполняются, HTTPS-соединение к разрешенному IP устанавливается, а любые другие исходящие соединения блокируются.

Для геофильтрации трафика на уровне NetworkPolicy можно комбинировать IP-блоки по странам. Подробный разбор этого сценария с готовыми манифестами смотрите в руководстве по геофильтрации в Kubernetes.

Продвинутое управление трафиком с Istio

NetworkPolicy и Ingress закрывают базовые потребности: изоляцию на L3/L4 и внешний HTTP-доступ. Когда требуется управление трафиком на уровне L7 между сервисами - распределение нагрузки по весам, повторные попытки при ошибках, автоматическое взаимное шифрование - в дело вступает сервис-меш. Istio - один из самых распространенных сервис-мешей, который внедряет sidecar-прокси (Envoy) в каждый под и централизованно управляет всем трафиком.

Переход к сервис-мешу оправдан, когда у вас десятки микросервисов, и вам нужны: канареечные развертывания с точным контролем процента трафика, сквозная взаимная TLS-аутентификация между всеми сервисами, сбор метрик и трейсинг без изменения кода, политики авторизации на уровне HTTP-заголовков и JWT-токенов. Если у вас три сервиса и простой Ingress - Istio добавит сложности без соразмерной пользы.

Настройка шлюза и виртуальных сервисов для внешнего трафика

В Istio аналогом Ingress выступают два объекта: Gateway и VirtualService. Gateway описывает, какие порты и протоколы открыты для входящего трафика на границе меша. VirtualService определяет правила маршрутизации для трафика, прошедшего через Gateway.

Создадим Gateway для приема HTTP-трафика на порту 80:

apiVersion: networking.istio.io/v1beta1
kind: Gateway
metadata:
  name: myapp-gateway
spec:
  selector:
    istio: ingressgateway
  servers:
  - port:
      number: 80
      name: http
      protocol: HTTP
    hosts:
    - "myapp.example.com"

Селектор istio: ingressgateway указывает, что этот Gateway применяется к стандартному Istio Ingress Gateway, который установлен в кластере. Теперь VirtualService для маршрутизации по URI:

apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
  name: myapp-vs
spec:
  hosts:
  - "myapp.example.com"
  gateways:
  - myapp-gateway
  http:
  - match:
    - uri:
        prefix: /api
    route:
    - destination:
        host: api-service
        port:
          number: 8080
  - match:
    - uri:
        prefix: /
    route:
    - destination:
        host: web-service
        port:
          number: 80

Запросы на /api уходят к api-service, все остальные - к web-service. По сравнению со стандартным Ingress, Istio дает больше возможностей: маршрутизация по заголовкам, распределение трафика по весам между разными версиями сервиса, fault injection для тестирования отказоустойчивости.

Обеспечение безопасности с помощью mTLS и авторизации

Взаимная TLS-аутентификация (mTLS) - одна из ключевых фич Istio. Когда mTLS включен, все соединения между подами автоматически шифруются, и каждая сторона проверяет сертификат другой стороны. Это защищает трафик от перехвата внутри кластера и гарантирует, что сервисы общаются только с легитимными контрагентами.

Включение строгого mTLS во всем пространстве имен:

apiVersion: security.istio.io/v1beta1
kind: PeerAuthentication
metadata:
  name: default
  namespace: production
spec:
  mtls:
    mode: STRICT

Режим STRICT требует mTLS для всех соединений. Под без sidecar-прокси Envoy не сможет подключиться к сервисам в этом пространстве имен. Режим PERMISSIVE разрешает и mTLS, и обычный трафик - удобно при миграции.

AuthorizationPolicy позволяет управлять доступом на уровне сервис-аккаунтов. Например, разрешим доступ к payment-service только от сервис-аккаунта checkout-service:

apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
  name: payment-access
  namespace: production
spec:
  selector:
    matchLabels:
      app: payment
  action: ALLOW
  rules:
  - from:
    - source:
        principals: ["cluster.local/ns/production/sa/checkout-service"]

Поле principals использует SPIFFE-идентификаторы, которые Istio автоматически назначает на основе сервис-аккаунтов Kubernetes. Это более гранулярный контроль, чем NetworkPolicy на основе меток подов: вы разрешаете доступ конкретному сервис-аккаунту, а не любому поду с определенной меткой.

Диагностика и решение типовых проблем с трафиком

Сетевые проблемы в Kubernetes сложны тем, что трафик проходит несколько уровней абстракции: подовая сеть, Service, Ingress-контроллер, возможно, сервис-меш. Систематический подход к диагностике экономит часы.

Первое правило: проверяйте связность с самого нижнего уровня. Может ли под A достучаться до пода B напрямую по IP? Если нет - проблема в CNI или NetworkPolicy. Если да, но недоступен Service - проблема в селекторах Service или в том, что под не готов (readiness probe).

Проверка связности и анализ логов

Запустите временный под с сетевыми утилитами для тестирования:

kubectl run debug --rm -it --image=nicolaka/netshoot -- bash

Образ nicolaka/netshoot содержит curl, dig, telnet, tcpdump и другие инструменты. Проверьте разрешение DNS:

dig +short my-service.default.svc.cluster.local

Если DNS не разрешается, проблема может быть в CoreDNS или в NetworkPolicy, блокирующей UDP 53. Проверьте доступность сервиса по IP:

curl -v http://10-244-1-5.default.pod.cluster.local:8080

IP-адрес пода можно узнать через kubectl get pod -o wide. Если прямой доступ по IP работает, а через Service нет - проверьте селекторы в Service:

kubectl describe service my-service

Сравните метки в поле Selector с метками подов. Несовпадение - самая частая причина неработающих сервисов.

Для диагностики Ingress анализируйте логи контроллера. NGINX Ingress Controller пишет детальные логи о каждом запросе и ошибках конфигурации:

kubectl logs -n ingress-nginx deployment/ingress-nginx-controller --tail=100

Ищите строки с уровнем error или warn. Типичные ошибки: «no live upstreams» (сервис не имеет готовых подов), «could not find a server block» (неправильный хост в Ingress), «SSL certificate not found» (отсутствует или просрочен Secret с сертификатом).

NetworkPolicy не имеют логов по умолчанию. Для отладки используйте kubectl describe:

kubectl describe networkpolicy backend-ingress-policy

Проверьте, что podSelector соответствует целевым подам, а в секции ingress.from указаны правильные селекторы. Некоторые CNI, например Cilium, предоставляют инструменты для трассировки политик: cilium policy trace.

Лучшие практики и рекомендации для production

Начинайте с deny-all NetworkPolicy в каждом production-пространстве имен. Пустая политика, запрещающая весь входящий трафик, создает безопасный базовый уровень. Затем добавляйте разрешающие правила только для необходимых соединений. Это принцип нулевого доверия в рамках кластера: каждый сервис по умолчанию изолирован.

Выбирайте Ingress-контроллер под конкретные задачи. NGINX Ingress Controller показывает стабильную производительность под высокой нагрузкой и имеет обширную документацию. Traefik удобен в средах с частыми развертываниями благодаря автоматическому обнаружению сервисов. Не разворачивайте оба контроллера в одном кластере без веской причины - это усложняет диагностику.

Внедряйте сервис-меш только при реальной потребности. Istio решает сложные задачи, но добавляет накладные расходы: sidecar-прокси потребляют CPU и память, задержка каждого запроса увеличивается на доли миллисекунды, отладка усложняется. Если вам нужны только изоляция и базовый ingress-egress контроль - NetworkPolicy и Ingress-контроллера достаточно.

Настройте мониторинг сетевого трафика. Prometheus и Grafana с дашбордами для NGINX Ingress или Istio покажут паттерны трафика, задержки и ошибки. Без мониторинга вы узнаете о проблемах от пользователей. Для долгосрочного хранения логов Ingress-контроллера используйте централизованное логирование - Loki, Elasticsearch или облачные решения.

Регулярно обновляйте Ingress-контроллеры и CNI-плагины. Уязвимости в сетевых компонентах критичны: они находятся на границе кластера и обрабатывают весь входящий трафик. Подпишитесь на уведомления о релизах и планируйте обновления каждые 1-2 месяца. Перед обновлением в production проверяйте новую версию в staging-окружении с тестами связности.

При использовании облачных Kubernetes-сервисов, таких как Timeweb Cloud, убедитесь, что выбранный CNI-плагин поддерживает NetworkPolicy. Некоторые управляемые кластеры по умолчанию используют плагины без поддержки политик - проверьте это до развертывания production-нагрузок.

Поделиться:
Сохранить гайд? В закладки браузера