Сервис (Service) в Kubernetes: публикация сервисов (ServiceTypes)

Для некоторых частей вашего приложения (например, фронтендов) вы можете захотеть предоставить Сервису внешний IP-адрес, который находится за пределами вашего кластера.

Kubernetes ServiceTypes (типы сервисов) позволяют вам указать, какой тип сервиса вы хотите. По умолчанию используется ClusterIP.

Значения Type (типа) сервиса и их поведение:

  • ClusterIP: Предоставляет Сервису внутренний IP-адрес кластера. Выбор этого значения делает Сервис доступным только из кластера. Это ServiceType (тип сервиса) по умолчанию.
  • NodePort: Предоставляет Сервис для каждого IP-адреса узла по статическому порту (NodePort). Сервис ClusterIP, к которой направляется сервис NodePort, создается автоматически. Вы сможете связаться с NodePort сервисом из-за пределов кластера, запросив <NodeIP>:<NodePort>.
  • LoadBalancer: предоставляет сервис извне, используя балансировщик нагрузки облачного провайдера. Службы NodePort и ClusterIP, к которым создаются внешние маршруты балансировки нагрузки, создаются автоматически.
  • ExternalName: сопоставляет Сервис с содержимым поля externalName (например, foo.bar.example.com), возвращая запись CNAME с ее значением, никакого проксирования не установлено.

Примечание. Для использования типа ExternalName требуется CoreDNS версии 1.7 или выше.

Вы также можете использовать Ingress для демонстрации вашего Сервиса. Ingress не является типом сервиса, но он действует как точка входа для вашего кластера. Это позволяет консолидировать правила маршрутизации в одном ресурсе, поскольку он может предоставлять несколько сервисов под одним и тем же IP-адресом.

Тип NodePort

Если для поля type установлено значение NodePort, плоскость управления Kubernetes выделяет порт из диапазона, указанного в флаге --service-node-port-range (по умолчанию: 30000-32767). Каждый узел передает этот порт (один и тот же номер порта на каждом узле) в ваш сервис. Ваш сервис сообщает о выделенном порте в своем поле .spec.ports[*].NodePort.

Если вы хотите указать конкретные IP-адреса для прокси-порта, вы можете установить флаг --nodeport-address в kube-proxy для конкретного IP-блока; это поддерживается начиная с Kubernetes v1.10. Этот флаг принимает список IP-блоков, разделенных запятыми (например, 10.0.0.0/8, 192.0.2.0/25), чтобы указать диапазоны IP-адресов, которые kube-proxy должен считать локальными для этого узла.

Например, если вы запускаете kube-proxy с флагом --nodeport-address=127.0.0.0/8, kube-proxy выбирает только loopback интерфейс для NodePort сервисов. По умолчанию для --nodeport-address значением является пустой список. Это означает, что kube-proxy должен учитывать все доступные сетевые интерфейсы для NodePort. (Это также совместимо с более ранними выпусками Kubernetes).

Если вам нужен конкретный номер порта, вы можете указать значение в поле nodePort. Плоскость управления либо выделит вам этот порт, либо сообщит о сбое транзакции API. Это означает, что вам нужно позаботиться о возможных конфликтах портов самостоятельно. Вы также должны использовать правильный номер порта, который находится внутри диапазона, настроенного для использования NodePort.

Использование NodePort дает вам свободу настраивать собственное решение для балансировки нагрузки, настраивать среды, которые не полностью поддерживаются Kubernetes, или даже просто выставлять IP-адреса одного или нескольких узлов напрямую.

Обратите внимание, что этот сервис отображается как :spec.ports[*].nodePort и .spec.clusterIP:spec.ports[*].port. (Если установлен флаг --nodeport-address в kube-proxy, будет отфильтрован NodeIP.)

Тип LoadBalancer

В облачных провайдерах, которые поддерживают внешние балансировщики нагрузки, установка поля type на LoadBalancer обеспечивает балансировщик нагрузки для вашего сервиса. Фактическое создание балансировщика нагрузки происходит асинхронно, и информация о подготовленном балансировщике публикуется в поле сервиса .status.loadBalancer. Например:

apiVersion: v1
kind: Service
metadata:
  name: my-service
spec:
  selector:
    app: MyApp
  ports:
    - protocol: TCP
      port: 80
      targetPort: 9376
  clusterIP: 10.0.171.239
  loadBalancerIP: 78.11.24.19
  type: LoadBalancer
status:
  loadBalancer:
    ingress:
      - ip: 146.148.47.155

Трафик с внешнего балансировщика нагрузки направляется на бэкэнд Pod'ы. Облачный провайдер решает, как он сбалансирован по нагрузке.

