8(800) 222 32 56
Панель управления
DevOps LLM Безопасность

Kubernetes NetworkPolicy для LLM inference: default-deny без поломки DNS и GPU-сервисов

Kubernetes NetworkPolicy для LLM inference: default-deny без поломки DNS и GPU-сервисов
Подберите идеальное решение для ваших задач:
в России, США и Нидерландах обеспечат максимальную скорость. Воспользуйтесь всеми преимуществами надежного оборудования. Базовая помощь и техническое обслуживание входят в пакет услуг.

После включения default-deny LLM-под внезапно перестаёт резолвить model storage, exporter теряет collector, а readiness остаётся зелёным — знакомая картина? Хуже другое: команда открывает весь egress на 443, сервис оживает, но любая уязвимость снова получает прямой путь наружу. В этом runbook разберём NetworkPolicy как проверяемый контракт для GPU inference: от карты зависимостей и DNS до metadata endpoint, canary и rollback. Результатом будет не набор YAML «для галочки», а доказанная граница доступа, которую можно сопровождать в production.

Готовы перейти на современную серверную инфраструктуру?

В King Servers мы предлагаем серверы как на AMD EPYC, так и на Intel Xeon, с гибкими конфигурациями под любые задачи — от виртуализации и веб-хостинга до S3-хранилищ и кластеров хранения данных.

  • S3-совместимое хранилище для резервных копий
  • Панель управления, API, масштабируемость
  • Поддержку 24/7 и помощь в выборе конфигурации

Создайте аккаунт

Быстрая регистрация для доступа к инфраструктуре

Почему LLM workload нужен отдельный сетевой контракт

После запуска inference-под редко общается с одним соседом. Он принимает запросы от gateway, читает модели или адаптеры из хранилища, обращается к DNS, отправляет метрики и трассировки, иногда вызывает внешние API. Если контейнер скомпрометирован через зависимость, tool call или ошибку приложения, тот же набор маршрутов превращается в канал разведки и вывода данных.

Поэтому задача NetworkPolicy не сводится к «закрыть namespace». Нужен проверяемый контракт: кто имеет право войти в pod, куда pod может выйти, какой компонент владеет каждым разрешением и каким отрицательным тестом доказано, что остальные пути закрыты. Это особенно важно для внутреннего AI API, где один gateway обслуживает несколько команд и наборов данных.

Разделите трафик на четыре плоскости. Ingress — доверенный gateway. Service egress — model storage, базы и очереди. Platform egress — DNS, telemetry и необходимые control endpoints. Запрещённая плоскость — соседние namespaces, произвольный интернет и metadata service, если workload не должен получать node- или cloud-credentials.

Типичная ловушка: команда вводит default-deny, видит падение readiness и сразу добавляет широкий egress. Инцидент как будто устранён, но граница исчезла. Правильный порядок другой: зафиксировать baseline, перечислить зависимости, разрешать их по одной и для каждой держать negative control.

Контейнер LLM inference с разрешёнными и заблокированными сетевыми направлениями

Как NetworkPolicy принимает решение на самом деле

Стандартный NetworkPolicy работает на L3/L4 и описывает разрешения, а не последовательность firewall-правил. Политики аддитивны: если несколько объектов выбирают один pod, итоговый allow-list равен объединению разрешений. Порядок YAML-файлов ничего не меняет. Для соединения pod-to-pod должны одновременно разрешить трафик egress-политика источника и ingress-политика назначения.

По умолчанию pod не изолирован. Он становится изолированным по направлению, когда хотя бы одна политика выбирает его и включает соответствующий policyTypes. Значит, «у нас есть NetworkPolicy» ещё не доказывает защиту egress. Проверьте selector и оба направления отдельно.

Есть обязательный gate: CNI должен поддерживать enforcement. Kubernetes API примет объект даже тогда, когда сетевой плагин его не реализует. Официальная документация Kubernetes прямо предупреждает об этом. Самая честная проверка — canary pod и два маршрута: разрешённый и заведомо запрещённый.

Какой gate проверять первым

Схема аддитивной модели Kubernetes NetworkPolicy для ingress и egress

