Daily MaverickLIVING NIGHTMARE: QwaQwa residents battle 10-year water, electricity outage ‘nightmare’ESPN DeportesSuiza excluye a Xhaka por cartilla de vacunación falsaוואלהשר האוצר האמריקני: חברות התעופה האיראניות עלולות להיות מנותקות מפעילות בינלאומיתThe Jerusalem PostKurdish Peshmerga completes its long process of unification - explainerESPNAdieu, Batum: 18-year NBA vet, Team France stalwart retiresColliderThe Stars of Netflix's 'Gilmore Girls' Replacement Officially Break Silence Over Shock CancellationХабрМечтает ли трехмерный андроид о четырехмерных овцах?CNN بالعربيةمعركة قانونية جديدة.. شبكات إخبارية تتحدى قرار ترامب بسحب تصاريحها الصحفية من البيت الأبيضANSA'La guerra in Ucraina deve finire', il monito di TrumpSudinfo« Il fait ce qu’il veut, mais… » : Radja Nainggolan écarté du groupe du Patro Eisden pour raisons disciplinairesTechCrunchOpenAI forms math advisory group as its AI resolves more than 100 open problemsEuronewsPearly Kings and Queens bring London’s Cockney tradition to life
The Daily Newsstand · Free, Always
Monday, September 21, 2026

Kubernetes просто, часть 3: зачем нужен Service и как трафик доходит до конкретного Pod

Translate

https://habr.com/ru/articles/1083100/ - Kubernetes просто, часть 2: что происходит после kubectl apply

https://habr.com/ru/articles/1082088/ - Kubernetes просто, часть 1: зачем Kubernetes, устройство кластера

В предыдущих частях мы успели разобрать базовую модель Kubernetes.Сначала мы разобрались с архитектурой кластера

Control Plane
     │
     ├── API Server
     ├── etcd
     ├── Scheduler
     └── Controllers
Worker Nodes
     │
     ├── kubelet
     ├── container runtime
     └── Pods

А потом разобрались, как пользователь описывает желаемое (Desired) состояние через YAML-манифесты:

Deployment
    ↓
ReplicaSet
    ↓
Pods
    ↓
Containers

Так, мы успели понять главную особенность Kubernetes - Pod это не что-то постоянное.

Его можно удалить, Node может выйти из строя и так далее. В таком случае ReplicaSet просто создаст новый Pod, Scheduler может назначить его на новую ноду - новый Pod на новой машине, конечно, может получить новый IP-адрес.

Для управления приложением это нормально, но появляется новая проблема.

Как подам общаться между собой, если они постоянно меняются?

Именно здесь появляется еще один важный Kubernetes-объект - Service.

О проблеме

Представим, что в нашем кластере работает несколько backend.

Скажем:

spec:
    replicas: 3

В результате, в кластере работают

Backend Pods:

  Pod A - 10.1.2.4
  Pod B - 10.1.2.5
  Pod C - 10.1.2.8

Где-то рядом с ними работает Frontend, который хочет отправить вопрос бэку.

Технически, естественно, он бы мог напрямую обратиться к одному из подов:

Frontend -> 10.1.2.8:8080 -> Pod C

На первый взгляд все работает, frontend успешно обращается к backend по IP.

Но вспоминаем, как Kubernetes относится к подам и понимаем: сейчас этот IP существует, а уже через мгновение машина может упасть и Pod C заменит другой Pod на другой машине с другим IP.

Смотрите:

Pod C отказывает:

Pod A - 10.1.2.4 работает
Pod B - 10.1.2.5 работает
Pod C - 10.1.2.8 отказал

ReplicaSet видит:

Desired: 3
Actual:  2

И создает новый Pod:

Pod D - 10.1.2.9

С точки зрения Deployment все хорошо:

Desired: 3
Actual:  3

Но frontend этого не знает - он продолжает обращаться на Pod C, которого уже нет.

Возникает необходимость в абстракции, которая будет всегда стабильно работать, даже при изменении конкретных подов.

Для этого в Kubernetes существует Service.

Что такое Service?

Наиболее ясно можно описать Service так:

Service - стабильная сетевая точка доступа к набору Pods.

Так, раньше клиент обращался напрямую к конкретному поду по его IP:

Frontend
    ↓
 Pod IP

А теперь между ними есть «прослойка» в виде нашего нового Kubernetes-объекта:

