Kubernetes: служба, расположенная в другом пространстве имен
Я пытался найти способ определить службу в одном пространстве имен, которая связана с модулем, работающим в другом пространстве имен. Я знаю, что контейнеры в serviceX
Pod, работающем в namespaceA
могут обращаться к serviceX
определенному в namespaceB
, ссылаясь на него в DNS кластера как serviceX.namespaceB.svc.cluster.local
, но я бы не хотел, чтобы код внутри контейнера должен был знать о расположение serviceX
. То есть я хочу, чтобы код просто serviceX
и затем serviceX
доступ к нему.
Документация Kubernetes предполагает, что это возможно. В нем говорится, что одной из причин, по которой вы определяете службу без селектора, является то, что вы хотите указать свою службу для службы в другом пространстве имен или в другом кластере.
Это подсказывает мне, что я должен:
- Определите сервис
serviceX
в namespaceA
serviceX
, без селектора (поскольку POD, который я хочу выбрать, не находится в namespaceA
). - Определите службу (которую я также назвал
serviceX
) в namespaceB
, а затем - Определите объект Endpoints в
namespaceA
чтобы он указывал на serviceX
в namespaceB
.
Это третий шаг, который мне не удалось сделать.
Сначала я попытался определить объект Endpoints следующим образом:
kind: Endpoints
apiVersion: v1
metadata:
name: serviceX
namespace: namespaceA
subsets:
- addresses:
- targetRef:
kind: Service
namespace: namespaceB
name: serviceX
apiVersion: v1
ports:
- name: http
port: 3000
Это казалось логичным подходом, и, очевидно, для чего предназначался targetRef
. Но это привело к ошибке, говорящей о том, что поле ip
в массиве addresses
является обязательным. Итак, моей следующей попыткой было назначить фиксированный адрес ClusterIP для serviceX
в namespaceB
и поместить его в поле IP (обратите внимание, что service_cluster_ip_range
настроен как 192.168.0.0/16
, а 192.168.1.1
был назначен в качестве ClusterIP для serviceX
в namespaceB
; serviceX
в namespaceA
автоматически назначается другой ClusterIP в подсети 192.168.0.0/16
):
kind: Endpoints
apiVersion: v1
metadata:
name: serviceX
namespace: namespaceA
subsets:
- addresses:
- ip: 192.168.1.1
targetRef:
kind: Service
namespace: namespaceB
name: serviceX
apiVersion: v1
ports:
- name: http
port: 3000
Это было принято, но доступ к serviceX
в namespaceA
serviceX
не перенаправлялся в Pod в namespaceB
serviceX
- они истекли. Глядя на настройку iptables, похоже, что для этого нужно было бы дважды выполнить предварительную маршрутизацию NAT.
Единственное, что я обнаружил, что это сработало, но не является удовлетворительным решением, - это поиск фактического IP-адреса Pod, предоставляющего serviceX
в namespaceB
и помещение этого адреса в объект Endpoints в namespaceA
. Конечно, это неудовлетворительно, потому что IP-адрес Pod может со временем меняться. Это проблема IP-адресов службы, чтобы решить.
Итак, есть ли способ удовлетворить то, что кажется обещанием документации, что я могу указать службу в одном пространстве имен службе, работающей в другом пространстве имен?
Комментатор спросил, почему вы хотели бы сделать это - вот пример использования, который имеет смысл для меня, по крайней мере:
Допустим, у вас есть мультитенантная система, которая также включает в себя общую функцию доступа к данным, которая может совместно использоваться арендаторами. Теперь представьте, что существуют разные варианты этой функции доступа к данным с общими API, но с разными характеристиками производительности. Некоторые арендаторы получают доступ к одному из них, другие арендаторы имеют доступ к другому.
Каждый модуль арендатора работает в своих собственных пространствах имен, но каждому из них требуется доступ к одной из этих общих служб доступа к данным, которые обязательно будут находиться в другом пространстве имен (поскольку к нему обращаются несколько арендаторов). Но вы не хотели бы, чтобы арендатор изменил свой код, если его подписка изменится, чтобы получить доступ к высокопроизводительной службе.
Потенциальное решение (самое чистое, которое я могу придумать, если бы оно работало) состоит в том, чтобы включить определение службы в каждое пространство имен арендатора для службы доступа к данным, причем каждое из них настроено для соответствующей конечной точки. Это определение службы будет настроено так, чтобы указывать на соответствующую службу доступа к данным, которую каждый арендатор имеет право использовать.
Ответы
Ответ 1
Я наткнулся на ту же проблему и нашел приятное решение, которое не требует статической конфигурации ip:
Вы можете получить доступ к сервису через него DNS-имя (как упоминалось вами): servicename.namespace.svc.cluster.local
Вы можете использовать это DNS-имя для ссылки в другое пространство имен через локальную службу:
kind: Service
apiVersion: v1
metadata:
name: service-y
namespace: namespace-a
spec:
type: ExternalName
externalName: service-x.namespace-b.svc.cluster.local
ports:
- port: 80
Ответ 2
Вы можете добиться этого, развернув что-то на более высоком уровне, чем службы с именами, например, loadbalancer https://github.com/kubernetes/contrib/tree/master/service-loadbalancer. Если вы хотите ограничить его одним пространством имен, используйте аргумент "--namespace = ns" (по умолчанию все пространства имен: https://github.com/kubernetes/contrib/blob/master/service-loadbalancer/service_loadbalancer.go#L715), Это хорошо работает для L7, но для L4 это немного грязно.
Ответ 3
Это так просто сделать
если вы хотите использовать его в качестве хоста и хотите разрешить его
это будет похоже на: servicename.namespacename.svc.cluster.local
это отправит запрос конкретной службе в пространство имен, которое вы упомянули.
Для бывших
kind: Service
apiVersion: v1
metadata:
name: service
spec:
type: ExternalName
externalName: <servicename>.<namespace>.svc.cluster.local
Здесь замените <servicename>
и <namespace>
на соответствующее значение.
В kubernetes пространства имен используются для создания виртуальной среды, но все они связаны друг с другом.