логотип PurpleSchool
логотип PurpleSchool

Что такое 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:

  1. Создает виртуальный IP для сервиса.
  2. Следит за списком Pod, соответствующих выбранному селектору (labels).
  3. Настраивает балансировщик, который отправляет запросы на один из доступных Pod.
  4. Для некоторых типов 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 VolumesРабота с secrets в KubernetesСтрелочка вправо

Постройте личный план изучения Kubernetes до уровня Middle — бесплатно!

Kubernetes — часть карты развития DevOps

  • step100+ шагов развития
  • lessons30 бесплатных лекций
  • lessons300 бонусных рублей на счет

Бесплатные лекции

Все гайды по Kubernetes

Terraform и Kubernetes инфраструктура как кодНастройка и использование Runners в KubernetesНастройка и деплой PostgreSQL в KubernetesСравнение и интеграция Openshift и KubernetesПримеры интеграции GitHub Actions и KubernetesDeploy приложений в Kubernetes - пошаговое руководство для начинающих и не толькоКак настроить CD в KubernetesИнтеграция Ansible в KubernetesИнтеграция CI/CD с Jenkins и KubernetesИнтеграция Kubernetes с GitLab - Автоматизация CI CD в облачной инфраструктуреГайд по DevOps инструментам в KubernetesОсобенности платформы Deckhouse в Kubernetes
Открыть базу знаний

Лучшие курсы по теме

изображение курса

Kubernetes и Helm

Антон Ларичев
AI-тренажеры
Гарантия
Бонусы
иконка звёздочки рейтинга4.9
3 999 ₽ 6 990 ₽
Подробнее
изображение курса

Docker и Ansible

Антон Ларичев
AI-тренажеры
Гарантия
Бонусы
иконка звёздочки рейтинга4.8
3 999 ₽ 6 990 ₽
Подробнее
изображение курса

Микросервисы

Антон Ларичев
Гарантия
Бонусы
иконка звёздочки рейтинга4.8
3 999 ₽ 6 990 ₽
Подробнее

Отправить комментарий