Олег Марков
Что такое Kubernetes Service и как его настроить
Введение
Когда вы работаете с Kubernetes, вы сталкиваетесь с понятием Pod — минимальной единицей выполнения, внутри которой запускаются контейнеры. Но чтобы ваше приложение было доступно для пользователей внутри кластера или снаружи, Pod недостаточно. Дело в том, что IP-адрес Pod может меняться при пересоздании. Для организации стабильной точки доступа используется объект Kubernetes Service. Это абстракция, которая создает стабильный виртуальный IP (ClusterIP) и DNS-имя для набора Pod. С его помощью вы может связать ваши приложения между собой или обеспечить связь пользователей с вашим сервисом.
Давайте подробнее разберемся, что такое Service в Kubernetes, какие виды сервисов бывают, как его создать, настроить и как выбирать правильный тип Service для ваших задач. Я буду дополнять теорию практическими примерами YAML-манифестов, чтобы вам было понятно, как применить эти знания на практике.
Для чего нужен Kubernetes Service
Когда в Kubernetes запускается несколько Pod одного типа (например, несколько экземпляров вашего веб-сервера), возникает задача: как связать их с другими сервисами или пользователями, если IP-адреса Pod не статичны? Именно здесь приходит на помощь Service. Основные задачи, которые он решает:
- Предоставляет статическую точку доступа для набора Pod, объединяя их по лейблам.
- Обеспечивает внутренний или внешний доступ (иногда оба варианта) к приложению.
- Балансирует трафик между доступными Pod, увеличивая отказоустойчивость.
- Позволяет реализовывать механизмы типа Load Balancer или публикации через NodePort.
Виды Kubernetes Service
В Kubernetes выделяют четыре основных типа Service:
- ClusterIP — используется для внутреннего взаимодействия компонентов кластера.
- NodePort — открывает порт на каждом узле кластера, доступен из внешней сети по адресу любого из узлов.
- LoadBalancer — интегрируется с провайдерами облака, выделяя внешний адрес, на который приходит трафик.
- ExternalName — создает внутри кластера DNS-именование для внешнего ресурса.
Теперь детально разберем каждую разновидность и научимся настраивать их в реальных сценариях.
ClusterIP — для внутреннего обмена трафиком
Это вариант по умолчанию. Обычно используется, если сервис нужен только для внутренних компонентов кластера.
Пример создания ClusterIP Service
Допустим, у вас есть приложение, сгруппированное по лейблу app: my-app
. Вы хотите, чтобы остальные Pod могли обращаться к нему по имени.
apiVersion: v1
kind: Service
metadata:
name: my-app-service
spec:
selector:
app: my-app # Лейбл, по которому сервис находит нужные Pod
ports:
- protocol: TCP
port: 80 # Порт сервиса, по которому он будет доступен другим Pod
targetPort: 8080 # Порт внутри Pod, на который сервис перенаправляет трафик
type: ClusterIP # Тип сервиса (по умолчанию)
Как это работает: любой Pod внутри вашего кластера сможет обратиться по имени my-app-service
(или через DNS — my-app-service.default.svc.cluster.local
) и получить доступ к вашему приложению.
NodePort — открываем сервис вовне
Бывает важно дать возможность обращаться к сервису снаружи кластера, например, для тестирования или интеграции с внешними системами. Опция NodePort позволяет “пробросить” порт на каждый Node кластера.
Пример NodePort Service
apiVersion: v1
kind: Service
metadata:
name: my-app-nodeport
spec:
type: NodePort
selector:
app: my-app
ports:
- port: 80 # Порт внутри кластера
targetPort: 8080 # Порт на Pod
nodePort: 30001 # Фиксированный NodePort (диапазон по умолчанию: 30000-32767)
Теперь сервис доступен по любому IP-адресу Node и порту 30001. Например: http://<NodeIP>:30001
. Так можно протестировать приложение напрямую во время разработки.
LoadBalancer — интеграция с публичным облаком
Этот вид Service наиболее популярен в облачных инфраструктурах (GCP, AWS, Azure). Он автоматически создаёт внешний балансировщик нагрузки.
Пример LoadBalancer Service
apiVersion: v1
kind: Service
metadata:
name: my-app-loadbalancer
spec:
type: LoadBalancer
selector:
app: my-app
ports:
- port: 80
targetPort: 8080
Через несколько минут у вас появится внешний публичный IP, который можно узнать командой:
kubectl get service my-app-loadbalancer
Теперь приложение будет доступно по этому адресу из интернета.
ExternalName — связь с внешними сервисами
Этот тип сервисов не направляет трафик, а создает внутри кластера псевдоним (DNS-имя) для доступа к внешним ресурсам.
Пример ExternalName Service
apiVersion: v1
kind: Service
metadata:
name: external-db
spec:
type: ExternalName
externalName: mydatabase.company.com # Внешний адрес, на который будет вести DNS
Теперь все запросы к external-db
внутри вашей сети будут автоматически направляться на mydatabase.company.com
.
Как работает Service внутри кластера
Когда вы создаете Service, Kubernetes:
- Создает виртуальный IP для сервиса.
- Следит за списком Pod, соответствующих выбранному селектору (labels).
- Настраивает балансировщик, который отправляет запросы на один из доступных Pod.
- Для некоторых типов Service (например, LoadBalancer) интегрируется с внешними ресурсами (облако, сетевые плагины).
Как Service “находит” нужные Pod
Service использует поле selector
для поиска Pod с соответствующими лейблами. Каждый раз, когда появляется новый подходящий Pod — сервис добавляет его в свой список (endpoints). Если Pod удалён, сервис перестаёт на него направлять запросы.
DNS — автоимя для простых обращений
В Kubernetes автоматически работает kube-dns (или CoreDNS). Для созданных сервисов формируется DNS-запись вида: <service-name>.<namespace>.svc.cluster.local
. Благодаря этому другие сервисы и Pod могут обращаться друг к другу по имени.
Настройка Service — пошагово
Давайте я покажу универсальный пошаговый шаблон, по которому вы сможете настраивать сервисы под свои задачи:
1. Определите цель сервиса
Подумайте, нужен ли сервис для:
- Внутреннего взаимодействия — выбираем ClusterIP.
- Внешнего доступа с фиксированным портом — NodePort.
- Публичного трафика — LoadBalancer.
- Преобразования имен — ExternalName.
2. Присвойте Pod понятные лейблы
Сервисы находят Pod только по лейблам. Убедитесь, что ваши Pod размечены правильно. Например:
apiVersion: v1
kind: Pod
metadata:
name: my-app-pod
labels:
app: my-app
spec:
containers:
- name: my-container
image: my-image
ports:
- containerPort: 8080
3. Создайте описание сервиса (YAML-файл)
Обязательно указывайте:
- selector: по какому лейблу искать Pod
- ports: порт сервиса и порт на Pod
- type: какой вид сервиса вам нужен
4. Примените манифест
kubectl apply -f your-service.yaml
5. Проверьте, что сервис работает
Список всех сервисов можно получить так:
kubectl get services
Проверьте список endpoints у сервиса:
kubectl describe service <service-name>
Посмотрите, совпадают ли endpoints с ожидаемыми Pod.
Расширенные настройки и полезные опции
LoadBalancer с настройками аннотаций
В публичных облаках вы часто захотите добавить аннотации для интеграции с провайдером:
metadata:
name: my-app-loadbalancer
annotations:
service.beta.kubernetes.io/aws-load-balancer-backend-protocol: http
Каждый облачный провайдер поддерживает свои уникальные аннотации.
Дополнительные параметры ports
Иногда нужно пробросить несколько портов сразу. Просто добавьте их в массив ports
. Пример:
ports:
- port: 80
targetPort: 8080
- port: 443
targetPort: 8443
Сервис без selector
Иногда сервис создают без поля selector
. Вручную можно прописать endpoints на другие Pod или внешние IP-адреса. Это удобно для некоторых нестандартных сценариев.
apiVersion: v1
kind: Service
metadata:
name: my-service
spec:
ports:
- port: 80
Тогда endpoints задаются отдельным объектом:
apiVersion: v1
kind: Endpoints
metadata:
name: my-service
subsets:
- addresses:
- ip: 10.0.0.42
ports:
- port: 80
Обновление конфигурации Service на лету
Вы можете править существующий сервис командой kubectl edit service <service-name>
, но не все поля можно менять на лету (например, тип сервиса иногда менять нельзя). Для серьезных изменений лучше удалять и пересоздавать сервис.
Использование affinity для умного балансинга
Service по умолчанию использует round-robin при балансировке между Pod, но можно настраивать session affinity по IP — чтобы сохранить связь клиент—сервер при обновлении кластера.
spec:
sessionAffinity: ClientIP # обеспечить “липкость” клиента к конкретному Pod
Это важно для приложений, где пользователь должен всё время попадать на один и тот же экземпляр.
Трюки и рекомендации
- Краткое имя сервиса (без domain-суффикса) работает только внутри того же namespace.
- Всегда закрывайте сервисы снаружи (используйте типа LoadBalancer или NodePort) только когда это необходимо.
- В целях безопасности используйте Network Policies для фильтрации трафика между сервисами.
- Описывайте лейблы Pod и сервисов детально — это облегчает поддержку больших кластеров.
- Для импорта внешних сервисов используйте ExternalName.
Заключение
Kubernetes Service — это ключевой абстрактный объект в инфраструктуре Kubernetes, предназначенный для связи между Pod, балансировки нагрузки и публикации сервисов во внешнюю или внутреннюю сеть. Выбирая правильный тип сервиса для конкретной задачи (ClusterIP, NodePort, LoadBalancer, ExternalName), вы обеспечиваете гибкость, отказоустойчивость и управляемость своих приложений в кластере. Настроить Kubernetes Service можно с помощью простого YAML-манифеста: важно правильно задать лейблы, порты и тип сервиса. Сервисы автоматически интегрируются с системой DNS в Kubernetes, что делает взаимодействие компонентов прозрачным и предсказуемым.
Опираясь на приведённые примеры и рекомендации, вы сможете быстро и уверенно настраивать Kubernetes Service для любых повседневных задач — как для внутренних микросервисов, так и для публикации публичных приложений в облаке.
Частозадаваемые технические вопросы по теме статьи
Как работает sessionAffinity в Kubernetes Service и когда это нужно?
SessionAffinity позволяет “привязать” клиента к конкретному Pod — по умолчанию сервис раскидывает запросы (round robin), но если указать в spec свойство sessionAffinity: ClientIP
, то все запросы от одного клиента (IP) будут поступать на один и тот же Pod. Включается опцией:
spec:
sessionAffinity: ClientIP
Используйте для приложений, где важно сохранять состояние пользовательской сессии на одном сервере.
Как опубликовать сервис через Ingress и в чем отличие от Service?
Ingress — это отдельный объект, который управляет http/https-трафиком и позволяет на одном IP публиковать несколько сервисов по разным маршрутам (URL). Для этого создайте сервис типа ClusterIP и опишите правило Ingress, указывая сервис и порт назначения:
# В манифесте Ingress
spec:
rules:
- host: example.com
http:
paths:
- path: /app
backend:
service:
name: my-app-service
port:
number: 80
Это позволит обращаться к разным сервисам под разными адресами и путями.
Можно ли поменять тип сервисов (например, с ClusterIP на LoadBalancer) "на лету" без удаления?
Некоторые типы сервисов можно менять через kubectl edit service <имя>
, однако не всегда поддерживается обратимое изменение (особенно из или в ExternalName). Лучше пересоздавать сервис для смены типа, чтобы избежать ошибок и потери связности.
Как ограничить доступ к сервису внутри кластера?
Для ограничения сетевого доступа используются NetworkPolicy. Опишите policy, указывая, какие Pod или namespace могут обращаться к конкретному сервису:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
spec:
podSelector:
matchLabels:
app: my-app
ingress:
- from:
- podSelector:
matchLabels:
access: allowed
Теперь сервис будет доступен только Pod с определенными лейблами.
Как получить внешний IP для NodePort сервиса?
Внешний IP для NodePort — это любой публичный адрес/hostname вашего ноды (worker узла). Узнать его можно командой:
kubectl get nodes -o wide
Доступ будет по адресу <NodeIP>:<nodePort>
. Если IP недоступен снаружи (например, вы развернули Minikube), используйте его команду minikube service <service-name>
для проброса порта.
Постройте личный план изучения Kubernetes до уровня Middle — бесплатно!
Kubernetes — часть карты развития DevOps
100+ шагов развития
30 бесплатных лекций
300 бонусных рублей на счет
Бесплатные лекции
Все гайды по Kubernetes
Лучшие курсы по теме

Kubernetes и Helm
Антон Ларичев
Docker и Ansible
Антон Ларичев