Некоторые облачные провайдеры позволяют вам указать loadBalancerIP. В этих случаях балансировщик нагрузки создается с помощью указанного пользователем loadBalancerIP. Если поле loadBalancerIP не указано, для loadBalancer устанавливается эфемерный IP-адрес. Если вы указываете loadBalancerIP, но ваш облачный провайдер не поддерживает эту функцию, то поле loadbalancerIP, которое вы устанавливаете, игнорируется.

Примечание: В Azure, если вы хотите использовать указанный пользователем открытый тип loadBalancerIP, сначала необходимо создать ресурс открытого IP-адреса статического типа. Этот общедоступный ресурс IP-адреса должен находиться в той же группе ресурсов, что и другие автоматически созданные ресурсы кластера. Например, MC_myResourceGroup_myAKSCluster_eastus.

Укажите назначенный IP-адрес как loadBalancerIP. Убедитесь, что вы обновили securityGroupName в файле конфигурации облачного провайдера.

Внутренний балансировщик нагрузки

В смешанной среде иногда необходимо направлять трафик от Сервисов внутри одного (виртуального) блока сетевых адресов.

В среде DNS с разделением горизонта вам потребуется два сервиса, чтобы иметь возможность направлять как внешний, так и внутренний трафик к вашим конечным точкам.

Тип ExternalName

Сервис типа ExternalName сопоставляет Сервис с DNS-именем, а не с типичным селектором, таким как my-service или cassandra. Вы указываете эти Сервисы с параметром spec.externalName.

Следующее определение сервиса, например, отображает сервис my-service в пространстве имен prod на my.database.example.com:

apiVersion: v1
kind: Service
metadata:
  name: my-service
  namespace: prod
spec:
  type: ExternalName
  externalName: my.database.example.com

Примечание. ExternalName принимает строку адреса IPv4, но в виде имен DNS, состоящих из цифр, а не в виде IP-адреса. ExternalNames, которые напоминают адреса IPv4, не разрешаются CoreDNS или ingress-nginx, потому что ExternalName предназначено для указания канонического имени DNS. Чтобы жестко закодировать IP-адрес, рассмотрите возможность использования headless Сервисов.

При поиске хоста my-service.prod.svc.cluster.local сервис DNS кластера возвращает запись CNAME со значением my.database.example.com. Доступ к my-service работает так же, как и к другим сервисам, но с той принципиальной разницей, что перенаправление происходит на уровне DNS, а не через прокси или пересылку. Если позднее вы решите перенести свою базу данных в кластер, вы можете запустить ее Pod'ы, добавить соответствующие селекторы или конечные точки и изменить тип сервиса.

Предупреждение: У вас могут возникнуть проблемы с использованием ExternalName для некоторых распространенных протоколов, включая HTTP и HTTPS. Если вы используете ExternalName, тогда имя хоста, используемое клиентами в вашем кластере, отличается от имени, на которое ссылается ExternalName.

Для протоколов, которые используют имена хостов, это различие может привести к ошибкам или неожиданным ответам. HTTP-запросы будут иметь заголовок Host:, который исходный сервер не распознает; Серверы TLS не смогут предоставить сертификат, соответствующий имени хоста, к которому подключен клиент.

Внешние IP-адреса

Если существуют внешние IP-адреса, которые маршрутизируют к одному или нескольким узлам кластера, сервисы Kubernetes могут быть доступны для этих внешних IP-адресов. Трафик, который поступает в кластер с внешним IP-адресом (в качестве IP-адреса назначения) через порт сервиса, будет направляться на одну из конечных точек сервиса. externalIPs не управляются Kubernetes и находятся в ведении администратора кластера.

В спецификации сервиса можно указать внешние IP-адреса вместе с любым из ServiceType. В приведенном ниже примере клиенты могут обращаться к “my-service” по адресу “80.11.12.10:80” (externalIP:port)

apiVersion: v1
kind: Service
metadata:
  name: my-service
spec:
  selector:
    app: MyApp
  ports:
    - name: http
      protocol: TCP
      port: 80
      targetPort: 9376
  externalIPs:
    - 80.11.12.10

Упущения

Использование прокси пользовательского пространства скрывает IP-адрес источника пакета, обращающегося к Сервису. Это делает невозможными некоторые виды сетевой фильтрации (межсетевой экран). Прокси-режим iptables не скрывает IP-адреса источника в кластере, но все же влияет на клиентов, проходящих через балансировщик нагрузки или порт узла.

Поле Type разработано как вложенная функциональность - каждый уровень добавляет к предыдущему. Это не является обязательным требованием для всех облачных провайдеров (например, Google Compute Engine не требуется выделять NodePort для работы LoadBalancer, а AWS делает это), но для текущего API это требуется.


Читайте также:


Комментарии

Популярные сообщения из этого блога

Контроллеры в Kubernetes: DaemonSet

Контроллеры в Kubernetes: ReplicaSet

Контроллеры в Kubernetes: StatefulSet