Які типи 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) повноцінний мережевий балансувальник навантаження з публічною 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) | ❌ Ні | Псевдонім для зовнішніх баз даних чи API |
🟡 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): збільшує мережеву затримку (latency).
- Втрата 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, трафік прямує безпосередньо від клієнта до зовнішнього хоста.