ZIM-НИЙ SAAALEЗимние скидки: до −50% на старт и −20% на продление
до 31.01.2026 Подробнее
Выберите продукт

Kubernetes Service и Endpoints: почему kubectl get ep показывает пусто и как это чинить

Бывает, что Service в Kubernetes «живёт»: ClusterIP выдан, DNS работает, но трафик не идёт, а kubectl get ep пустой. Разберём, как Service выбирает Pod по selector и labels, почему Ready важнее «порты открыты», чем Endpoints отличается от EndpointSlice и где чаще всего ошибаются с targetPort.
Kubernetes Service и Endpoints: почему kubectl get ep показывает пусто и как это чинить

В Kubernetes есть классическая ловушка: Service создан, DNS-имя резолвится, ClusterIP выдан, а запросы заканчиваются таймаутом. В логах Ingress/контроллера всплывает «kubernetes no endpoints», а kubectl get ep показывает пустоту. Обычно это не «магия сети», а вполне конкретная причина: Service не смог сопоставить свои селекторы с Pod, либо Pod не попали в готовые endpoints.

Ниже — практичная схема диагностики: от kubectl describe service и проверки selector/labels до нюансов targetPort и механизма EndpointSlice. Логика простая: идём по цепочке, фиксируем, на каком шаге всё «рассыпалось», и правим точечно.

Что такое Endpoints и почему это критично для Service

Service в Kubernetes — это стабильная точка входа (VIP + DNS) и правила маршрутизации. Но фактически он «работает» только когда существует список бэкендов — IP:port конкретных Pod. Исторически этот список публиковался в объекте Endpoints. Сейчас чаще используется EndpointSlice, но смысл одинаковый: контроллер смотрит на Service, находит подходящие Pod и публикует их адреса как endpoints.

Если endpoints пустые, то трафик направлять некуда: kube-proxy (или dataplane CNI) не сможет проксировать запросы, а Ingress/контроллер обычно исключит upstream и будет ругаться «no endpoints».

Главная мысль: Service не ищет Pod «по имени». Он выбирает Pod по labels, которые совпадают с selector в Service.

Быстрый чек-лист: как понять, почему kubectl get ep пустой

Начинайте с трёх проверок и не перескакивайте шаги. Если на шаге 3 вы не находите Pod по селектору — дальнейшие проверки портов и сети почти всегда бессмысленны.

Шаг 1: посмотреть Service и его selector

kubectl get svc -n NAMESPACE
kubectl describe service SERVICE_NAME -n NAMESPACE
kubectl get service SERVICE_NAME -n NAMESPACE -o yaml

В kubectl describe service внимательно смотрите:

  • Selector — по каким меткам выбираются Pod;
  • Port и TargetPort — куда именно пойдёт трафик на стороне Pod;
  • Endpoints — если там <none>, бэкенды не найдены или не опубликованы;
  • Events — иногда прямо подсказывают, что мешает публикации.

Шаг 2: проверить Endpoints и EndpointSlice

kubectl get endpoints -n NAMESPACE
kubectl get endpoints SERVICE_NAME -n NAMESPACE -o wide
kubectl get endpointslices -n NAMESPACE -l kubernetes.io/service-name=SERVICE_NAME

Важно: в части кластеров «истина» живёт в EndpointSlice. Поэтому если kubectl get ep пустой или выглядит странно — сразу проверяйте slices.

Шаг 3: найти Pod, которые должны попасть под selector

Возьмите селектор из Service и выберите Pod по меткам. Например, если в Service:

selector:
  app: web
  tier: frontend

То проверка выглядит так:

kubectl get pods -n NAMESPACE -l app=web,tier=frontend -o wide
kubectl describe pod POD_NAME -n NAMESPACE

Если выборка Pod пустая — вы почти нашли причину: неверные labels на Pod, неверный selector в Service или объекты находятся в разных namespace.

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

Самая частая причина no endpoints: selector и labels не совпали

В реальных инцидентах чаще всего проблема не в CNI и не в kube-proxy, а в том, что Service выбирает «никого».

Типовые сценарии рассинхронизации меток

  • Переименовали label в Deployment, но забыли обновить Service.
  • Разные окружения: у Pod метка env=prod, а Service ожидает env=stage.
  • Helm values: селектор в шаблоне Service зависит от values, а релиз обновили частично.
  • Service без selector: тогда endpoints должны быть созданы вручную, но их нет.

Как быстро сравнить selector и labels

Ваша цель — добиться, чтобы выборка Pod по селектору Service возвращала ровно те Pod, которые должны обслуживать трафик.