Снимите карту зависимостей до default-deny

До изменения dataplane соберите наблюдаемый список направлений хотя бы за один репрезентативный цикл: cold start, загрузка модели, health checks, обычный streaming-запрос, отправка метрик и graceful shutdown. Карта из документации полезна, но runtime evidence важнее: забытый exporter или sidecar ломает rollout чаще, чем основной inference-процесс.

Для каждого потока запишите source, destination, protocol, port, способ идентификации и owner. Критический столбец — почему разрешение остаётся стабильным. Внутрикластерный Service удобно выбирать через namespaceSelector + podSelector. Внешний SaaS с меняющимися адресами не становится стабильным только потому, что сегодня dig вернул два IP.

Разделите bootstrap и steady state. Если init container скачивает веса, а основной контейнер только обслуживает GPU, постоянный доступ runtime-пода к registry может быть лишним. Иногда лучше загрузить артефакт через контролируемую Job или локальный read-only volume. Обзор Kubernetes-платформы для AI inference показывает соседние компоненты; здесь каждый из них должен стать явной сетевой зависимостью.

  • Ingress: gateway, probes и административный путь, если он нужен.
  • Egress: DNS, object storage, telemetry, KMS или внешняя модель.
  • Cluster services: очередь, vector DB, cache, model controller.
  • Negative set: соседний namespace, случайный публичный адрес, metadata endpoint.

Не переносите наблюдённый трафик в allow-list автоматически. Сначала спросите owner-а, действительно ли зависимость нужна. Компрометированный контейнер тоже создаёт «наблюдаемый» трафик, а старый sidecar может продолжать обращаться к уже ненужному endpoint.

Введите default-deny как baseline, а не как финальную политику

Baseline должен быть коротким: выбрать все pods в целевом namespace и изолировать ingress с egress. Он не содержит исключений и не пытается угадать архитектуру. Именно поэтому его удобно ревьюить и применять к canary namespace до production.

Не накатывайте baseline поверх общего namespace, где живут unrelated workloads. Если selectors и ownership размыты, сначала разнесите приложения или введите обязательные labels. Иначе первое «временное» разрешение быстро станет широким правилом для всех.

yaml00-default-deny.yaml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: default-deny-all
  namespace: llm-prod
spec:
  podSelector: {}
  policyTypes:
    - Ingress
    - Egress
Базовая изоляция namespace по обоим направлениям

После применения DNS и service paths перестанут работать, пока вы их явно не разрешите. Это не дефект baseline, а доказательство того, что dependency map ещё не перенесена в policies. Если canary продолжает ходить к произвольному адресу, остановитесь: selector, namespace или CNI enforcement не соответствуют ожиданию.

Что означает baseline-тест

Enforcement работает. Добавляйте минимальные allow-политики.
Проверьте CNI, selector, namespace и effective policy на pod.
Разрешения складываются: найдите другую политику с широким allow.
Инженер применяет default-deny к namespace с GPU workload

Верните DNS и докажите фактический resolver path

Default-deny egress блокирует DNS. Но правило «разрешить kube-system:53» тоже может оказаться неверным: NodeLocal DNSCache, иной namespace или кастомный resolver меняют фактический путь. Сначала посмотрите /etc/resolv.conf внутри canary pod, затем найдите Service и EndpointSlice resolver-а.

В типовой установке CoreDNS Service называется kube-dns, а pods сохраняют label k8s-app=kube-dns ради обратной совместимости. Разрешайте UDP и TCP 53: TCP нужен для крупных ответов и fallback. DNS runbook Kubernetes предлагает проверять resolver, Service, pods и EndpointSlice отдельно.

yaml10-allow-dns.yaml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-cluster-dns
  namespace: llm-prod
spec:
  podSelector:
    matchLabels:
      app.kubernetes.io/name: llm-server
  policyTypes: [Egress]
  egress:
    - to:
        - namespaceSelector:
            matchLabels:
              kubernetes.io/metadata.name: kube-system
          podSelector:
            matchLabels:
              k8s-app: kube-dns
      ports:
        - {protocol: UDP, port: 53}
        - {protocol: TCP, port: 53}