Frontend
    ↓
 Service
    │
    ├────────→ Pod A
    ├────────→ Pod B
    └────────→ Pod C

Теперь Frontend не обязан знать:

Pod A = 10.1.2.4
Pod B = 10.1.2.5
Pod C = 10.1.3.8

Он знает только стабильную точку доступа к любому из этих Pod:

backend-service

Какие конкретно доступные поды находятся за этой точкой доступа, это уже задача Kubernetes.

Это отлично сочетается с моделью Kubernetes.

Поды могут появляться и исчезать, их IP меняются, они переезжают между разными Nodes. Клиент при этом не должен отслеживать все эти изменения самостоятельно.

Service - тоже Kubernetes-объект

Service также описывается manifest:

apiVersion: v1
kind: Service
metadata:
  name: backend-service
spec:
  selector:
    app: backend
  ports:
    - port: 80
      targetPort: 8080

Предыдущая статья уже позволяет нам понять большую часть этого YAML. И выглядит знакомо.

apiVersion: v1
kind: Service

Создаем Kubernetes-объект типа Service.

Дальше:

metadata:
  name: backend-service

Его название - backend-service.

Далее - его конфигурация:

spec:
  selector:
    app: backend
  ports:
    - port: 80
      targetPort: 8080

Здесь появляется пара новых вопросов:

Первый:

«Как Service понимает, к каким Pods направлять трафик?»

Второй:

«Что означает port и targetPort?»

Разберем с первого.

Как Service понимает, к каким Pods направлять трафик?

В прошлой части мы успели познакомиться с labels (метками) и selectors (селекторами):

template:
  metadata:
    labels:
      app: backend

В результате в кластере существуют:

Pod A [app=backend]
Pod B [app=backend]
Pod C [app=backend]

Pod X [app=frontend]

Теперь посмотрим на Service:

selector:
  app: backend

Его интересуют поды с меткой app=backend. А значит:

Pod A [app=backend]  подходит
Pod B [app=backend]  подходит
Pod C [app=backend]  подходит

Pod X [app=frontend] не подходит

Получается:

Здесь появляется важный паттерн Kubernetes:

Объекты часто связывают между собой не по их именам и адресам, а с помощью меток и селекторов.

Мы уже встречались с этим в Deployment.

Service не отправляет трафик в Deployment

У нас есть:

Deployment
    ↓
ReplicaSet
    ↓
Pods

Поэтому может показаться, что и сетевой запрос проходит так:

Service
    ↓
Deployment
    ↓
ReplicaSet
    ↓
Pod

Дело в том, что Deployment управляет жизненным циклом подов, а Service предоставляет к ним сетевой доступ. Они фактически выполняют совершенно разные задачи.

Правильнее представлять это себе так:

Так, важно понять, Service не находится в цепочке Deployment - ReplicaSet.

port и targetPort

Теперь разберем вторую часть Service:

ports:
  - port: 80
    targetPort: 8080

Вы, должно быть, знаете, что приложения висят на определенных портах машины. В Kubernetes-подах приложения тоже имеют порты. Пусть backend слушает 8080 порт внутри Pod:

Pod
└── backend application
        └── :8080Но клиенту мы хотим представить Service на порту 80:
Получается:

Но клиенту мы хотим представить Service на порту 80.

Получается:

Client
   │
   ↓
backend-service:80
   │
   ↓
 Service
   │
   ↓
Pod:8080

Именно это описывает:

port: 80
targetPort: 8080

port - порт, на котором клиент обращается к Service.

targetPort - порт backend, куда должен направляться трафик.

К примеру:

Эти поля, к слову, не обязаны различаться, вполне может быть:

ports:
  - port: 8080
    targetPort: 8080

Достаточно просто понимать роль полей.

Что такое ClusterIP

Итак, мы создали

apiVersion: v1
kind: Service
metadata:
  name: backend-service
spec:
  selector:
    app: backend
  ports:
    - port: 80
      targetPort: 8080

У Service есть еще одно поле:

type:

Которое мы не указали. В таком случае Kubernetes автоматически создает Service с

type: ClusterIP

То есть предыдущий манифест идентичен:

spec:
  type: ClusterIP
  selector:
    app: backend
  ports:
    - port: 80
      targetPort: 8080

Такой Service получает IP, который доступен внутри кластера:

К примеру:

