Сервисы Kubernetes
Сервис в Kubernetes — это высокоуровневая абстракция, предназначенная для обеспечения доступа к одному или нескольким подам, работающим в кластере. Сервисы упрощают процесс взаимодействия между различными компонентами приложения и предоставляют удобный интерфейс для доступа к ресурсам. Проще говоря, сервис в Kubernetes выступает в роли стабильной сетевой точки входа для приложений, которые работают в кластере.
Важно упомянуть, что сервисы используют селекторы для идентификации подов, которые должны быть частью данного сервиса. Селекторы позволяют группировать поды по определённым критериям, таким, как метки или имена.
Каждый сервис имеет уникальное имя и может быть сконфигурирован для работы в разных режимах доступа. Например, service может быть настроен на внутренний доступ только внутри кластера или он может быть настроен на внешний доступ через внешний балансировщик нагрузки. В связи с такой вариативностью сервисы разделили на несколько типов:
- ClusterIP: самый простой тип сервиса, доступный только внутри кластера.
- NodePort: доступен снаружи кластера по определённому порту на всех нодах.
- LoadBalancer: автоматически создаёт внешний балансировщик нагрузки.
- ExternalName: маппинг на внешний ресурс посредством CNAME-записи.
ClusterIP
ClusterIP — это дефолтный тип сервиса в кубах, он поднимает вам сервис внутри кластера на внутрекластеровом IP. Доступа для внешнего трафика нет, только внутри кластера.
YAML для ClusterIP выглядит как-то так:
apiVersion: v1 kind: Service metadata: name: my-internal-service spec: selector: app: my-app type: ClusterIP ports: - name: http port: 80 targetPort: 80 protocol: TCP
$ kubectl proxy --port=8080
Когда использовать ClusterIP для открытия внешнего доступа? Есть парочка вариантов применения, когда стоит пускать трафик на сервис через kubernetes proxy:
- Когда надо дебажить сервисы, подключаясь к ним напрямую
- Когда надо получить доступ к какому-либо сервису
NodePort
NodePort — наиболее простой и “тупой” способ пустить внешний трафик на сервис. Название “NodePort” говорит само за себя — просто открывается порт на ноде для доступа извне, а трафик уже маршрутизируется на сам сервис.
apiVersion: v1 kind: Service metadata: name: my-nodeport-service spec: selector: app: my-app type: NodePort ports: - name: http port: 80 targetPort: 80 nodePort: 30036 protocol: TCP
Как можно было заметить, в описании фигурирует параметр nodePort, который задаёт номер порта для открытия. Если его не задавать, то выберется рандомный порт в диапазоне 30000-32767.
Когда использовать NodePort? Для начала, у этого метода сразу несколько минусов:
- Один порт — один сервис
- Диапазон 30000-32767 (хоть и изменяемый, но делать это надо крайне осторожно)
- Если IP ноды может измениться (например, в GKE или AWS при автоскейлинге), то это тоже надо учитывать
В общем, не рекомендую использовать этот метод в продакшне. Конечно, если это какой-то демо-сервис и от него не требуется 100% доступность, вполне можно использовать NodePort.
LoadBalancer
LoadBalancer — это, можно сказать, стандартный и самый простой способ пустить внешний трафик на сервис. Правда, работает он только в облаках, т.к. использует нативные облачные решения текущего провайдера. Например, при использовании в GKE будет поднят Network Load Balancer с отдельным внешним IP-адресом, который будет маршрутизировать весь трафик на указанный сервис.
Когда использовать LoadBalancer?
- Элемент ненумерованного списка
- Если надо дать прямой доступ к сервису извне, это ваш выбор. Весь трафик на выбранный порт будет маршрутизироваться на сервис. Это значит, что можно пускать практически любой вид трафика: HTTP, TCP, UDP, Websockets, gRPC и т.п.
Огромный минус в том, что для каждого сервиса будет использоваться свой LoadBalancer со своим внешним IP, и придётся в результате платить сразу за несколько LoadBalancer’ов.
Ingress
В отличие от других приведённых выше примеров Ingress — вообще не сервис как таковой. Его нельзя задать как type в описании сервиса. На деле Ingress поднимается между сервисами и внешним миром и выступает в роли некоего умного маршрутизатора, который является точкой входа в кластер.
С Ingress’ом можно делать очень много разных штук, т.к. существует множество Ingress Controller’ов с разными возможностями. Например, в GKE дефолтный Ingress Controller поднимет HTTP(S) Load Balancer. Он позволяет роутить трафик на сервисы по путям URL’ов и поддоменам. Например, можно отправить всё, что приходит на foo.yourdomain.com на сервис foo, а всё, что приходит на yourdomain.com/bar/ на сервис bar
apiVersion: extensions/v1beta1 kind: Ingress metadata: name: my-ingress spec: backend: serviceName: other servicePort: 8080 rules: - host: foo.mydomain.com http: paths: - backend: serviceName: foo servicePort: 8080 - host: mydomain.com http: paths: - path: /bar/* backend: serviceName: bar servicePort: 8080