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


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
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.