Какие типы Service существуют (ClusterIP, NodePort, LoadBalancer)
В Kubernetes существует 4 основных типа Service, которые определяют уровень сетевой доступности приложения (будет ли оно видно только внутри кластера или доступно пользователям...
🟢 Junior Level
30-секундный ответ
В Kubernetes существует 4 основных типа Service, которые определяют уровень сетевой доступности приложения (будет ли оно видно только внутри кластера или доступно пользователям из интернета):
ClusterIP(по умолчанию): сервис получает стабильный виртуальный IP, доступный строго внутри кластера. Внешний трафик из интернета сюда попасть не может. Используется для 95% микросервисов (связь бэкенда с базой данных, кэшем, очередями).NodePort: открывает выделенный статический порт (из диапазона30000–32767) на каждом физическом сервере (Node) кластера. Позволяет достучаться до приложения извне по адресуhttp://<IP-любой-ноды>:NodePort.LoadBalancer: автоматически заказывает у внешнего облачного провайдера (AWS, GCP, Azure, Yandex Cloud) полноценный физический балансировщик нагрузки с публичным IP-адресом.ExternalName: специальный тип без селектора и без проксирования трафика. Возвращает DNS CNAME-запись, перенаправляя запросы на внешний домен (например,db.external-provider.com).
Наглядная аналогия «Матрёшка»
Архитектурно типы сервисов вложены друг в друга как русская матрёшка:
ClusterIP— самая маленькая внутренняя матрёшка (базовый маршрут к подам).NodePort— средняя матрёшка: он оборачиваетClusterIP, пробрасывая порт на хосты.LoadBalancer— самая большая внешняя матрёшка: он заказывает внешний балансировщик, направляет трафик наNodePort, который передаёт его наClusterIP, а тот балансирует на Pod!
Сводная таблица для быстрого понимания
| Тип сервиса | Внешний IP | Доступен из интернета | Основное назначение |
| :— | :—: | :—: | :— |
| ClusterIP | ❌ Нет | ❌ Нет | Межсервисное общение (Back $\to$ DB) |
| NodePort | ❌ Нет (порт ноды) | 🟡 Да (по IP нод) | Тестовые стенды, прямое подключение |
| LoadBalancer | 🟢 Да (Public IP) | 🟢 Да | Продакшен-доступ для внешних клиентов |
| ExternalName | ❌ Нет (DNS CNAME) | ❌ Нет | Псевдоним для внешних баз данных |
🟡 Middle Level
Детальная конфигурация и спецификация
1. ClusterIP (Внутрикластерный стандарт)
apiVersion: v1
kind: Service
metadata:
name: order-service
spec:
type: ClusterIP # Можно опустить, выставляется по умолчанию
selector:
app: order-service
ports:
- port: 80 # Порт сервиса
targetPort: 8080 # Порт контейнера Java Spring Boot
2. NodePort (Доступ через порты хостов)
apiVersion: v1
kind: Service
metadata:
name: debug-service
spec:
type: NodePort
selector:
app: order-service
ports:
- port: 80
targetPort: 8080
nodePort: 31234 # Диапазон: 30000–32767 (если опустить, K8s выберет случайный)
Запрос на адрес 192.168.1.10:31234 перенаправляется на сервис, даже если на этой конкретной ноде вообще не запущено ни одного пода order-service.
3. LoadBalancer (Интеграция с облачной инфраструктурой)
apiVersion: v1
kind: Service
metadata:
name: public-gateway
spec:
type: LoadBalancer
selector:
app: api-gateway
ports:
- port: 443
targetPort: 8443
Cloud Controller Manager перехватывает событие создания такого сервиса и через облачный API поднимает AWS NLB или Google Cloud Network Load Balancer.
4. ExternalName (Внешний CNAME редирект)
apiVersion: v1
kind: Service
metadata:
name: postgres-db
spec:
type: ExternalName
externalName: mydb-cluster.rds.amazonaws.com # CNAME запись в CoreDNS
Java-приложение подключается к jdbc:postgresql://postgres-db:5432/mydb, а CoreDNS возвращает CNAME на облачную AWS RDS.
Архитектурный выбор: LoadBalancer vs Ingress
В продакшене каждый облачный LoadBalancer стоит денег (от 15 до 30 долларов в месяц за каждый экземпляр в AWS/GCP):
- Антипаттерн: делать 20 микросервисов с типом
LoadBalancer($20 \times $25 = $500$ ежемесячно только за сетевые балансировщики). - Best Practice (Паттерн Ingress):
- Создаётся ровно один сервис типа
LoadBalancer, смотрящий в интернет. - За ним работает Ingress Controller (Nginx, Traefik, Envoy).
- Все остальные микросервисы объявляются как дешёвые и безопасные
ClusterIP. - Ingress распределяет входящий HTTP/HTTPS трафик по путям (
/api/orders,/api/users) на внутренниеClusterIPсервисы.
- Создаётся ровно один сервис типа
🔴 Senior Level
Политика маршрутизации: externalTrafficPolicy: Cluster vs Local
При использовании сервисов типов NodePort и LoadBalancer критически важно понимать поведение параметра spec.externalTrafficPolicy:
[ externalTrafficPolicy: Cluster ] [ externalTrafficPolicy: Local ]
Клиент Клиент
│ │
▼ ▼
[ Node 1 (без пода) ] [ Node 1 (без пода) ]
│ (SNAT + Extra Hop) ❌ Трафик сброшен!
▼
[ Node 2 (с подом) ] [ Node 2 (с подом) ]
🟢 Обработка без SNAT!
1. externalTrafficPolicy: Cluster (по умолчанию)
- Трафик, пришедший на любую ноду кластера, может быть переслан через внутреннюю оверлейную сеть на совершенно другую ноду, где реально запущен под.
- Плюсы: идеальная равномерная балансировка нагрузки между подами.
- Минусы:
- Лишний сетевой переход (Extra Network Hop): повышает сетевую задержку.
- Потеря Client IP (SNAT): ядро выполняет подмену исходного адреса (Source NAT). Java-приложение видит IP-адрес внутренней ноды вместо реального публичного IP клиента, что ломает аудит безопасности и rate-limiting.
2. externalTrafficPolicy: Local
- Трафик направляется только на поды, работающие на этой же самой ноде. Если подов на ноде нет, трафик отбрасывается.
- Плюсы:
- Сохраняется реальный исходный IP клиента (Source IP Preservation) без SNAT.
- Отсутствует второй межсерверный hop (минимальные задержки).
- Минусы: риск неравномерной загрузки подов при перекосе трафика между нодами. Облачный балансировщик обязан отправлять health-проверки на порт
healthCheckNodePort.
Частные облачные сети (Internal Load Balancer)
По умолчанию сервис type: LoadBalancer заказывает публичный IP. Для создания балансировщика, доступного только внутри корпоративной VPC, используют аннотации облачного провайдера:
metadata:
name: internal-service
annotations:
# Для AWS:
service.beta.kubernetes.io/aws-load-balancer-internal: "true"
# Для GCP:
networking.gke.io/load-balancer-type: "Internal"
On-Premise балансировка: MetalLB
В локальных датацентрах (Bare-Metal K8s) нет API облачного провайдера, и сервис LoadBalancer навсегда зависает в статусе <pending>.
Для решения этой проблемы разворачивают MetalLB:
- Layer 2 Mode (ARP/NDP): один из серверов кластера отвечает на ARP-запросы для выделенного виртуального IP из пула. При падении сервера другой узел перехватывает IP через Gratuitous ARP.
- BGP Mode: узлы кластера устанавливают BGP-сессии с физическими датацентровыми маршрутизаторами (Cisco, Juniper) и анонсируют маршруты к сервисам с поддержкой Equal-Cost Multi-Path (ECMP) балансировки.
4 Tricky Questions
1. Почему при создании сервиса type: LoadBalancer Kubernetes всё равно выделяет для него NodePort и ClusterIP? Можно ли отключить выделение NodePort?
Ответ:
Архитектурно облачный балансировщик (например, классический AWS ELB) не имеет прямой маршрутизации в оверлейную сеть подов (10.244.0.0/16). Он принимает внешний трафик и пересылает его на физические IP серверов кластера на выделенный NodePort. Далее kube-proxy через правила ClusterIP маршрутизирует пакет до пода.
Отключение NodePort: начиная с Kubernetes 1.20, доступно свойство spec.allocateLoadBalancerNodePorts: false. Если облачный контроллер поддерживает прямую маршрутизацию пакетов в поды (например, AWS VPC CNI с TargetGroupBinding в режиме IP mode), выделение портов NodePort можно отключить, экономя пул портов кластера.
2. Почему обращение к внешнему HTTPS-сервису через type: ExternalName часто падает с ошибкой валидации SSL/TLS сертификата в Java (SSLHandshakeException)?
Ответ:
Тип ExternalName работает исключительно на уровне DNS: он не проксирует TCP-соединение, а лишь возвращает клиенту CNAME-запись (например, mydb.internal $\to$ custom-service.eu-west-1.rds.amazonaws.com).
Когда Java-клиент устанавливает защищённое TLS-соединение, он отправляет заголовок SNI (Server Name Indication) с исходным именем хоста, к которому подключался (mydb.internal).
Удалённый сервер возвращает SSL-сертификат, выписанный на домен *.rds.amazonaws.com. JVM сравнивает запрошенное имя mydb.internal с маской сертификата, фиксирует несовпадение имён и выбрасывает фатальное исключение javax.net.ssl.SSLPeerUnverifiedException: Certificate for <mydb.internal> doesn't match any of the subject alternative names.
3. Как директива externalTrafficPolicy: Local защищает от утечки Client IP и почему она требует настройки healthCheckNodePort?
Ответ:
В стандартном режиме Cluster сетевой пакет, пришедший на Node 1, пересылается на Node 2. Чтобы Node 2 знала, куда отправить ответный пакет, ядро на Node 1 выполняет Source NAT (SNAT), заменяя реальный IP клиента на IP-адрес Node 1 (клиентский IP теряется).
В режиме Local ядро запрещает пересылку между нодами: пакет передаётся поду только локально, благодаря чему SNAT не требуется, и настоящий Client IP сохраняется.
Но если на Node 1 нет подов этого сервиса, пакет будет отброшен. Чтобы облачный балансировщик знал, на какие именно ноды можно слать трафик, Kubernetes автоматически открывает служебный порт healthCheckNodePort. Балансировщик непрерывно опрашивает этот порт: ноды с подами отвечают HTTP 200, а ноды без подов — HTTP 503.
4. Можно ли внутри кластера обратиться к сервису NodePort по его внутреннему ClusterIP, игнорируя выделенный порт 30000–32767?
Ответ:
Да, абсолютно.
Каждый сервис типа NodePort одновременно является полноценным сервисом типа ClusterIP.
Внутри кластера другие микросервисы могут обращаться к нему по его DNS-имени и стандартному внутреннему порту spec.ports.port (например, http://my-service:80), минуя громоздкие внешние порты nodePort (31234). Выделенный порт nodePort открывается только для входящего трафика с внешних физических интерфейсов нод.
🎯 Шпаргалка для интервью
Главное о типах Service
ClusterIP: дефолтный виртуальный IP, доступен только внутри кластера.NodePort: открывает порт30000–32767на всех серверах; трафик идет черезNodePort$\to$ClusterIP$\to$ Pod.LoadBalancer: заказывает внешний IP в облаке (AWS/GCP); в on-premise требует MetalLB.ExternalName: чистый DNS CNAME алиас на внешнюю систему (без виртуального IP и без селектора).- Ingress vs LoadBalancer: 1 Ingress (1 LoadBalancer) обслуживает десятки сервисов
ClusterIP, экономя бюджет. externalTrafficPolicy: Local: сохраняет реальный Client IP и убирает лишний hop, но отключает межсерверную балансировку.
Сравнение свойств сетевого доступа
| Тип | Выделяет ClusterIP? | Выделяет NodePort? | Требует интеграции с облаком? |
| :— | :—: | :—: | :—: |
| ClusterIP | 🟢 Да | ❌ Нет | ❌ Нет |
| NodePort | 🟢 Да | 🟢 Да | ❌ Нет |
| LoadBalancer | 🟢 Да | 🟢 Да (по умолчанию)| 🟢 Да (Cloud Provider / MetalLB) |
| ExternalName | ❌ Нет | ❌ Нет | ❌ Нет (только CoreDNS) |
Красные флаги на собеседовании (Чего говорить нельзя)
- ❌ «В продакшене мы для каждого бэкенд-сервиса создаём LoadBalancer с публичным IP» — колоссальный перерасход денег и дыра в безопасности; нужен Ingress + ClusterIP.
- ❌ «NodePort открывает порт только на том сервере, где физически запущен под» — NodePort открывается на ВСЕХ серверах кластера без исключения.
- ❌ «ExternalName умеет балансировать TCP-пакеты на внешнюю БД» — ExternalName это только DNS-алиас CNAME, трафик идёт напрямую от клиента к внешнему хосту.