Разрешение DNS к CoreDNS по UDP и TCP

Проверка должна различать три исхода: запрос дошёл до resolver-а, resolver вернул ответ, приложение установило новое соединение к нужному endpoint. Успешный nslookup доказывает первые два шага. Он не доказывает egress на полученный IP и не проверяет reuse существующего connection pool.

DNS gate перед следующим allow

DNS-запросы от LLM pod проходят только к CoreDNS

Разрешайте сервисы по identity, внешние endpoints — по владельцу

Для cluster-internal зависимостей сочетайте namespaceSelector и podSelector в одном элементе to. Это логическое AND: нужные pods только в нужном namespace. Два отдельных элемента означали бы OR и открыли больше, чем кажется при беглом ревью.

Named ports снижают риск расхождения номера порта между Service и workload, но политика сопоставляется с портом конечного pod. Проверьте реализацию CNI и EndpointSlice, особенно если Service использует другой targetPort. Ниже inference разрешает telemetry только к pods коллектора.

yaml20-allow-telemetry.yaml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-otel
  namespace: llm-prod
spec:
  podSelector:
    matchLabels:
      app.kubernetes.io/name: llm-server
  policyTypes: [Egress]
  egress:
    - to:
        - namespaceSelector:
            matchLabels:
              kubernetes.io/metadata.name: observability
          podSelector:
            matchLabels:
              app.kubernetes.io/name: opentelemetry-collector
      ports:
        - {protocol: TCP, port: 4317}
Минимальный egress к OpenTelemetry Collector

Внешние сервисы сложнее. Стандартный NetworkPolicy оперирует IP/CIDR, а не доменными именами. Адреса object storage, SaaS telemetry или внешнего LLM API могут меняться. Не превращайте это в 0.0.0.0/0:443 без решения владельца риска. Варианты: управляемый egress proxy, CNI с DNS-aware policy или выделенный network edge.

Если используете Cilium toFQDNs, учитывайте DNS proxy и lifecycle кеша; подробный практический разбор есть в статье о Cilium FQDN egress для LLM API. Документация Cilium объясняет, что ответы DNS превращаются в динамические L3-разрешения. Это расширение Cilium, а не переносимый объект Kubernetes.

Для model registry полезно разделить роли: отдельная Job с egress загружает проверенный digest, runtime pod монтирует read-only volume. Такой дизайн уменьшает постоянный outbound surface и упрощает разбор инцидента: сетевой owner bootstrap не смешивается с owner serving.

Сделайте metadata endpoint отдельным отрицательным контролем

Адрес 169.254.169.254 нельзя считать «просто ещё одним внешним IP». В AWS там работает IMDS, в Google Compute Engine — metadata server; ответы могут включать данные, связанные с identity и credentials. Конкретная семантика зависит от провайдера и конфигурации, поэтому переносить правила между облаками механически опасно.

Стандартный NetworkPolicy не имеет deny-правил с приоритетом. Если другой объект разрешает весь egress на TCP/80, отдельная политика с пустым списком не «перебьёт» это разрешение: allow-sets объединяются. Надёжная модель — default-deny и явные разрешения нужных направлений, которые не включают link-local metadata range.

ipBlock.except исключает CIDR из конкретного allow-правила, но не отменяет разрешение из другой политики. Кроме того, поведение IP вокруг Service NAT может различаться по CNI и cloud provider. Поэтому обязательны runtime negative probes из effective namespace. AWS документирует IPv4 IMDS 169.254.169.254 и отдельный IPv6 endpoint; Google также использует этот IPv4 адрес, но с собственными заголовками и правилами.

yaml30-allow-https-except-link-local.yaml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-approved-https-cidrs
  namespace: llm-prod
spec:
  podSelector:
    matchLabels:
      app.kubernetes.io/name: llm-server
  policyTypes: [Egress]
  egress:
    - to:
        - ipBlock:
            cidr: 0.0.0.0/0
            except:
              - 169.254.0.0/16
      ports:
        - {protocol: TCP, port: 443}
Пример CIDR allow с исключением link-local

