Service ClusterIP: внутренний адрес для подов
Как группа Pod получает один стабильный адрес и DNS-имя внутри кластера.
Зачем нужен Service
Pod - наименьшая единица, которую запускает Kubernetes. Внутри Pod работает один или несколько контейнеров. Каждый Pod получает свой IP-адрес при старте.
Этот IP меняется при любом пересоздании Pod. Нода упала, прошёл rollout (замена Pod на новую версию), кто-то поменял число реплик. IP станет другим. Запоминать IP Pod в коде соседнего приложения не выйдет: через минуту его уже нет.
Service - объект Kubernetes, который даёт группе Pod стабильный адрес. Этот адрес не зависит от того, какие именно Pod сейчас живы.
Service делает четыре вещи.
- Получает стабильный виртуальный IP внутри кластера (поле
spec.clusterIP). - Получает DNS-имя
<svc-name>.<namespace>.svc.cluster.local. Namespace - это область имён, логический раздел кластера для группировки объектов. - Через поле
selectorнаходит свои Pod по меткам (labels). - Распределяет запросы между этими Pod. В режиме kube-proxy по умолчанию (iptables) бэкенд выбирается случайно на каждое соединение.
Service не проверяет здоровье Pod сам. Он смотрит на readinessProbe Pod. readinessProbe - проверка, которую Kubernetes повторяет, чтобы понять, готов ли контейнер принимать трафик. Pod без readinessProbe считается готовым сразу. Pod с readinessProbe попадает в распределение только после первой успешной проверки.
В Pod нет readinessProbe, а приложение ещё не стартовало. Запрос придёт в Pod, который пока не отвечает. Решает readinessProbe.
Манифест ClusterIP
apiVersion: v1
kind: Service
metadata:
name: web
spec:
type: ClusterIP
selector:
app: web
ports:
- port: 80
targetPort: 8080
protocol: TCP
type: ClusterIP
ClusterIP - внутренний адрес Service. Он доступен только из Pod и нод кластера. Снаружи кластера его не видно.
ClusterIP стоит по умолчанию, поле type можно не писать. Другие
типы (NodePort, LoadBalancer, ExternalName) решают другие задачи и
разбираются в отдельных уроках.
selector
selector - это набор пар ключ: значение. Service ищет в своём
namespace все Pod, у которых есть эти метки, и считает их своими.
selector:
app: web
Если ни один Pod не подошёл, Service существует, но список его адресов
пуст. Запросы к нему вернут connection refused. Опечатка в selector
ломает связь незаметно: Service при этом выглядит исправным.
ports
ports - список портов Service. Обычно он один. У порта три ключа.
port- порт самого Service. По нему обращаются клиенты:web:80.targetPort- порт контейнера в Pod, куда уходит трафик. У образа nginx-unprivileged это 8080.protocol- TCP по умолчанию, можно UDP или SCTP.
port и targetPort различать обязательно. Клиент видит port.
kube-proxy переводит запрос на targetPort. kube-proxy - компонент на
каждой ноде, который настраивает правила сети для Service. Если Pod
слушает 8080, а в манифесте стоит targetPort: 80, запросы никуда не
дойдут.
Что показывает kubectl
kubectl - утилита командной строки для работы с кластером.
kubectl get svc web
# NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
# web ClusterIP 10.43.123.45 <none> 80/TCP 10s
kubectl get endpoints web
# Warning: v1 Endpoints is deprecated in v1.33+; use discovery.k8s.io/v1 EndpointSlice
# NAME ENDPOINTS AGE
# web 10.42.0.5:8080,10.42.0.6:8080 10s
Предупреждение в первой строке - норма. Начиная с версии 1.33 объект
Endpoints объявлен устаревшим, ему на смену пришёл EndpointSlice.
Команда продолжает работать и остаётся самой короткой для быстрой
проверки. Тот же список через новый API:
kubectl get endpointslice -l kubernetes.io/service-name=web
Endpoints - объект, который Kubernetes автоматически создаёт рядом с
каждым Service. Внутри список реальных адресов IP:port Pod,
которые сейчас попали в selector. Если Pod упал, его IP уходит из
Endpoints секунд за пять.
Сверяют связку так:
kubectl get pod -l app=web -o wide
kubectl get endpoints web
IP Pod из первого вывода должны совпасть с адресами в Endpoints из второго.
DNS внутри кластера
CoreDNS - DNS-сервер кластера. Он работает в namespace kube-system
и переводит имена Service в их ClusterIP. Из любого Pod:
# Короткое имя (только если pod в том же namespace)
curl http://web/
# С namespace
curl http://web.demo/
# Полный FQDN
curl http://web.demo.svc.cluster.local/
Все три варианта работают благодаря строке search в
/etc/resolv.conf. Этот файл kubelet кладёт в каждый Pod. kubelet -
агент Kubernetes на ноде, который запускает Pod.
Быстрая императивная команда
Если Deployment уже есть, писать YAML руками не нужно. Deployment - объект, который держит заданное число одинаковых Pod.
kubectl expose deploy web --port=80 --target-port=8080 --name=web
Команда создаст Service с правильным selector (он берётся из меток
Deployment) и нужными портами. По умолчанию --type=ClusterIP.
Что обычно ломается
- Метки Pod не совпадают с
selectorService. Покажутkubectl get pod --show-labelsиkubectl describe svc web. targetPortне совпадает с портом, который слушает контейнер. СверяютcontainerPortу Pod и порт внутри образа.- Pod в другом namespace. selector не пересекает границу namespace. Из другого namespace можно достучаться только по DNS-имени.
Домашка
Теорию закрепляет задание на своём кластере: 4 шага с проверкой. Кластер поднимается по треку Kubernetes локально, задания лежат в репозитории k8s-practice.
./run.sh start k8s-service-clusterip # развернуть стартовое состояние
./run.sh verify k8s-service-clusterip # проверить текущий шаг
Коротко
- Service даёт группе Pod стабильный ClusterIP и DNS-имя, которые не зависят от жизни конкретного Pod.
- Pod находятся через
selectorпо меткам, и только внутри своего namespace. port- порт Service для клиентов,targetPort- порт контейнера. Путаница между ними ломает трафик молча.- Список реальных адресов лежит в Endpoints (устарел) и EndpointSlice. Пустой список означает, что selector или readinessProbe не сошлись.
kubectl expose deployсоздаёт ClusterIP-Service без ручного YAML.
Дрилл · вопросы как на собесе
Проверь себя без подсказок
Сформулируй ответ вслух или письменно, потом раскрой и честно отметь: знал или нет.
Что такое Service в Kubernetes и какие у него типы?
K8S-010Прошли материал до конца? Отметьте урок пройденным.
Прогресс сохранён в этом браузере
Почистишь историю или откроешь с телефона, и отметки пропадут. Оставь почту, они переедут в аккаунт. Пароль придумывать не нужно.
Готово. теперь в аккаунте: прогресс виден с любого устройства. Мой прогресс