kubectl get service SERVICE_NAME -n NAMESPACE -o jsonpath='{.spec.selector}'
kubectl get pods -n NAMESPACE --show-labels

Если меток много, удобнее посмотреть метки конкретного Pod:

kubectl get pod POD_NAME -n NAMESPACE -o jsonpath='{.metadata.labels}'

Практическое правило: сначала добейтесь, чтобы kubectl get pods -l ... показывал нужные Pod. Только после этого имеет смысл разбираться с targetPort, readiness и сетевыми нюансами.

Вторая частая причина: Port и targetPort не соответствуют реальности

Даже если Pod выбраны правильно, Service может отправлять трафик «не туда». В этом случае endpoints обычно не пустые, но симптомы похожи: таймауты, 502/504 на Ingress, «приложение не отвечает».

Коротко:

  • port — порт Service (куда стучатся клиенты внутри кластера);
  • targetPort — порт на Pod, куда Kubernetes направляет трафик.

targetPort может быть числом или именем порта. Ошибка часто прячется именно в «именах», особенно когда в Pod несколько контейнеров.

Проверка сводится к сопоставлению Service → targetPort → фактический порт приложения.

kubectl describe service SERVICE_NAME -n NAMESPACE
kubectl get pod POD_NAME -n NAMESPACE -o yaml

В манифесте Pod смотрите containersports. Kubernetes не требует указывать containerPort, но для людей это сильно упрощает диагностику.

Если вы используете Ingress, полезно держать под рукой обзор по вариантам контроллеров и типовым ошибкам маршрутизации: сравнение Ingress-контроллеров и практические нюансы.

Схема цепочки Service → selector → Pod → EndpointSlice

Почему endpoints могут быть пустыми даже при правильных labels

Бывает, что селектор совпал и Pod существуют, но endpoints не появляются или публикуются «не готовыми». Чаще всего виновата готовность Pod.

Pod не Ready: адреса не добавляются

По умолчанию Service публикует только Ready-адреса. Поэтому сначала проверьте состояние:

kubectl get pods -n NAMESPACE -l app=web -o wide
kubectl describe pod POD_NAME -n NAMESPACE

Особенно внимательно смотрите:

  • ошибки readinessProbe (неверный путь, порт, таймауты);
  • события ImagePullBackOff, CrashLoopBackOff, проблемы с PVC;
  • зависимости приложения (БД, очередь), из-за которых readiness не проходит.

publishNotReadyAddresses: когда нужно и почему опасно

Опция Service publishNotReadyAddresses позволяет публиковать адреса Pod даже если они не Ready. Это полезно для некоторых stateful-сценариев (bootstrap/peer discovery), но для обычных веб-сервисов часто приводит к флаппингу и случайным 502/504.

Service без selector: endpoints должны быть «ручными»

У Service может не быть selector. Это нормально, когда вы подключаете внешние бэкенды (вне кластера) или строите нестандартную схему. Но тогда Kubernetes сам endpoints не соберёт.

Признаки простые: в kubectl describe service поле Selector пустое, а kubectl get ep не меняется от каких-либо labels на Pod.

В таком варианте должны существовать отдельные объекты Endpoints или EndpointSlice, созданные вручную (или оператором). Если их нет — это и есть причина «no endpoints».

FastFox SSL
Надежные SSL-сертификаты
Мы предлагаем широкий спектр SSL-сертификатов от GlobalSign по самым низким ценам. Поможем с покупкой и установкой SSL бесплатно!

EndpointSlice: чем отличается и как читать

EndpointSlice — современная замена «монолитному» Endpoints. Она масштабируется лучше (много Pod — много slices), хранит больше метаданных и стабильнее ведёт себя в больших кластерах.

Минимальная практика для админа: уметь найти slices по Service и увидеть, какие адреса и порты опубликованы.

kubectl get endpointslices -n NAMESPACE -l kubernetes.io/service-name=SERVICE_NAME
kubectl describe endpointslice ENDPOINTSLICE_NAME -n NAMESPACE

В описании смотрите:

  • список endpoints и условия ready/serving/terminating;
  • список ports (имя порта и номер);
  • привязку к Service по лейблу kubernetes.io/service-name.

Нюансы, которые ломают доступ, когда «вроде всё правильно»

Namespace: Service и Pod должны быть в одном пространстве имён

Service выбирает Pod только внутри своего namespace. Если Service в default, а Deployment в app, endpoints не появятся никогда.

kubectl get svc -A | grep SERVICE_NAME
kubectl get pods -A -l app=web

Headless Service вместо обычного