Пример показывает механику, но широкое HTTPS-разрешение всё равно оставляет канал вывода данных. Используйте его как промежуточный canary или осознанный trust boundary, не как желаемый финал. Предпочтительнее корпоративные CIDR, egress proxy либо DNS-aware policy с наблюдаемым owner.

Как трактовать metadata-тест

Negative control выполнен. Убедитесь, что workload получает identity предусмотренным способом.
Не открывайте endpoint всем pods. Выделите selector, минимальную identity и провайдерный механизм защиты.
Найдите effective allow во всех выбирающих политиках. Пустой deny не отменяет чужое разрешение.
Схема блокировки metadata endpoint 169.254.169.254 для LLM pod

Оставьте ingress только от реального gateway

Label app=gateway недостаточен, если любой пользователь namespace может поставить его на свой pod. Trust boundary включает не только selector, но и право создавать workload и менять labels. Для multi-tenant кластера закрепите gateway в отдельном namespace с ограниченным RBAC и выберите одновременно namespace и pod.

Не разрешайте ingress «от Service»: NetworkPolicy видит endpoint traffic и выбирает pods/namespace либо IPBlock. В зависимости от dataplane исходный адрес может быть gateway pod, node или внешний балансировщик. Сначала снимите фактический peer, затем пишите selector. Сохранение client IP и PROXY protocol решают другую задачу и не заменяют workload identity.

yaml40-allow-gateway-ingress.yaml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-inference-from-gateway
  namespace: llm-prod
spec:
  podSelector:
    matchLabels:
      app.kubernetes.io/name: llm-server
  policyTypes: [Ingress]
  ingress:
    - from:
        - namespaceSelector:
            matchLabels:
              kubernetes.io/metadata.name: ai-gateway
          podSelector:
            matchLabels:
              app.kubernetes.io/name: llm-gateway
      ports:
        - {protocol: TCP, port: 8000}
Ingress только от gateway namespace и pods

Readiness и liveness probes требуют отдельной проверки. Трафик от node к local pod может обрабатываться иначе, а модель Kubernetes разрешает ingress от node, на котором работает pod. Не делайте из успешной probe вывод, что gateway path открыт; это два разных evidence gate.

Проверьте также sidecars. Если TLS завершается в proxy-контейнере того же pod, NetworkPolicy не различает контейнеры внутри общего network namespace. Сегментация на уровне pod не заменяет аутентификацию приложения, mTLS и минимальные ServiceAccount права.

Наблюдайте verdict, peer и application outcome раздельно

Для диагностики нужны три слоя. Первый — policy verdict: какой endpoint и правило разрешили или отклонили пакет. Второй — фактический peer: куда ушло новое соединение после DNS и балансировки. Третий — outcome приложения: TTFT, streaming completion, ошибки загрузки модели и экспорт telemetry. Один зелёный слой не гарантирует остальные.

Метрики dropped packets без labels workload-а дают шум, а application timeout без сетевого контекста заставляет расширять allow-list наугад. Свяжите flow logs с pod UID, namespace, destination identity и временем rollout. Для внешнего адреса сохраните DNS answer и новый peer; существующий connection pool может пережить изменение policy и исказить тест.

Canary выполняет положительные и отрицательные пробы на fresh connections: резолвит разрешённое имя, подключается к model storage, отправляет telemetry; одновременно пытается открыть соседний namespace, случайный публичный адрес и metadata service. Проверяли ли вы, что запрещённый маршрут падает из-за policy, а не потому, что endpoint недоступен?

Какой сигнал считать доказательством

Сетевой canary проверяет разрешённые и запрещённые подключения LLM workload

Проведите rollout с симметричным rollback

Безопасный rollout начинается не с production namespace, а с копии policy и репрезентативного canary workload. Снимите baseline до enforcement: список peer-ов, DNS answers, error rate, cold-start outcome и завершение streaming-запроса. Затем примените default-deny, добавляйте allow-правила по одному и после каждого повторяйте тот же набор probes.

