Чем отличаются всякие там NodePorts, LoadBalancer и Ingress? Все они дают возможность внешнему трафику попасть в ваш кластер, но дают эту возможность по-разному. Давайте-ка разберёмся, как они это делают и когда какой тип сервиса лучше использовать.
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
“Так, ну и зачем же рассказывать нам о ClusterIP, если он не принимает внешний трафик?” — спросите вы. А всё потому, что попасть на этот сервис можно через Kubernetes proxy!
Делается это так:
$ kubectl proxy --port=8080
*Прим. пер.: Надо отметить, что эта команда выполняется со своего локального компьютера, где настроен kubectl и для него прописаны доступы в кластер. Таким образом кубовый api-сервер будет доступен через прокси на localhost
Теперь можно попасть на сервис по такому адресу:
http://localhost:8080/api/v1/proxy/namespaces/<NAMESPACE>/services/<SERVICE-NAME>:<PORT-NAME>/
К примеру, чтобы попасть на сервис, описанный выше, надо использовать следующий адрес:
http://localhost:8080/api/v1/proxy/namespaces/default/services/my-internal-service:http/
Когда использовать ClusterIP для открытия внешнего доступа?
Есть парочка вариантов применения, когда стоит пускать трафик на сервис через kubernetes proxy:
- Когда надо дебажить сервисы, подключаясь к ним напрямую
- Когда надо получить доступ к какой-
Пожалуй, не стоит использовать этот подход, чтобы открывать доступ к сервисам извне, особенно на проде.
*Прим. пер.: Да и кто вообще подумает о том, чтобы открывать так доступы на прод?
NodePort
NodePort — наиболее простой и “тупой” способ пустить внешний трафик на сервис. Название “NodePort” говорит само за себя — просто открывается порт на ноде для доступа извне, а трафик уже маршрутизируется на сам сервис.
Пример YAML для 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
Примера YAML Ingress для кластера в GKE:
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
И когда же использовать Ingress?
Пожалуй, Ingress — наиболее мощное средство для того, что пускать внешний трафик на приложения, но при этом сложнее других способов. Есть множество разных Ingress Controller’ов Google Cloud Load Balancer, Nginx, Contour, Istio и другие. Для этих контроллеров ещё существуют и плагины, типа cert-manager, которые могут автоматом выпускать сертификаты для сервисов. Ingress больше всего пригодится, когда надо открыть доступ сразу к пачке сервисов на одном IP и все эти сервисы используют один и тот же L7 протокол (обычно, HTTP). В таком случае придётся платить всего за один LoadBalancer (в случае с gke), а использование дополнительных плюшек в виде всяких SSL, авторизации, роутинга и пр. — очень хорошее подспорье.
*GKE — Google Kubernetes Engine