Знакомство с 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, а мы в следующей статье поговорим об аннотациях.