backend-service

ClusterIP:
10.96.20.10

Теперь другой под внутри кластера может обращаться:

10.96.20.10:80

А дальше трафик пойдет к одному из подходящих бэкендов.

И здесь важно именно слово «внутри» кластера.

Обычный ClusterIP предоставляет прежде всего возможность для взаимодействия внутри Kubernetes-кластера. Внешний Интернет пока никак с ним не связан - это будет темой следующих статей.

И все же, обращаться по IP адресу тоже очень неудобно.

Хоть IP Service стабильнее IP Pod человеку, все же, привычнее мыслить словами - использовать имена.

Здесь появляется DNS (domain name system).

Kubernetes DNS

У нашего Service уже есть имя:

metadata:
  name: backend-service

Поэтому frontend может обращаться не на:

http://10.96.20.10

А просто к:

http://backend-service

Это гораздо удобнее, чем использовать IP-адреса.

Но как Service определяет, куда отправить трафик?

Концептуально, Service связан с набором подов бэкенда - backend endpoints.

backend-service

Backend endpoints:
10.1.2.4:8080
10.1.2.5:8080
10.1.3.8:8080

В современных версиях Kubernetes информация о таких backend’ах представляется через объекты EndpointSlice.

На нашем уровне пока не нужно разбирать их manifest или внутреннее устройство.

Важнее понять идею.

Есть стабильная абстракция: За ней лежит изменяющийся набор backend endpoints:

backend-service
      │
      ├── 10.1.2.4:8080
      ├── 10.1.2.5:8080
      └── 10.1.3.8:8080

Если вдруг один из подов откажет, EndpointSlice обновится в соответствии с новыми рабочими адресами.

Что происходит, если под не готов к обслуживанию трафика

Теперь мы можем связаться с еще одной Kubernetes-механикой.

Представим 3 backend

Pod A Ready=True
Pod B Ready=True
Pod C Ready=True

Service может отправлять трафик только к готовым (Ready) подам.

Но представим, что теперь Pod B не готов к обслуживанию трафика, при этом контейнер все еще может работать. Pod может продолжать существовать, но с точки зрения обслуживания клиентских запросов он пока не готов.

Поэтому обычная логика Service выглядит так:

Готовность обычно проверяется с помощью специальных проверок, о которых мы еще поговорим. Это называется readiness check (проверка на готовность).

Именно поэтому readiness не означает:

Контейнер нужно перезапускать.

Эта проверка подразумевает:

Можно ли отправлять на этот под клиентский трафик?

Обобщим прошлую статью с этой

Здесь уже соединяется довольно большая часть Kubernetes.

Deployment отвечает за существование Pods.

ReplicaSet поддерживает их количество.

Readiness показывает, готов ли конкретный Pod принимать трафик.

Service предоставляет стабильную сетевую точку доступа.

Labels и selectors связывают Service с Pods.

EndpointSlice представляет актуальный набор backend endpoints.

DNS позволяет клиенту использовать понятное имя вместо IP.

Что следует запомнить?

Сейчас главное запомнить:

Service - стабильная сетевая точка доступа к набору Pods.

Selector определяет, какие Pods соответствуют Service.

Labels позволяют этим Pods быть найденными.

port - порт Service.

targetPort - порт backend.

ClusterIP - стандартный тип Service, предназначенный прежде всего для доступа внутри кластера.

А Kubernetes DNS позволяет вместо IP использовать имя.

Самая важная мысль:

Клиенту не нужно знать IP конкретных Pods. Он обращается к Service, а набор backend Pods может меняться независимо от него.

Проверьте себя

1. Почему frontend не стоит привязывать к IP конкретного backend Pod?

2. Какую проблему решает Service?

3. Есть:

Pod A [app=backend]
Pod B [app=backend]
Pod C [app=frontend]

Service содержит:

selector:
  app: backend

Какие Pods ему соответствуют?

4. Что означают:

port: 80
targetPort: 8080

5. Что такое ClusterIP?

6. Зачем использовать Kubernetes DNS, если у Service уже есть ClusterIP?

7. Pod B продолжает работать, но его readiness стала False. Почему трафик Service обычно не должен идти в этот Pod и почему для этого не обязательно перезапускать контейнер?

View the original on Хабр

KioskNews shows a cleaned-up reading view extracted from the publisher’s page — the original always lives on their site, not ours.