🐳 Раздел 14 · Вопрос #11

Что такое Service в Kubernetes

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


🟢 Junior Level

30-секундный ответ

Service (Сервис) — это абстрактный объект Kubernetes, предоставляющий единую стабильную точку входа (виртуальный IP-адрес и DNS-имя) и балансировщик нагрузки транспортного уровня (L4) для динамической группы подов.

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

  • Если бы микросервисы обращались друг к другу напрямую по IP подов, любая перезагрузка ломала бы всю систему.
  • Service решает эту проблему: сервис получает постоянный виртуальный адрес (ClusterIP), который никогда не меняется в течение всей жизни сервиса.
  • Клиенты обращаются по стабильному имени (например, http://order-service:8080), а Kubernetes автоматически перенаправляет и балансирует сетевые пакеты между здоровыми подами.

Наглядная аналогия из жизни

Представьте колл-центр крупного банка:

  • Операторы поддержки — это поды (они уходят на перерыв, сменяются, их число растёт в часы пик).
  • Service — это единый номер горячей линии (например, 8-800-100-00-00).
  • Клиенту не нужно знать домашний телефон или имя конкретного дежурного оператора. Клиент набирает один общий номер, а телефонная станция автоматически соединяет его с любым свободным оператором на линии.

Базовый пример манифеста Service

apiVersion: v1
kind: Service
metadata:
  name: payment-service
spec:
  type: ClusterIP # Доступен только внутри кластера
  selector:
    app: payment-service # Ищет все поды с меткой app=payment-service
  ports:
  - name: http
    port: 80         # Порт, на котором Service слушает запросы
    targetPort: 8080 # Порт внутри контейнера Pod (куда пересылать трафик)

Внутри кластера любое другое приложение обращается к нему по DNS:

curl http://payment-service:80/api/v1/pay

🟡 Middle Level

Как Service находит поды: Селекторы и Endpoints

Связь между Service и подами является слабосвязанной и строится на метках (Labels):

  1. В секции spec.selector сервис указывает критерии поиска (например, app: payment-service).
  2. Kubernetes непрерывно сканирует поды с такими метками.
  3. IP-адреса всех подов, успешно прошедших проверку readinessProbe, автоматически заносятся в дочерний системный объект — Endpoints (или EndpointSlice): ```yaml apiVersion: v1 kind: Endpoints metadata: name: payment-service subsets:
    • addresses:
      • ip: 10.244.1.15
      • ip: 10.244.2.34 ports:
      • port: 8080 ```
  4. Если под падает или зависает (readiness probe проваливается), контроллер мгновенно удаляет его IP из списка Endpoints, и трафик перестаёт на него поступать.

Разрешение доменных имён (CoreDNS)

Каждый созданный Service автоматически регистрируется во встроенном DNS-сервере кластера (CoreDNS). Полное доменное имя (FQDN) имеет вид: \(\mathbf{<service\text{-}name>.<namespace>.svc.cluster.local}\)

  • В рамках одного и того же Namespace достаточно обратиться по короткому имени: http://payment-service.
  • При вызове из другого Namespace указывается двухкомпонентное имя: http://payment-service.prod.

4 основных типа Service

| Тип | Где доступен | Для чего используется | | :— | :— | :— | | ClusterIP (дефолт)| Только внутри K8s кластера | Внутреннее межсервисное взаимодействие микросервисов. | | NodePort | На выделенном порту каждого физического сервера (Node) | Локальное тестирование, отладка (диапазон 30000–32767). | | LoadBalancer | В публичном интернете | Создаёт внешний балансировщик облачного провайдера (AWS NLB, GCP LB). | | ExternalName | Внутри кластера как CNAME-алиас | Проброс внешних баз данных (например, db.rds.amazonaws.com) в DNS K8s. |


🔴 Senior Level

Как работает ClusterIP под капотом: Магия kube-proxy

Senior-инженер обязан понимать, что ClusterIP — это фиктивный виртуальный IP-адрес (Virtual IP / VIP).

  • В кластере НЕТ физического сетевого интерфейса, которому был бы назначен этот IP.
  • За обработку пакетов отвечает агент kube-proxy, работающий на каждом сервере в одном из трёх режимов:
[ Пакет на ClusterIP:80 ]
           │
           ▼
[ Ядро Linux: Netfilter / iptables / IPVS ]
           │ (DNAT подмена IP назначения на лету)
           ▼
[ Реальный IP пода: 10.244.2.34:8080 ]

1. Режим iptables (по умолчанию в большинстве кластеров)

  • kube-proxy не перехватывает трафик сам. Он лишь транслирует конфигурацию сервисов в цепочки правил iptables ядра Linux в таблице nat.
  • Для балансировки используется модуль ядра statistic с вероятностным механизмом (Random Probability):
    • Для 3 подов первое правило срабатывает с вероятностью $1/3$, второе — $1/2$, третье забирает остаток.
  • Проблема масштабирования: добавление и проверка правил требует линейного обхода $O(N)$. При $10\,000+$ сервисов пересчёт правил начинает утилизировать до 100% CPU одного ядра сервера.

2. Режим IPVS (IP Virtual Server)

  • Использует транспортный L4-балансировщик, встроенный непосредственно в ядро Linux.
  • Хранит соответствия в хэш-таблицах с константной сложностью поиска $O(1)$.
  • Поддерживает сложные алгоритмы распределения: round-robin, least connections, source hashing. Идеален для больших кластеров.

3. eBPF (Cilium CNI)

  • Полностью исключает kube-proxy и стек iptables/conntrack.
  • Программы eBPF перехватывают пакеты прямо на сетевом сокете ядра через интерфейс XDP (eXpress Data Path), обеспечивая минимально возможную задержку (Zero-overhead networking).

EndpointSlice API: Защита etcd от Watch Storm

В ранних версиях Kubernetes (до 1.21) все IP-адреса подов сервиса хранились в одном монолитном объекте Endpoints.

  • Если у сервиса 5000 подов, то при падении всего одного пода пересылался весь объект размером 2 МБ на все узлы кластера.
  • Это вызывало перегрузку API-сервера и etcd (Watch Storm).
  • Современное решение — EndpointSlice: K8s автоматически нарезает список эндпоинтов на компактные слайсы по 100 адресов в каждом. При смене одного пода обновляется только один слайс размером в пару килобайт.

Headless Service (clusterIP: None)

Если в спецификации указать clusterIP: None:

  • Kubernetes НЕ выделяет виртуальный VIP и не настраивает правила балансировки в kube-proxy.
  • При DNS-запросе к сервису CoreDNS возвращает полный список A-записей с реальными IP-адресами всех здоровых подов.
  • Применение: распределённые Stateful-системы (Kafka, Cassandra, MongoDB), где Java-клиент должен сам управлять соединениями к конкретным нодам-лидерам и репликам.

4 Tricky Questions

1. Почему попытка отправить ICMP-запрос ping <ClusterIP> изнутри пода всегда завершается 100% потерей пакетов, хотя HTTP-запросы через curl работают мгновенно?

Ответ: Виртуальный IP-адрес сервиса (ClusterIP) существует исключительно как правило подмены сетевых адресов (DNAT) в подсистеме ядра Netfilter (iptables или IPVS). Эти правила настроены строго для протоколов TCP и UDP на определённых портах. Протокол ICMP (на котором работает утилита ping) не имеет портов и не обрабатывается правилами трансляции сервиса. Поскольку интерфейса с таким IP физически не существует в природе, ядру некому доставить ICMP Echo Request, и пакет молча отбрасывается.


2. Как настроить Service в Kubernetes для подключения к внешней СУБД Oracle/PostgreSQL, расположенной вне кластера, используя внутренний Service Discovery?

Ответ: Создаётся Service БЕЗ селектора (selector), и вручную объявляется объект Endpoints с тем же именем:

apiVersion: v1
kind: Service
metadata:
  name: external-oracle-db
spec:
  ports:
  - port: 1521
---
apiVersion: v1
kind: Endpoints
metadata:
  name: external-oracle-db
subsets:
  - addresses:
      - ip: 192.168.10.50 # IP физического сервера БД вне K8s
    ports:
      - port: 1521

Java-приложение внутри кластера использует стабильное имя jdbc:oracle:thin:@external-oracle-db:1521/XEPDB1. Если физический IP базы данных изменится, достаточно изменить манифест Endpoints без перезапуска и переконфигурации микросервисов.


3. В чём отличие port от targetPort в спецификации Service, и что произойдёт, если targetPort опущен?

Ответ:

  • port: это TCP/UDP порт, который открывает сам Service на своём виртуальном ClusterIP. Именно к этому порту обращаются клиенты внутри кластера.
  • targetPort: это реальный порт в контейнере пода, на котором слушает процесс приложения (например, порт 8080 встроенного Tomcat в Spring Boot). Ядро Linux транслирует запросы с port на targetPort.
  • Если targetPort не указан: Kubernetes по умолчанию считает, что значение targetPort строго равно значению port.

4. Почему использование свойства sessionAffinity: ClientIP в Service может сломать балансировку нагрузки в микросервисной архитектуре?

Ответ: При включении sessionAffinity: ClientIP kube-proxy направляет все запросы от одного IP-адреса клиента на один и тот же фиксированный под в течение заданного тайм-аута. В архитектуре с API Gateway (Ingress-контроллер, Spring Cloud Gateway) абсолютно все входящие запросы поступают к сервису с одного и того же IP-адреса шлюза. В результате sessionAffinity привяжет весь входящий клиентский трафик к одному-единственному поду, перегружая его до падения по CPU/OOM, в то время как остальные поды сервиса будут простаивать с нулевой нагрузкой.


🎯 Шпаргалка для интервью

Главное о Service

  • Суть: стабильный сетевой фасад (L4 VIP + DNS) для эфемерных подов.
  • Поиск подов: через spec.selector по меткам (Labels).
  • Связующий объект: Endpoints / EndpointSlice (хранит IP живых подов).
  • DNS: доступен по имени service-name (в том же namespace) или FQDN service.namespace.svc.cluster.local.
  • Реализация: агент kube-proxy через правила ядра iptables (по умолчанию) или IPVS ($O(1)$ для хайлоада).
  • Headless: clusterIP: None — CoreDNS возвращает IP всех подов напрямую (для StatefulSet/Kafka).

Типы Service

| Тип Service | Область видимости | Назначение | | :— | :— | :— | | ClusterIP | Только внутри кластера K8s | Стандарт по умолчанию для межсервисного общения | | NodePort | Порт 30000–32767 на всех нодах | Доступ без облачного балансировщика | | LoadBalancer| Интернет (внешний облачный IP)| Продакшен точка входа через облачный LB | | ExternalName| Внутренний CNAME редирект | Подключение внешних систем по домену |

Красные флаги на собеседовании (Чего говорить нельзя)

  • ❌ «Service — это отдельный контейнер с Nginx, который крутится и проксирует трафик» — Service это абстракция, реализованная через правила ядра iptables/IPVS.
  • ❌ «ClusterIP можно пропинговать утилитой ping» — виртуальный IP не отвечает на ICMP, только TCP/UDP.
  • ❌ «Service балансирует HTTP-трафик по URL и заголовкам» — Service работает на L4 (TCP/IP). Маршрутизацией на L7 (HTTP-пути) занимается Ingress.

Связанные вопросы