Сервис находится в другом пространстве имен

111

Я пытался найти способ определить службу в одном пространстве имен, которая связана с модулем, работающим в другом пространстве имен. Я знаю, что контейнеры в запущенном Pod namespaceAмогут получить доступ к serviceXопределенному в namespaceB, указав его в DNS кластера как serviceX.namespaceB.svc.cluster.local, но я бы предпочел не иметь код внутри контейнера, который должен знать о местонахождении serviceX. То есть я хочу, чтобы код просто выполнял поиск, serviceXа затем имел к нему доступ.

Документация Kubernetes предполагает, что это возможно. В нем говорится, что одна из причин, по которой вы должны определить службу без селектора, заключается в том, что вы хотите указать свою службу на службу в другом пространстве имен или в другом кластере .

Это подсказывает мне, что я должен:

  1. Определите serviceXслужбу namespaceAбез селектора (поскольку POD, который я хочу выбрать, отсутствует namespaceA).
  2. Определите службу (которую я также вызвал serviceX) namespaceB, а затем
  3. Определить объект в 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массиве является обязательным. Итак, моя следующая попытка состояла в том, чтобы назначить фиксированный IP-адрес ClusterIP для serviceXin namespaceBи поместить его в поле IP (обратите внимание, что service_cluster_ip_rangeон настроен как 192.168.0.0/16и 192.168.1.1был назначен как ClusterIP для serviceXin namespaceB; serviceXin 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

Это было принято, но доступ к serviceXin namespaceAне перенаправлялся в Pod in namespaceB- время ожидания истекло. Глядя на настройку iptables, похоже, что для этого пришлось бы дважды выполнить предварительную маршрутизацию NAT.

Единственным , что я нашел , что работало - но не является удовлетворительным решением - это для поиска фактического IP - адреса Pod , обеспечивающий serviceXв namespaceBи поместить этот адрес в объекте Endpoints в namespaceA. Это, конечно, неудовлетворительно, потому что IP-адрес модуля может со временем измениться. Это проблема IP-адресов служб, которую нужно решить.

Итак, есть ли способ выполнить то, что, кажется, является обещанием документации, что я могу указать службу в одном пространстве имен на службу, работающую в другом пространстве имен?

Комментатор спросил, зачем вам это нужно - вот пример использования, который, по крайней мере, для меня имеет смысл:

Допустим, у вас есть мультитенантная система, которая также включает в себя общую функцию доступа к данным, которая может совместно использоваться арендаторами. Теперь представьте, что существуют разные варианты этой функции доступа к данным с общими API-интерфейсами, но с разными характеристиками производительности. Одни арендаторы получают доступ к одному из них, другие - к другому.

Модули каждого клиента работают в своих собственных пространствах имен, но каждый из них должен иметь доступ к одной из этих общих служб доступа к данным, которая обязательно будет в другом пространстве имен (поскольку к нему обращаются несколько клиентов). Но вы бы не хотели, чтобы арендатору пришлось менять свой код, если его подписка изменится для доступа к более высокопроизводительной службе.

Потенциальное решение (самое чистое, о котором я могу думать, если бы оно только работало) - включить определение службы в пространство имен каждого клиента для службы доступа к данным, причем каждое из них настроено для соответствующей конечной точки. Это определение службы должно быть настроено так, чтобы указывать на соответствующую службу доступа к данным, которую имеет право использовать каждый арендатор.

Дэвид МакКинли
источник
цель пространств имен - изолировать, поэтому я думаю, что если вам нужно пройти через пространства имен, вам нужно знать, по крайней мере, где они расположены!
MrE
Итак, что означает документация, когда она предлагает, чтобы вы могли направить службу, определенную в одном пространстве имен, для доступа к службе в другом пространстве имен, не определяя селектор - и косвенно определяя конечную точку? Для этого, безусловно, есть допустимые варианты использования - один из которых я добавил к вопросу. Документация вводит в заблуждение, или есть способ сделать это, что я еще не понял?
Дэвид МакКинли
я не уверен, извините. что я знаю, так это то, что я обращаюсь к службам в нескольких пространствах имен, используя их fqdn. Я делаю это особенно с vpn, так как у меня есть 1 pod vpn, и я подключаюсь через все службы с него. однако вам нужно знать пространство имен и предоставить fqdn. Я предлагаю вам спросить на слабом канале.
MrE
В настоящее время я использую fqdn. Тем не менее, мой вариант использования был бы лучше (теперь добавлен к вопросу), если бы в этом не было необходимости.
Дэвид МакКинли
Мне также интересно, о чем идет речь в документации, однако я могу использовать fqdn как удовлетворительное решение для моего варианта использования.
Винсент Де Смет,

Ответы:

228

Я наткнулся на ту же проблему и нашел хорошее решение, которое не требует статической конфигурации 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
Это отличное решение! Я не уверен, был ли тип «ExternalName» доступен для служб, когда я изначально задавал вопрос, но сейчас он поддерживается и аккуратно решает проблему. Спасибо, Пол.
Дэвид МакКинли
1
Это работает? я сомневаюсь. Может ли кто-нибудь подтвердить, действительно ли это сработало, у меня не работает.
debianmaster
2
Да, это так. Один модуль работает с сервисом в другом пространстве имен, но не для входящего балансировщика нагрузки.
Пол
из-за исправления поиска CNAME в кластере Kubernetes старая версия может не работать.
赵浩翔
1
Будет ли / должно ли это работать и для сервисов в пространстве имен kube-system?
Nabheet
11

Это так просто сделать

если вы хотите использовать его в качестве хоста и хотите разрешить его

Если вы используете посланник к любому другому шлюзу API для службы, расположенной в другом пространстве имен, всегда рекомендуется использовать:

            Use : <service name>
            Use : <service.name>.<namespace name>
            Not : <service.name>.<namespace name>.svc.cluster.local

это будет так: servicename.namespacename.svc.cluster.local

это отправит запрос определенной службе внутри указанного вами пространства имен.

пример:

kind: Service
apiVersion: v1
metadata:
  name: service
spec:
  type: ExternalName
  externalName: <servicename>.<namespace>.svc.cluster.local

Здесь замените <servicename>и <namespace>на соответствующее значение.

В Kubernetes пространства имен используются для создания виртуальной среды, но все они связаны друг с другом.

Суровый манвар
источник
6
Не могли бы вы объяснить, чем этот ответ отличается от того, который дал Пол почти двумя годами ранее?
Оливер
2
@Oliver нет разницы, но я только что указал, что заменить имя службы и пространство имен в конкретном месте. в то время как он использовал namespace-a, поэтому меня это сбивает с толку.
Harsh Manvar
8
Удобный трюк с SO - добавить комментарий к ответу и внести необходимые пояснения.
Оливер
4
Я бы назвал это лучшим решением, потому что .svc.cluster.localпо умолчанию поддерживается внутреннее разрешение службы.
DrKNa
0

Вы можете добиться этого, развернув что-то на более высоком уровне, чем службы с пространством имен, например балансировщик нагрузки службы 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
Этот проект устарел (август 2018 г.)
Никола Бен
1
@Prashanth B: Не могли бы вы соответствующим образом обновить свой ответ!
chaosguru