Модуль 3.1: Сервіси — ClusterIP, NodePort, LoadBalancer
Складність:
[MEDIUM]- Базова концепція мережіЧас на проходження: 45-55 хвилин
Передумови: Модуль 2.1 (Поди), Модуль 2.2 (Деплойменти)
Що ви зможете робити
Розділ «Що ви зможете робити»Після цього модуля ви зможете:
- Створити ClusterIP, NodePort та LoadBalancer сервіси й пояснити потік трафіку для кожного
- Дебажити з’єднання сервісів, перевіряючи endpoints, селектори та правила kube-proxy
- Простежити запит від клієнта через Service до Pod, використовуючи правила iptables/IPVS
- Пояснити, як kube-proxy реалізує балансування навантаження сервісів у режимах iptables та IPVS
Чому цей модуль важливий
Розділ «Чому цей модуль важливий»Поди є ефемерними — вони з’являються та зникають, а їхні IP-адреси змінюються. Сервіси забезпечують стабільну мережу для ваших додатків. Без сервісів вам довелося б вручну відстежувати кожну IP-адресу пода, що неможливо при масштабуванні.
На іспиті CKA Сервіси перевіряються дуже ретельно. Вам потрібно буде швидко створювати сервіси, відкривати доступ до деплойментів, налагоджувати підключення до сервісів та розуміти, коли використовувати кожен тип сервісу.
Аналогія з рестораном
Уявіть собі ресторан (ваш додаток). Поди — це окремі кухарі — вони можуть змінювати зміни, хворіти або їх можуть замінити. Номер телефону ресторану (Сервіс) залишається незмінним незалежно від того, які кухарі працюють. Клієнти телефонують на той самий номер, і дзвінок перенаправляється до доступного кухаря. Це саме те, що роблять Сервіси у Kubernetes.
Що ви дізнаєтесь
Розділ «Що ви дізнаєтесь»До кінця цього модуля ви зможете:
- Розуміти чотири типи сервісів і коли використовувати кожен з них
- Створювати сервіси імперативно та декларативно
- Відкривати доступ до деплойментів та подів
- Налагоджувати проблеми з підключенням до сервісів
- Використовувати селектори для націлювання на правильні поди
Чи знали ви?
Розділ «Чи знали ви?»-
Сервіси з’явилися раніше за Поди: Концепція стабільних IP-адрес сервісів була розроблена ще до того, як у Kubernetes з’явилися поди. Засновники знали, що ефемерним подам потрібні стабільні кінцеві точки.
-
Віртуальні IP-адреси — це магія: IP-адрес ClusterIP не існує на жодному мережевому інтерфейсі. Вони є “віртуальними” IP-адресами, які kube-proxy перехоплює та маршрутизує за допомогою правил iptables або nftables. (Примітка: режим IPVS застарів у K8s 1.35 — nftables є рекомендованою заміною.)
-
Діапазон NodePort можна налаштувати: Діапазон за замовчуванням 30000-32767 можна змінити за допомогою прапорця
--service-node-port-rangeна API-сервері, хоча більшість кластерів дотримуються значень за замовчуванням.
Частина 1: Основи Сервісів
Розділ «Частина 1: Основи Сервісів»1.1 Чому Сервіси?
Розділ «1.1 Чому Сервіси?»┌────────────────────────────────────────────────────────────────┐│ Проблема ││ ││ Клієнт хоче отримати доступ до "web app" ││ ││ ┌─────────────────────────────────────────────────────┐ ││ │ Под: web-abc123 IP: 10.244.1.5 ← Створено │ ││ │ Под: web-def456 IP: 10.244.2.8 ← Працює │ ││ │ Под: web-ghi789 IP: 10.244.1.12 ← Створено │ ││ │ Под: web-abc123 IP: 10.244.1.5 ← Видалено! │ ││ │ Под: web-xyz999 IP: 10.244.3.2 ← Новий под │ ││ └─────────────────────────────────────────────────────┘ ││ ││ Яку IP-адресу має використовувати клієнт? Вони змінюються! ││ │└────────────────────────────────────────────────────────────────┘
┌────────────────────────────────────────────────────────────────┐│ Рішення: Сервіси ││ ││ ┌───────────────────────────────────────────────────────┐ ││ │ Сервіс: web-service │ ││ │ ClusterIP: 10.96.45.123 │ ││ │ (Ніколи не змінюється!) │ ││ │ │ ││ │ Селектор: app=web │ ││ │ │ │ ││ │ ├──► Под: web-def456 (10.244.2.8) │ ││ │ ├──► Под: web-ghi789 (10.244.1.12) │ ││ │ └──► Под: web-xyz999 (10.244.3.2) │ ││ └───────────────────────────────────────────────────────┘ ││ ││ Клієнт завжди використовує 10.96.45.123 - Kubernetes все інше││ │└────────────────────────────────────────────────────────────────┘1.2 Компоненти Сервісу
Розділ «1.2 Компоненти Сервісу»| Компонент | Опис |
|---|---|
| ClusterIP | Стабільна внутрішня IP-адреса для сервісу |
| Selector | Мітки, що визначають, на які поди маршрутизувати |
| Port | Порт, на якому слухає сервіс |
| TargetPort | Порт на подах, куди пересилається трафік |
| Endpoints | Фактичні IP-адреси подів, що підтримують сервіс |
1.3 Як працюють Сервіси
Розділ «1.3 Як працюють Сервіси»┌────────────────────────────────────────────────────────────────┐│ Потік запитів до Сервісу ││ ││ 1. Клієнт надсилає запит на IP-адресу Сервісу (10.96.45.123:80)││ │ ││ ▼ ││ 2. kube-proxy (на кожному вузлі) перехоплює ││ │ ││ ▼ ││ 3. kube-proxy використовує правила iptables/nftables ││ │ ││ ▼ ││ 4. Запит пересилається на одну з IP-адрес пода ││ (балансування навантаження - round robin за замовчуванням) ││ │ ││ ▼ ││ 5. Под отримує запит на targetPort ││ │└────────────────────────────────────────────────────────────────┘Частина 2: Типи Сервісів
Розділ «Частина 2: Типи Сервісів»2.1 Чотири типи Сервісів
Розділ «2.1 Чотири типи Сервісів»| Тип | Область дії | Варіант використання | Частота на іспиті |
|---|---|---|---|
| ClusterIP | Лише внутрішня | Зв’язок між подами | ⭐⭐⭐⭐⭐ |
| NodePort | Зовнішня через IP вузла | Розробка, тестування | ⭐⭐⭐⭐ |
| LoadBalancer | Зовнішня через хмарний БН | Продакшн у хмарі | ⭐⭐⭐ |
| ExternalName | DNS-псевдонім | Зовнішні сервіси | ⭐⭐ |
2.2 ClusterIP (За замовчуванням)
Розділ «2.2 ClusterIP (За замовчуванням)»# Internal-only access - most common typeapiVersion: v1kind: Servicemetadata: name: web-servicespec: type: ClusterIP # Default, can be omitted selector: app: web # Match pods with label app=web ports: - port: 80 # Service listens on port 80 targetPort: 8080 # Forward to pod port 8080┌────────────────────────────────────────────────────────────────┐│ Сервіс ClusterIP ││ ││ Доступно лише зсередини кластера ││ ││ ┌────────────────┐ ┌────────────────┐ ││ │ Інший Под │───────►│ ClusterIP │ ││ │ (клієнт) │ │ 10.96.45.123 │ ││ └────────────────┘ │ │ ││ │ ┌──────────┐ │ ││ │ │ Под │ │ ││ │ │ app=web │ │ ││ ┌────────────────┐ │ └──────────┘ │ ││ │ Зовнішній │───X───►│ │ ││ │ (заблоковано) │ │ ┌──────────┐ │ ││ └────────────────┘ │ │ Под │ │ ││ │ │ app=web │ │ ││ │ └──────────┘ │ ││ └────────────────┘ ││ │└────────────────────────────────────────────────────────────────┘2.3 NodePort
Розділ «2.3 NodePort»# Exposes service on each node's IP at a static portapiVersion: v1kind: Servicemetadata: name: web-nodeportspec: type: NodePort selector: app: web ports: - port: 80 # ClusterIP port (internal) targetPort: 8080 # Pod port nodePort: 30080 # External port (30000-32767)┌────────────────────────────────────────────────────────────────┐│ Сервіс NodePort ││ ││ Зовнішній доступ через <NodeIP>:<NodePort> ││ ││ ┌─────────────────────────────────────────────────────────┐ ││ │ Кластер │ ││ │ │ ││ │ Вузол 1 (192.168.1.10) Вузол 2 (192.168.1.11) │ ││ │ ┌──────────────────┐ ┌──────────────────┐ │ ││ │ │ :30080 ──────────┼──────┼─► Под (app=web) │ │ ││ │ └──────────────────┘ └──────────────────┘ │ ││ │ │ ││ └─────────────────────────────────────────────────────────┘ ││ ▲ ▲ ││ │ │ ││ Зовнішній: 192.168.1.10:30080 АБО 192.168.1.11:30080 ││ (Обидва працюють!) ││ │└────────────────────────────────────────────────────────────────┘2.4 LoadBalancer
Розділ «2.4 LoadBalancer»# Creates external load balancer (cloud provider)apiVersion: v1kind: Servicemetadata: name: web-lbspec: type: LoadBalancer selector: app: web ports: - port: 80 targetPort: 8080┌────────────────────────────────────────────────────────────────┐│ Сервіс LoadBalancer ││ ││ Хмарний провайдер створює зовнішній балансувальник навантаження││ ││ ┌──────────────────┐ ││ │ Інтернет │ ││ └────────┬─────────┘ ││ │ ││ ▼ ││ ┌──────────────────┐ Зовнішня IP-адреса: 34.85.123.45 ││ │ Хмарний БН │ ││ │ (AWS/GCP/Azure)│ ││ └────────┬─────────┘ ││ │ ││ ▼ ││ ┌──────────────────────────────────────────────────┐ ││ │ NodePort (автоматично створений) │ ││ │ │ │ ││ │ ┌─────────────┼─────────────┐ │ ││ │ ▼ ▼ ▼ │ ││ │ ┌──────┐ ┌──────┐ ┌──────┐ │ ││ │ │ Под │ │ Под │ │ Под │ │ ││ │ └──────┘ └──────┘ └──────┘ │ ││ └──────────────────────────────────────────────────┘ ││ │└────────────────────────────────────────────────────────────────┘2.5 ExternalName
Розділ «2.5 ExternalName»# DNS alias to external service (no proxying)apiVersion: v1kind: Servicemetadata: name: external-dbspec: type: ExternalName externalName: database.example.com # Returns CNAME record # No selector - points to external DNS name┌────────────────────────────────────────────────────────────────┐│ Сервіс ExternalName ││ ││ DNS-псевдонім — без ClusterIP, без проксіювання ││ ││ ┌────────────────┐ ││ │ Под │ ││ │ │──► DNS: external-db.default.svc ││ │ │ │ ││ └────────────────┘ │ Повертає CNAME ││ ▼ ││ database.example.com ││ │ ││ ▼ ││ ┌──────────────────┐ ││ │ Зовнішня БД │ ││ │ (поза K8s) │ ││ └──────────────────┘ ││ │└────────────────────────────────────────────────────────────────┘Частина 3: Створення Сервісів
Розділ «Частина 3: Створення Сервісів»3.1 Імперативні команди (Швидко для іспиту)
Розділ «3.1 Імперативні команди (Швидко для іспиту)»# Expose a deployment (most common exam task)k expose deployment nginx --port=80 --target-port=8080 --name=nginx-svc
# Expose with NodePortk expose deployment nginx --port=80 --type=NodePort --name=nginx-np
# Expose a podk expose pod nginx --port=80 --name=nginx-pod-svc
# Generate YAML without creatingk expose deployment nginx --port=80 --dry-run=client -o yaml > svc.yaml
# Create service for existing pods by selectork create service clusterip my-svc --tcp=80:80803.2 Опції команди Expose
Розділ «3.2 Опції команди Expose»# Full syntaxk expose deployment <name> \ --port=<service-port> \ --target-port=<pod-port> \ --type=<ClusterIP|NodePort|LoadBalancer> \ --name=<service-name> \ --protocol=<TCP|UDP>
# Examplesk expose deployment web --port=80 --target-port=8080k expose deployment web --port=80 --type=NodePortk expose deployment web --port=80 --type=LoadBalancer3.3 Декларативний YAML
Розділ «3.3 Декларативний YAML»# Complete service exampleapiVersion: v1kind: Servicemetadata: name: web-service labels: app: webspec: type: ClusterIP selector: app: web # MUST match pod labels tier: frontend ports: - name: http # Named port (good practice) port: 80 # Service port targetPort: 8080 # Pod port (can be name or number) protocol: TCP # TCP (default) or UDP3.4 Сервіси з кількома портами
Розділ «3.4 Сервіси з кількома портами»# Service with multiple portsapiVersion: v1kind: Servicemetadata: name: multi-port-svcspec: selector: app: web ports: - name: http # Required when multiple ports port: 80 targetPort: 8080 - name: https port: 443 targetPort: 8443 - name: metrics port: 9090 targetPort: 9090Частина 4: Виявлення Сервісів (Service Discovery)
Розділ «Частина 4: Виявлення Сервісів (Service Discovery)»4.1 Виявлення на основі DNS
Розділ «4.1 Виявлення на основі DNS»Кожен сервіс отримує запис DNS:
<service-name>- в межах одного Простору імен<service-name>.<namespace>- між Просторами імен<service-name>.<namespace>.svc.cluster.local- повністю визначене ім’я
# From a pod in the same namespacecurl web-service
# From a pod in different namespacecurl web-service.production
# Fully qualified (always works)curl web-service.production.svc.cluster.local4.2 Змінні середовища
Розділ «4.2 Змінні середовища»Kubernetes впроваджує інформацію про сервіс у поди:
# Environment variables for service "web-service"WEB_SERVICE_SERVICE_HOST=10.96.45.123WEB_SERVICE_SERVICE_PORT=80
# Note: Only works for services created BEFORE the pod4.3 Пошук Сервісів
Розділ «4.3 Пошук Сервісів»# List servicesk get servicesk get svc # Short form
# Get service detailsk describe svc web-service
# Get service endpointsk get endpoints web-service
# Get service YAMLk get svc web-service -o yaml
# Find service ClusterIPk get svc web-service -o jsonpath='{.spec.clusterIP}'Частина 5: Селектори та Ендпоінти (Endpoints)
Розділ «Частина 5: Селектори та Ендпоінти (Endpoints)»5.1 Як працюють Селектори
Розділ «5.1 Як працюють Селектори»# Service selector MUST match pod labels exactly# Service:spec: selector: app: web tier: frontend
# Pod (will be selected):metadata: labels: app: web tier: frontend version: v2 # Extra labels OK
# Pod (will NOT be selected - missing tier):metadata: labels: app: web version: v25.2 Ендпоінти
Розділ «5.2 Ендпоінти»Ендпоінти автоматично створюються, коли поди відповідають селектору:
# View endpoints (pod IPs backing the service)k get endpoints web-service# NAME ENDPOINTS AGE# web-service 10.244.1.5:8080,10.244.2.8:8080 5m
# Detailed endpoint infok describe endpoints web-service5.3 Сервіс без Селектора
Розділ «5.3 Сервіс без Селектора»Створення сервісу, який вказує на ручні ендпоінти:
# Service without selectorapiVersion: v1kind: Servicemetadata: name: external-servicespec: ports: - port: 80 targetPort: 80---# Manual endpointsapiVersion: v1kind: Endpointsmetadata: name: external-service # Must match service namesubsets:- addresses: - ip: 192.168.1.100 # External IP - ip: 192.168.1.101 ports: - port: 80Варіант використання: Вказування на зовнішні бази даних або сервіси поза кластером.
Частина 6: Налагодження Сервісів
Розділ «Частина 6: Налагодження Сервісів»6.1 Робочий процес налагодження Сервісу
Розділ «6.1 Робочий процес налагодження Сервісу»Сервіс не працює? │ ├── kubectl get svc (перевірити існування сервісу) │ │ │ └── Перевірити TYPE, CLUSTER-IP, EXTERNAL-IP, PORT │ ├── kubectl get endpoints <svc> (перевірити ендпоінти) │ │ │ ├── Немає ендпоінтів? → Селектор не відповідає подам │ │ Перевірити мітки подів │ │ │ └── Ендпоінти існують? → Поди не відповідають │ Перевірити стан подів │ ├── kubectl describe svc <svc> (перевірити селектор) │ │ │ └── Переконатися, що селектор відповідає міткам подів │ └── Протестувати зсередини кластера: kubectl run test --rm -it --image=busybox -- wget -qO- <svc>6.2 Типові проблеми Сервісів
Розділ «6.2 Типові проблеми Сервісів»| Симптом | Причина | Рішення |
|---|---|---|
| Немає ендпоінтів | Селектор не відповідає подам | Виправити селектор або мітки подів |
| З’єднання відхилено | Под не слухає на targetPort | Перевірити конфігурацію порту пода |
| Тайм-аут | Под не працює або постійно перезапускається (crashlooping) | Спочатку налагодити проблеми з подом |
| NodePort недоступний | Брандмауер блокує порт | Перевірити правила брандмауера вузла |
| Неправильний тип сервісу | Використання ClusterIP для зовнішнього доступу | Змінити на NodePort/LoadBalancer |
6.3 Команди налагодження
Розділ «6.3 Команди налагодження»# Check service and endpointsk get svc,endpoints
# Verify selector matches podsk get pods --selector=app=web
# Test connectivity from within clusterk run test --rm -it --image=busybox:1.36 --restart=Never -- \ wget -qO- http://web-service
# Test with curlk run test --rm -it --image=curlimages/curl --restart=Never -- \ curl -s http://web-service
# Check DNS resolutionk run test --rm -it --image=busybox:1.36 --restart=Never -- \ nslookup web-service
# Check port on pod directlyk exec <pod> -- netstat -tlnpБойова історія: Невідповідність селектора
Розробник витратив години на налагодження, чому його сервіс не мав ендпоінтів. Деплоймент використовував
app: web-app, але селектор сервісу бувapp: webapp(без дефіса). Різниця в один символ = нульове підключення. Завжди копіюйте селектори!
Частина 7: Прив’язка сеансу Сервісу (Session Affinity)
Розділ «Частина 7: Прив’язка сеансу Сервісу (Session Affinity)»7.1 Опції Session Affinity
Розділ «7.1 Опції Session Affinity»# Sticky sessions - route same client to same podapiVersion: v1kind: Servicemetadata: name: sticky-servicespec: selector: app: web sessionAffinity: ClientIP # None (default) or ClientIP sessionAffinityConfig: clientIP: timeoutSeconds: 10800 # 3 hours (default) ports: - port: 807.2 Коли використовувати Session Affinity
Розділ «7.2 Коли використовувати Session Affinity»| Сценарій | Використовувати прив’язку? |
|---|---|
| API без стану (Stateless) | Ні (за замовчуванням) |
| Кошик покупок у пам’яті пода | Так (але краще: використовувати Redis) |
| З’єднання WebSocket | Так |
| Сеанси автентифікації в пам’яті | Так (але краще: зовнішнє сховище) |
Розподіл трафіку (Traffic Distribution) (K8s 1.35+)
Розділ «Розподіл трафіку (Traffic Distribution) (K8s 1.35+)»Kubernetes 1.35 перевів розподіл трафіку PreferSameNode у статус GA (загальна доступність), що дає вам точний контроль над тим, куди маршрутизується трафік сервісу:
apiVersion: v1kind: Servicemetadata: name: latency-sensitivespec: selector: app: cache ports: - port: 6379 trafficDistribution: PreferSameNode # Route to local node first| Значення | Поведінка |
|---|---|
PreferSameNode | Суворо надавати перевагу кінцевим точкам на тому самому вузлі, повертатися до віддалених (GA у 1.35) |
PreferClose | Надавати перевагу топологічно близьким кінцевим точкам — в одній зоні під час використання топологічно-обізнаної маршрутизації |
Це особливо корисно для робочих навантажень, чутливих до затримок, таких як кеші, sidecar-контейнери та локальні сервіси вузлів.
Типові помилки
Розділ «Типові помилки»| Помилка | Проблема | Рішення |
|---|---|---|
| Невідповідність селектора | Сервіс не має ендпоінтів | Переконайтеся, що селектор точно відповідає міткам подів |
| Плутанина між Port та TargetPort | З’єднання відхилено | Port = сервіс, TargetPort = под |
| Відсутній тип сервісу | Немає доступу ззовні | Вкажіть NodePort або LoadBalancer |
| Використання ClusterIP зовні | Тайм-аут з’єднання | ClusterIP є лише внутрішнім |
| Забули Простір імен | Сервіс не знайдено | Використовуйте FQDN для запитів між просторами імен |
Тест
Розділ «Тест»-
У чому різниця між
portтаtargetPortу сервісі?Відповідь
`port` — це порт, на якому слухає сервіс. `targetPort` — це порт на поді, який отримує трафік. Приклад: Сервіс слухає на 80, пересилає на 8080 пода. -
Сервіс показує “No endpoints” (Немає ендпоінтів). Що є найімовірнішою причиною?
Відповідь
Селектор сервісу не відповідає міткам жодного запущеного пода. Перевірте, чи селектор точно збігається з мітками подів, використовуючи `k get pods --show-labels`. -
Як отримати доступ до сервісу ClusterIP з-поза меж кластера?
Відповідь
Прямо ніяк. ClusterIP призначений лише для внутрішнього використання. Вам потрібно або: - Змінити тип на NodePort або LoadBalancer - Використати `kubectl port-forward` - Отримати доступ через Інгрес (Ingress) або Gateway -
Яка команда відкриває доступ до деплойменту як до сервісу NodePort на порту 80?
Відповідь
`k expose deployment--port=80 --type=NodePort` NodePort буде призначено автоматично (30000-32767), якщо не вказано інше.
-
Яке DNS-ім’я може використовувати под у просторі імен “prod”, щоб дістатися до сервісу “api” у просторі імен “staging”?
Відповідь
`api.staging` або повне FQDN `api.staging.svc.cluster.local`
Практичні вправи
Розділ «Практичні вправи»Завдання: Створити та налагодити сервіси для багаторівневого додатку.
Кроки:
- Створити деплоймент бекенду:
k create deployment backend --image=nginx --replicas=2k set env deployment/backend APP=backend- Правильно призначити мітки подам:
k label deployment backend tier=backend- Відкрити доступ до бекенду як ClusterIP:
k expose deployment backend --port=80 --name=backend-svc- Перевірити сервіс:
k get svc backend-svck get endpoints backend-svc- Створити деплоймент фронтенду:
k create deployment frontend --image=nginx --replicas=2- Відкрити доступ до фронтенду як NodePort:
k expose deployment frontend --port=80 --type=NodePort --name=frontend-svc- Протестувати внутрішнє підключення:
# From a test pod, reach the backend servicek run test --rm -it --image=busybox:1.36 --restart=Never -- \ wget -qO- http://backend-svc- Протестувати між просторами імен:
# Create another namespace and testk create namespace otherk run test -n other --rm -it --image=busybox:1.36 --restart=Never -- \ wget -qO- http://backend-svc.default- Налагодити зламаний сервіс:
# Create a service with wrong selectork create service clusterip broken-svc --tcp=80:80# Check endpoints (should be empty)k get endpoints broken-svc# Fix by creating proper servicek delete svc broken-svck expose deployment backend --port=80 --name=broken-svc --selector=app=backendk get endpoints broken-svc- Очищення:
k delete deployment frontend backendk delete svc backend-svc frontend-svc broken-svck delete namespace otherКритерії успіху:
- Вміє створювати сервіси ClusterIP та NodePort
- Розуміє різницю між port та targetPort
- Вміє налагоджувати сервіси без ендпоінтів
- Може отримувати доступ до сервісів між просторами імен
- Розуміє, коли використовувати кожен тип сервісу
Практичні вправи
Розділ «Практичні вправи»Вправа 1: Швидкість створення Сервісу (Ціль: 2 хвилини)
Розділ «Вправа 1: Швидкість створення Сервісу (Ціль: 2 хвилини)»Створіть сервіси для деплойменту якомога швидше:
# Setupk create deployment drill-app --image=nginx --replicas=2
# Create ClusterIP servicek expose deployment drill-app --port=80 --name=drill-clusterip
# Create NodePort servicek expose deployment drill-app --port=80 --type=NodePort --name=drill-nodeport
# Verify bothk get svc drill-clusterip drill-nodeport
# Generate YAMLk expose deployment drill-app --port=80 --dry-run=client -o yaml > svc.yaml
# Cleanupk delete deployment drill-appk delete svc drill-clusterip drill-nodeportrm svc.yamlВправа 2: Сервіс з кількома портами (Ціль: 3 хвилини)
Розділ «Вправа 2: Сервіс з кількома портами (Ціль: 3 хвилини)»# Create deploymentk create deployment multi-port --image=nginx
# Create multi-port service from YAMLcat << 'EOF' | k apply -f -apiVersion: v1kind: Servicemetadata: name: multi-port-svcspec: selector: app: multi-port ports: - name: http port: 80 targetPort: 80 - name: https port: 443 targetPort: 443EOF
# Verifyk describe svc multi-port-svc
# Cleanupk delete deployment multi-portk delete svc multi-port-svcВправа 3: Виявлення Сервісів (Ціль: 3 хвилини)
Розділ «Вправа 3: Виявлення Сервісів (Ціль: 3 хвилини)»# Create servicek create deployment web --image=nginxk expose deployment web --port=80
# Test DNS resolutionk run dns-test --rm -it --image=busybox:1.36 --restart=Never -- \ nslookup web
# Test full FQDNk run dns-test --rm -it --image=busybox:1.36 --restart=Never -- \ nslookup web.default.svc.cluster.local
# Test connectivityk run curl-test --rm -it --image=curlimages/curl --restart=Never -- \ curl -s http://web
# Cleanupk delete deployment webk delete svc webВправа 4: Налагодження Ендпоінтів (Ціль: 4 хвилини)
Розділ «Вправа 4: Налагодження Ендпоінтів (Ціль: 4 хвилини)»# Create deployment with specific labelsk create deployment endpoint-test --image=nginxk label deployment endpoint-test tier=web --overwrite
# Create service with WRONG selector (intentionally broken)cat << 'EOF' | k apply -f -apiVersion: v1kind: Servicemetadata: name: broken-endpointsspec: selector: app: wrong-label # This won't match! ports: - port: 80EOF
# Observe: no endpointsk get endpoints broken-endpoints# ENDPOINTS: <none>
# Debug: check what selector should bek get pods --show-labels
# Fix: delete and recreate with correct selectork delete svc broken-endpointsk expose deployment endpoint-test --port=80 --name=fixed-endpoints
# Verify: endpoints exist nowk get endpoints fixed-endpoints
# Cleanupk delete deployment endpoint-testk delete svc fixed-endpointsВправа 5: Доступ між Просторами імен (Ціль: 3 хвилини)
Розділ «Вправа 5: Доступ між Просторами імен (Ціль: 3 хвилини)»# Create service in default namespacek create deployment app --image=nginxk expose deployment app --port=80
# Create other namespacek create namespace testing
# Access from other namespace - short formk run test -n testing --rm -it --image=busybox:1.36 --restart=Never -- \ wget -qO- http://app.default
# Access with FQDNk run test -n testing --rm -it --image=busybox:1.36 --restart=Never -- \ wget -qO- http://app.default.svc.cluster.local
# Cleanupk delete deployment appk delete svc appk delete namespace testingВправа 6: Специфічний порт NodePort (Ціль: 3 хвилини)
Розділ «Вправа 6: Специфічний порт NodePort (Ціль: 3 хвилини)»# Create deploymentk create deployment nodeport-test --image=nginx
# Create NodePort with specific portcat << 'EOF' | k apply -f -apiVersion: v1kind: Servicemetadata: name: specific-nodeportspec: type: NodePort selector: app: nodeport-test ports: - port: 80 targetPort: 80 nodePort: 30080 # Specific portEOF
# Verify portk get svc specific-nodeport# Should show 80:30080/TCP
# Cleanupk delete deployment nodeport-testk delete svc specific-nodeportВправа 7: Сервіс ExternalName (Ціль: 2 хвилини)
Розділ «Вправа 7: Сервіс ExternalName (Ціль: 2 хвилини)»# Create ExternalName servicecat << 'EOF' | k apply -f -apiVersion: v1kind: Servicemetadata: name: external-apispec: type: ExternalName externalName: api.example.comEOF
# Check the service (no ClusterIP!)k get svc external-api# Note: CLUSTER-IP shows as <none>
# Test DNS resolutionk run test --rm -it --image=busybox:1.36 --restart=Never -- \ nslookup external-api# Shows CNAME to api.example.com
# Cleanupk delete svc external-apiВправа 8: Виклик - Повний робочий процес Сервісу
Розділ «Вправа 8: Виклик - Повний робочий процес Сервісу»Без підглядання у рішення:
- Створіть деплоймент
challenge-appз nginx, 3 репліки - Відкрийте доступ як сервіс ClusterIP на порту 80
- Перевірте, чи ендпоінти показують 3 IP-адреси подів
- Масштабуйте деплоймент до 5 реплік
- Перевірте, чи ендпоінти тепер показують 5 IP-адрес подів
- Змініть тип сервісу на NodePort
- Отримайте номер NodePort
- Очистіть усе
# YOUR TASK: Complete in under 5 minutesВідповідь
# 1. Create deploymentk create deployment challenge-app --image=nginx --replicas=3
# 2. Expose as ClusterIPk expose deployment challenge-app --port=80
# 3. Verify 3 endpointsk get endpoints challenge-app
# 4. Scale to 5k scale deployment challenge-app --replicas=5
# 5. Verify 5 endpointsk get endpoints challenge-app
# 6. Change to NodePort (delete and recreate)k delete svc challenge-appk expose deployment challenge-app --port=80 --type=NodePort
# 7. Get NodePortk get svc challenge-app -o jsonpath='{.spec.ports[0].nodePort}'
# 8. Cleanupk delete deployment challenge-appk delete svc challenge-appНаступний модуль
Розділ «Наступний модуль»Модуль 3.2: Ендпоінти та EndpointSlices - Глибоке занурення в те, як сервіси відстежують поди.