Hubble: наблюдаемость сетевых потоков внутри Kubernetes
Published: 2026-02-08
Hubble от Cilium — это слой сетевой наблюдаемости, встроенный прямо в eBPF-датаплейн. Каждый пакет, проходящий через кластер — под-под, под-сервис, под-внешний адрес — фиксируется с указанием источника, назначения, вердикта и причины. Никаких sidecar-прокси, никакого сэмплирования, никаких лишних хопов.
Этот пост — полная настройка, использование CLI для типичных сценариев отладки, метрики Prometheus и операционные паттерны, которые мы используем при диагностике сетевых проблем в шестикластерной среде.
Почему Hubble, а не tcpdump или логи сетевых политик
Традиционные инструменты отладки сети Kubernetes имеют серьёзные ограничения:
tcpdumpтребует exec в под или на узел, и нужно заранее знать, на каком узле проходит трафик. При 6 кластерах и 200+ подах на узле — это поиск иголки в стоге сена.- Логи NetworkPolicy о дропах отсутствуют в vanilla Kubernetes — пакеты отбрасываются молча, без audit trail.
- Наблюдаемость через service mesh (Istio, Linkerd) требует внедрения sidecar, что добавляет каждому поду задержку, потребление памяти и сложность.
Hubble записывает все события потоков на уровне ядра через eBPF. Агент работает на каждом узле как часть DaemonSet Cilium — никаких дополнительных подов, никаких sidecar, никаких накладных расходов сверх того, что и так добавляет Cilium. Через hubble-relay данные доступны в масштабе всего кластера.
Компоненты
hubble-agent — встроен в каждый pod с Cilium agent. Экспортирует события потоков по gRPC.
hubble-relay — агрегирует события со всех узлов, предоставляет единый gRPC-эндпоинт для видимости на уровне всего кластера.
hubble-ui — веб-интерфейс для просмотра потоков и построения карт зависимостей сервисов в реальном времени.
Включите все три в Helm values для Cilium:
yamlhubble:
enabled: true
metrics:
enabled:
- dns:query;ignoreAAAA
- drop
- tcp
- flow
- icmp
- http
serviceMonitor:
enabled: true
labels:
release: kube-prom-stack
relay:
enabled: true
prometheus:
enabled: true
serviceMonitor:
enabled: true
labels:
release: kube-prom-stack
ui:
enabled: true
labels: release: kube-prom-stack в serviceMonitor — это то, как Prometheus обнаруживает endpoint метрик: kube-prometheus-stack деплоится с label-селектором release=kube-prom-stack.
Метрика dns:query;ignoreAAAA игнорирует AAAA-запросы (IPv6) в метриках DNS, что существенно снижает кардинальность для IPv4-кластеров. Иначе каждый DNS-запрос hostname генерирует две записи метрик.
Hubble CLI
Установите hubble локально и пробросьте порт relay:
bashkubectl port-forward -n kube-system svc/hubble-relay 4245:80 &
# Последние 100 потоков по всему кластеру
hubble observe --last 100
# Отброшенные потоки в namespace
hubble observe --namespace app --verdict DROPPED
# Потоки от конкретного пода
hubble observe --pod app/backend --protocol TCP
# Режим слежения (как tail -f)
hubble observe --follow --namespace default
Или запустите Hubble CLI прямо внутри пода Cilium на любом узле:
bashkubectl exec -n kube-system ds/cilium -- hubble observe --last 50
Это избавляет от настройки port-forward — полезно при реагировании на инцидент, когда нужны ответы быстро.
Фильтр --verdict DROPPED — самый быстрый способ диагностировать, почему трафик не доходит до пода. Частые причины:
NetworkPolicyблокирует поток — вердикт покажетPOLICY_DENIED- Нет активного эндпоинта — вердикт покажет
UNKNOWN_CONNECTION - Несовпадение порта — вердикт покажет
PORT_UNROUTABLE
Формат вывода
По умолчанию вывод человекочитаемый. Для структурированной обработки:
bash# JSON-вывод (для передачи в jq)
hubble observe --last 100 --output json | jq '.flow | select(.verdict == "DROPPED")'
# Подсчёт дропов по source namespace
hubble observe --last 1000 --output json \
| jq -r 'select(.flow.verdict == "DROPPED") | .flow.source.namespace' \
| sort | uniq -c | sort -rn
Видимость DNS
Hubble перехватывает DNS-запросы на уровне пода:
bashhubble observe --type l7 --protocol DNS
hubble observe --type l7 --protocol DNS --pod app/backend
Вывод показывает, какой под запрашивал какой hostname и каким был ответ. Незаменимо при отладке недоступности внешнего сервиса — видно, возвращает ли DNS правильный IP, происходит ли запрос вообще, или возвращается NXDOMAIN.
Типичные DNS-проблемы, которые выявляет Hubble:
- Приложение запрашивает неправильный hostname (жёстко заданный IP или неверная переменная окружения)
- DNS-разрешение успешно, но IP недоступен (проблема NetworkPolicy, не связанная с DNS)
- DNS-запросы завершаются по таймауту (перегруженный CoreDNS)
Для проверки производительности CoreDNS:
bash# DNS-запросы к kube-dns от конкретного пода
hubble observe --to-pod kube-system/coredns --protocol DNS --follow
Если от одного пода идёт много повторных запросов — CoreDNS может оказаться узким местом.
Отладка NetworkPolicy
Предположим, трафик от frontend к backend молча отбрасывается. Без Hubble пришлось бы добавлять отладочные логи в приложение и деплоить заново. С Hubble:
bashhubble observe \
--namespace app \
--from-pod app/frontend \
--to-pod app/backend \
--verdict DROPPED
Если вердикт POLICY_DENIED с reason: INGRESS_DENIED, вы знаете точное направление и какая политика блокирует. Дальше:
bashkubectl get ciliumnetworkpolicy -n app
kubectl get networkpolicy -n app
Найдите политику и скорректируйте селектор ingress. В классическом NetworkPolicy это обычно добавление недостающего селектора from. В CiliumNetworkPolicy можно также ограничивать по L7 — HTTP-методу, пути, заголовкам.
AUDIT-режим для безопасного ввода политик
Режим AUDIT позволяет тестировать ограничивающую политику до её применения:
yamlapiVersion: "cilium.io/v2"
kind: CiliumNetworkPolicy
metadata:
name: restrict-backend
namespace: app
spec:
endpointSelector:
matchLabels:
app: backend
ingress:
- fromEndpoints:
- matchLabels:
app: frontend
policyAuditMode: true # не отбрасывает пакеты, только логирует
Установите policyAuditMode: true, задеплойте, наблюдайте AUDIT-вердикты в Hubble 24 часа, затем уберите флаг для применения. Ужесточение политик без простоя.
bash# Наблюдать audit-вердикты для backend
hubble observe --namespace app --to-pod app/backend --verdict AUDIT --follow
Карта сервисов в Hubble UI
UI рисует граф зависимостей в реальном времени. Каждый узел — это namespace или рабочая нагрузка. Рёбра окрашены по уровню дропов и подписаны частотой запросов.
В нашей настройке UI доступен через ApisixRoute с проверкой группы RBAC — только для внутренних пользователей:
yamlapiVersion: apisix.apache.org/v2
kind: ApisixRoute
metadata:
name: hubble-ui
namespace: ingress-apisix
spec:
http:
- name: hubble
match:
hosts:
- hubble.infra.example.com
paths:
- "/*"
backends:
- serviceName: hubble-ui
serviceNamespace: kube-system
servicePort: 80
Карта сервисов — первое место, куда мы смотрим после нового деплоя, когда что-то «тормозит». Часто карта показывает новую downstream-зависимость без ограничения частоты запросов, которая теперь получает их шквал. Визуализация делает это сразу очевидным: толстые красные рёбра к одному сервису — этот сервис отбрасывает трафик.
Метрики потоков в Prometheus
С serviceMonitor.enabled: true hubble-relay экспортирует метрики Prometheus в существующую Grafana:
promql# Частота дропов по namespace
rate(hubble_drop_total[5m])
# Частота дропов по причине (POLICY_DENIED, NO_TUNNEL_KEY и т.д.)
sum by (reason) (rate(hubble_drop_total[5m]))
# Частота HTTP-запросов по destination
rate(hubble_http_requests_total[5m])
# Частота HTTP-ошибок (4xx, 5xx)
rate(hubble_http_requests_total{status=~"[45].."}[5m])
# Частота DNS-ошибок
rate(hubble_dns_error_total[5m])
# Частота DNS-запросов по подам (топ-10)
topk(10, rate(hubble_dns_queries_total[5m]))
В нашем кластерном дашборде Grafana есть отдельная строка «Network»: частота дропов по namespace, частота HTTP-ошибок по сервисам, частота DNS-запросов. Она находится между строками «Node» и «App» и часто выявляет первопричину ошибок на уровне приложения раньше, чем их замечает команда разработки.
Алерт на всплески дропов
Полезное правило PrometheusRule:
yaml- alert: NetworkDropSpike
expr: sum(rate(hubble_drop_total[5m])) by (namespace) > 10
for: 2m
labels:
severity: warning
annotations:
summary: "Высокая частота дропов в {{ $labels.namespace }}"
description: "{{ $value | printf \"%.1f\" }} дропов/сек в {{ $labels.namespace }}"
Срабатывает, если в любом namespace больше 10 дропов в секунду на протяжении 2 минут. Частые причины: неправильно настроенный NetworkPolicy после деплоя или новый сервис, которому не открыт проход через политику.
Вердикты Cilium NetworkPolicy
Каждый поток Hubble имеет вердикт и до трёх вердиктов политик:
| Вердикт | Значение |
|---|---|
FORWARDED |
пакет прошёл все политики |
DROPPED |
заблокирован NetworkPolicy |
ERROR |
проблема с эндпоинтом |
AUDIT |
был бы заблокирован, политика в режиме аудита |
REDIRECTED |
перенаправлен к прокси (например, L7-политика) |
Хранение и производительность
Потоки Hubble хранятся в памяти в кольцевом буфере на каждом узле. Размер буфера по умолчанию — 4096 событий на узел. Для высоконагруженных кластеров увеличьте:
yamlhubble:
eventQueueSize: 65536
eventBufferCapacity: 65535
Потоки старше ёмкости кольцевого буфера теряются. Если нужно более длительное хранение, пересылайте потоки во внешнее хранилище через gRPC-экспорт Hubble или используйте метрики Prometheus (с их retention).
При очень высоком трафике (10k+ потоков в секунду) накладные расходы CPU на обработку событий на каждом узле могут стать заметными. Профилируйте с cilium monitor --type drop перед включением всех метрик одновременно — начинайте с drop и dns, добавляйте http и tcp только при необходимости.