Не смешивайте изменение NetworkPolicy с обновлением CNI, gateway или модели. Иначе при деградации вы не узнаете owner. Rollback должен быть симметричным: вернуть предыдущую policy revision и повторить те же positive/negative controls. Простое удаление всех политик восстановит доступность, но уничтожит границу безопасности.

  1. Зафиксируйте namespace labels, pod labels и effective CNI.
  2. Создайте canary с тем же ServiceAccount, sidecars и DNS policy.
  3. Проверьте baseline на fresh connections.
  4. Примените default-deny и подтвердите отрицательные тесты.
  5. Верните DNS, ingress gateway и обязательный egress по одному.
  6. Сравните application SLO и flow verdicts.
  7. Проведите rollback rehearsal до production rollout.

Готовность к production rollout

Схема canary rollout и rollback сетевых политик для LLM inference

Когда нужен управляемый egress или выделенная инфраструктура

Не начинайте закупку с тезиса «нам нужен отдельный сервер ради NetworkPolicy». Если проблема в неверном selector, широком allow, connection reuse или отсутствии negative control, новое железо её не исправит. Procurement default — оставить текущую платформу, пока canary не доказал дефицит control plane или ownership.

Обычного NetworkPolicy достаточно, когда зависимости имеют стабильные cluster identities или контролируемые CIDR, а команда умеет наблюдать enforcement. DNS-aware CNI либо egress gateway оправдан, когда внешние адреса меняются и нужен единый audit point. Выделенные nodes или dedicated network edge полезны, если требуется контролировать CNI version, маршрутизацию, firewall, flow logs и change window без noisy-neighbor границы.

Для GPU inference ценность здесь не в обещании «меньше latency». Она в воспроизводимой границе: известный dataplane, понятный owner, ограниченный blast radius и rollback. Параллельно проверьте, что планирование GPU-нагрузки не маскирует очередь accelerator-а под сетевую деградацию.

Сравнивайте варианты по пяти вопросам: кто управляет CNI и обновлениями, где завершается egress, как связать flow с workload identity, кто меняет firewall, можно ли повторить canary и rollback. Только после этого VPS, dedicated node pool или отдельный gateway становятся инженерным решением, а не дорогой попыткой угадать причину.

Вывод: policy должна доказывать границу, а не просто существовать

Kubernetes NetworkPolicy для LLM inference работает, когда превращается в проверяемый сетевой контракт. Начните с карты зависимостей и canary, докажите CNI enforcement, введите default-deny, затем верните DNS, gateway ingress и обязательный egress по одному. Metadata endpoint, соседний namespace и случайный интернет держите как постоянные negative controls.

Главная практическая мысль проста: allow-list без runtime evidence быстро устаревает, а один широкий allow складывается со всеми остальными политиками. Сопоставляйте verdict dataplane, фактический peer и outcome приложения; для внешних FQDN заранее выберите owner — egress proxy, DNS-aware CNI или контролируемый network edge.

Возьмите один non-critical inference workload и пройдите checklist canary-rollout до production. Если текущая платформа не даёт наблюдать путь, фиксировать версии и безопасно откатывать изменения, это конкретное основание обсудить выделенную инфраструктуру King Servers — с понятными требованиями, а не с надеждой, что перенос сам исправит policy.

Memory pressure в LLM-инференсе: cgroup v2, PSI и systemd-oomd
AI

Memory pressure в LLM-инференсе: cgroup v2, PSI и systemd-oomd

Практический runbook для защиты LLM-инференса от дефицита host RAM: PSI, cgroup v2, systemd-oomd, лимиты vLLM, алерты и аварийное восстановление.

Power cap для GPU в LLM inference: production-runbook без гадания по ваттам
AI

Power cap для GPU в LLM inference: production-runbook без гадания по ваттам

Практический runbook для безопасного ограничения мощности GPU: baseline, canary, DCGM и vLLM-метрики, energy-per-token, rollout и rollback.

GPU throttling в LLM inference: мониторинг через DCGM и Prometheus
AI

GPU throttling в LLM inference: мониторинг через DCGM и Prometheus

Практический мониторинг GPU throttling в LLM inference: DCGM Exporter, Prometheus, метрики power/thermal violation, PromQL, алерты и production-runbook.