Для StatefulSet часто используют headless Service (clusterIP: None). Endpoints при этом будут, но поведение DNS и ожидания клиентов отличаются. Если вы ожидаете балансировку на ClusterIP, а создали headless — будет ощущение «не работает».

Named ports и одинаковые имена в разных контейнерах

Если targetPort задан именем, Kubernetes ищет порт с таким именем в Pod. При нескольких контейнерах и копипасте легко получить ситуацию, когда имя совпало, а номер порта — не тот (или нужный порт вообще в другом контейнере). Если именованные порты не нужны — используйте числовой targetPort.

Диагностика «с конца»: сравниваем port-forward на Pod и на Service

Когда непонятно, проблема в Service/Endpoints или в приложении, удобно сравнить порт-форвард на Pod и на Service. Если Pod отвечает, а Service — нет, почти наверняка проблема в Service, endpoints или targetPort.

kubectl port-forward -n NAMESPACE pod/POD_NAME 18080:8080
kubectl port-forward -n NAMESPACE service/SERVICE_NAME 18081:80

Порт-форвард не проверяет весь сетевой тракт кластера, но отлично подсвечивает типовые ошибки конфигурации Service.

Рецепты исправления: что менять и где

Если не совпали labels и selector

  • Приведите .spec.selector Service к фактическим меткам Pod (или наоборот), чтобы выборка Pod была однозначной.
  • Проверьте, что селектор не слишком общий, иначе Service может «подхватить» чужие Pod.

Если targetPort неверный

  • Исправьте targetPort на реальный порт приложения.
  • Если используете именованные порты, убедитесь, что имя совпадает в Service и в Pod.

Если Pod не Ready

  • Чините readiness: путь, порт, таймаут, зависимости (БД/очереди), DNS.
  • Смотрите события Pod и логи контейнера — это обычно быстрее, чем «ковырять сеть».

Мини-шпаргалка команд для инцидента no endpoints

kubectl describe service SERVICE_NAME -n NAMESPACE
kubectl get endpoints SERVICE_NAME -n NAMESPACE -o wide
kubectl get endpointslices -n NAMESPACE -l kubernetes.io/service-name=SERVICE_NAME
kubectl get pods -n NAMESPACE -l key=value -o wide
kubectl describe pod POD_NAME -n NAMESPACE

Пример вывода kubectl describe service и kubectl describe endpointslice

Итог: логика проста, если идти по цепочке

Сообщение «kubernetes no endpoints» почти всегда означает разрыв в одной из связок:

  • Service selector не находит Pod по labels;
  • Pod найдены, но не попали в endpoints из-за статуса Ready;
  • endpoints есть, но targetPort ведёт не на тот порт;
  • вы смотрите в Endpoints, а актуальная картина в EndpointSlice;
  • Service вообще без selector и требует ручных endpoints.

Держите в голове трассировку: Service → selector → Pod → readiness → endpoints/endpointslice → targetPort → приложение. Если идти ровно по ней, большинство проблем находится за 5–10 минут даже в незнакомом кластере.

Если вы разворачиваете сервисы под нагрузкой и важна предсказуемая сетка, ресурсы и изоляция на узлах, удобнее держать инфраструктуру на управляемых виртуалках: VDS часто даёт больше контроля над сетью, CNI и лимитами, чем «сборная солянка» из разрозненных сред.

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

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

Kubernetes: ImagePullBackOff из-за TLS/CA при pull из registry (self-signed, MITM, custom CA) OpenAI Статья написана AI (GPT 5)

Kubernetes: ImagePullBackOff из-за TLS/CA при pull из registry (self-signed, MITM, custom CA)

Если Pod уходит в ImagePullBackOff с x509 unknown authority, проблема почти всегда в TLS-доверии: self-signed реестр, корпоративны ...
SSH на Linux без боли: правим sshd_config через systemd drop-in, проверяем ss -tlpn и делаем rollback OpenAI Статья написана AI (GPT 5)

SSH на Linux без боли: правим sshd_config через systemd drop-in, проверяем ss -tlpn и делаем rollback

Пошагово разбираем безопасные изменения SSH-сервера без риска потерять доступ: план со страховочными сессиями, снимок состояния, п ...
PostgreSQL и /tmp: temp_files, disk full и настройка памяти для sort/hash join OpenAI Статья написана AI (GPT 5)

PostgreSQL и /tmp: temp_files, disk full и настройка памяти для sort/hash join

Если PostgreSQL внезапно упирается в «No space left on device» из-за переполнения /tmp, почти всегда виноваты временные файлы запр ...