Знакомство с Kubernetes. Часть 11: Сервисы (services)
Jul 9, 2018 07:06 · 665 words · 4 minute read
Поды в кластере Kubernetes
смертны - они создаются (рождаются), но когда под по какой-либо причине умирает, то он не воскресает. И хотя каждый под при создании получает свой собственный IP-адрес, этот адрес нельзя назвать постоянным и стабильным вследствие “смертности” подов. Давайте разберемся!
К примеру, ReplicaSet
может динамически изменять количество подов в кластере (путем масштабирования), при этом новые поды могут быть запущены на других узлах (нодах) кластера - в этом случае IP-адрес пода наверняка изменится.
Это порождает проблему: если некий набор подов (назовем их backends) предоставляют функционал другому набору подов (назовем их frontends) внутри кластера Kubernetes
, то как frontend-поды узнают адреса backend-подов и взаимодействуют с ними?
Сервис в Kubernetes
- это абстракция, определяющая логический набор подов и политику доступа к ним (иногда такой набор подов еще называют микросервисом). Как правило, этот набор подов определяется на основе меток (присваиваются в момент создания подов) и селекторов.
Например, backend - это 3 реплики подов, занимающихся обработкой изображений. Все три пода абсолютно идентичны с функциональной точки зрения (так как это реплики), поэтому frontend не должен беспокоиться на какой именно backend-под попадет запрос - это работа сервиса.
Простейший пример сервиса может выглядеть так:
kind: Service
apiVersion: v1
metadata:
name: my-service
spec:
selector:
app: MyApp
ports:
- protocol: TCP
port: 80
targetPort: 9376
Согласно данной спецификации, будет создан объект “сервис” (service
) с именем my-service
, перенаправляющий запросы на порт 9376 каждого пода, у которого присутствует метка app=MyApp
. Этому сервису также будет назначен отдельный IP-адрес.
Согласно указанному селектору, в кластере непрерывно будут проверяться поды на наличие метки app=MyApp
, а результат такой проверки будет публиковаться (с помощью POST
) в объект Endpoints
с таким же именем - my-service
.
Стоит отметить, что сервис может сопоставлять входящий порт (port:
) с любым портом назначения (targetPort:
). Если параметр targetPort
не указан, то по умолчанию будет использоваться тот же порт, что и в параметре port
. Еще одна интересная особенность - targetPort
может содержать строку с именем порта в подах (а сам номер порта, присвоенный этому имени, может быть разным для каждого пода).
Сервисы чаще всего используются для доступа к подам в кластере Kubernetes
, но их также можно использовать и для доступа к другим типам бэкендов, например:
- внешний кластер баз данных в production-окружении, локальная БД для тестового окружения;
- совершенно иной сервис в другом неймспейсе или кластере;
- часть бекендов, запущенных вне кластера
Kubernetes
(например, если вы только переносите свою инфраструктуру).
В любом из предложенных вариантов следует создать сервис без селекторов, например:
kind: Service
apiVersion: v1
metadata:
name: my-service
spec:
ports:
- protocol: TCP
port: 80
targetPort: 9376
и, так как селекторов нет, соотвествующий объект Endpoints
не создастся автоматически. Его необходимо создать вручную, тем самым указав связь между сервисом и конечной точкой (бекендом), например так:
kind: Endpoints
apiVersion: v1
metadata:
name: my-service
subsets:
- addresses:
- ip: 1.2.3.4
ports:
- port: 9376
Примечание. IP-адрес в данном случае не может находиться в диапазонах 127.0.0.0/8, 169.254.0.0/16 и 224.0.0.0/24.
Для многих сервисов обычным делом является использование (открытие) нескольких портов. В таком случае, все что необходимо - присвоить имена всем портам, например:
kind: Service
apiVersion: v1
metadata:
name: my-service
spec:
selector:
app: MyApp
ports:
- name: http
protocol: TCP
port: 80
targetPort: 9376
- name: https
protocol: TCP
port: 443
targetPort: 9377
В Kubernetes
существует несколько вариантов предоставления доступа к сервисам, которые называются типы (ServiceTypes
):
ClusterIP
: предоставляет доступ к сервису на внутреннем IP-адресе кластера (сервис доступен только внутри кластера). ТипClusterIP
используется по умолчанию;NodePort
: предоставляет доступ к сервису на IP-адресе каждого узла (ноды) кластера, на статическом порту (из диапазона 30000-32767). Автоматически создастся и сервис типаClusterIP
, на который будут маршрутизироваться запросы сNodePort
. Взаимодействовать с сервисом можно также из-за пределов кластера, используя в качестве адреса<NodeIP>:<NodePort>
;LoadBalancer
: предоставляет доступ к сервису используя балансировщик (load balancer) облачного провайдера. При этом автоматически создаются сервисы типаNodePort
иClusterIP
, на которые будут маршрутизироваться запросы с балансировщика;ExternalName
: особый случай - сопоставляет имя сервиса с содержимым поляexternalName
(например, foo.bar.example.com), возвращая CNAME запись. Никакого проксирования не происходит.
Больше информации о сервисах можно найти в официальной документации или в статье Understanding kubernetes networking: services, а мы в следующей статье поговорим об аннотациях.