Dienst befindet sich in einem anderen Namespace

107

Ich habe versucht, einen Weg zu finden, um einen Dienst in einem Namespace zu definieren, der mit einem Pod verknüpft ist, der in einem anderen Namespace ausgeführt wird. Ich weiß, dass Container in einem Pod, in dem ausgeführt wird, namespaceAauf serviceXdefinierten Zugriff zugreifen können , namespaceBindem sie im Cluster-DNS als referenziert werden serviceX.namespaceB.svc.cluster.local, aber ich möchte lieber nicht, dass der Code im Container über den Speicherort von informiert wird serviceX. Das heißt, ich möchte, dass der Code nur nachschlägt serviceXund dann darauf zugreifen kann.

Die Kubernetes-Dokumentation legt nahe, dass dies möglich ist. Einer der Gründe, warum Sie einen Dienst ohne Selektor definieren würden, besteht darin, dass Sie Ihren Dienst auf einen Dienst in einem anderen Namespace oder in einem anderen Cluster verweisen möchten .

Das legt mir nahe, dass ich:

  1. Definieren Sie einen serviceXDienst in namespaceAohne Selektor (da der POD, den ich auswählen möchte, nicht in ist namespaceA).
  2. Definieren Sie einen Dienst (den ich auch angerufen habe serviceX) in namespaceBund dann
  3. Definieren Sie ein Endpunktobjekt namespaceA, auf das serviceXin gezeigt werden soll namespaceB.

Es ist dieser dritte Schritt, den ich nicht ausführen konnte.

Zuerst habe ich versucht, das Endpunktobjekt folgendermaßen zu definieren:

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

Das schien der logische Ansatz zu sein und offensichtlich, wofür das targetRefwar. Dies führte jedoch zu einem Fehler, der besagte, dass das ipFeld im addressesArray obligatorisch war. Also, mein nächster Versuch war eine feste ClusterIP Adresse zuweisen serviceXin namespaceBund umsetzen , die in dem IP - Feld (beachten Sie, dass das service_cluster_ip_rangeso konfiguriert ist 192.168.0.0/16, und 192.168.1.1wurde als ClusterIP für zugewiesen serviceXin namespaceB, serviceXin namespaceAwurde automatisch einen anderen ClusterIP auf dem zugewiesenen 192.168.0.0/16Subnetz) ::

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

Das wurde akzeptiert, aber die Zugriffe auf serviceXin namespaceAwurden nicht an den Pod in weitergeleitet namespaceB- sie haben eine Zeitüberschreitung. Wenn man sich das iptables-Setup ansieht, sieht es so aus, als hätte es zweimal NAT-Pre-Routing durchführen müssen, um dies zu erreichen.

Das einzige , was ich gefunden haben , das funktionierte - aber keine befriedigende Lösung - ist die tatsächliche IP - Adresse der Pod Bereitstellung Nachschlag serviceXin namespaceBund diese Adresse in dem Endpoints Objekt setzen namespaceA. Das ist natürlich nicht zufriedenstellend, da sich die Pod-IP-Adresse im Laufe der Zeit ändern kann. Das ist das Problem, das Service-IPs lösen müssen.

Gibt es also eine Möglichkeit, das Versprechen der Dokumentation zu erfüllen, dass ich einen Dienst in einem Namespace auf einen Dienst verweisen kann , der in einem anderen Namespace ausgeführt wird?

Ein Kommentator fragte, warum Sie dies tun möchten - hier ist ein Anwendungsfall, der zumindest für mich sinnvoll ist:

Angenommen, Sie haben ein System mit mehreren Mandanten, das auch eine gemeinsame Datenzugriffsfunktion enthält, die von Mandanten gemeinsam genutzt werden kann. Stellen Sie sich nun vor, dass es verschiedene Varianten dieser Datenzugriffsfunktion mit gemeinsamen APIs gibt, aber unterschiedliche Leistungsmerkmale. Einige Mieter erhalten Zugang zu einem von ihnen, andere Mieter haben Zugang zu einem anderen.

Die Pods jedes Mandanten werden in seinen eigenen Namespaces ausgeführt, aber jeder muss auf einen dieser allgemeinen Datenzugriffsdienste zugreifen, die sich notwendigerweise in einem anderen Namespace befinden (da mehrere Mandanten darauf zugreifen). Sie möchten jedoch nicht, dass der Mandant seinen Code ändern muss, wenn sich sein Abonnement ändert, um auf den leistungsstärkeren Dienst zuzugreifen.

Eine mögliche Lösung (die sauberste, die ich mir vorstellen kann, wenn sie nur funktioniert) besteht darin, eine Dienstdefinition in den Namespace jedes Mandanten für den Datenzugriffsdienst aufzunehmen, wobei jede für den entsprechenden Endpunkt konfiguriert ist. Diese Dienstdefinition würde so konfiguriert, dass sie auf den richtigen Datenzugriffsdienst verweist, zu dessen Nutzung jeder Mandant berechtigt ist.

David McKinley
quelle
Der Sinn von Namespaces besteht darin, sie zu isolieren. Wenn Sie also über Namespaces gehen müssen, müssen Sie zumindest wissen, wo sie sich befinden!
MrE
Was bedeutet die Dokumentation, wenn vorgeschlagen wird, dass Sie einen in einem Namespace definierten Dienst anweisen können, auf einen Dienst in einem anderen Namespace zuzugreifen, indem Sie keinen Selektor definieren - und implizit einen Endpunkt definieren? Hierfür gibt es sicherlich gültige Anwendungsfälle, von denen ich einen der Frage hinzugefügt habe. Ist die Dokumentation nur irreführend oder gibt es eine Möglichkeit, die ich noch nicht herausgefunden habe?
David McKinley
Ich bin mir nicht sicher, sorry. Was ich weiß ist, dass ich mit ihrem fqdn auf Dienste in mehreren Namespaces zugreife. Ich mache das besonders mit VPN, da ich 1 VPN-Pod habe und mich über alle Dienste von dort aus verbinde. Sie müssen jedoch den Namespace kennen und fqdn angeben. Ich würde vorschlagen, dass Sie auf dem Slack-Kanal fragen.
MrE
Die Verwendung von fqdn ist die Lösung, die ich derzeit verwende. Mein Anwendungsfall wäre jedoch besser bedient (jetzt zur Frage hinzugefügt), wenn dies nicht notwendig wäre.
David McKinley
Ich frage mich auch, worauf sich die Dokumentation bezieht, kann jedoch fqdn als zufriedenstellende Lösung für meinen Anwendungsfall verwenden.
Vincent De Smet

Antworten:

221

Ich bin über das gleiche Problem gestolpert und habe eine nette Lösung gefunden, die keine statische IP-Konfiguration benötigt:

Sie können über den DNS-Namen (wie von Ihnen angegeben) auf einen Dienst zugreifen : servicename.namespace.svc.cluster.local

Sie können diesen DNS-Namen verwenden, um ihn über einen lokalen Dienst in einem anderen Namespace zu referenzieren :

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
Paul
quelle
2
Dies ist eine großartige Lösung! Ich bin nicht sicher, ob der Typ "ExternalName" für Dienste verfügbar war, als ich die Frage ursprünglich gestellt habe, aber er wird jetzt unterstützt und löst das Problem ordentlich. Danke, Paul.
David McKinley
1
Funktioniert das? ich bezweifle. kann jemand bestätigen, ob dies wirklich funktioniert hat, funktioniert bei mir nicht.
Debianmaster
2
Ja tut es. Es funktioniert für einen Pod, um mit einem Dienst in einem anderen Namespace zu kommunizieren, nicht jedoch für einen Ingress Loadbalancer.
Paul
Aufgrund der CNAME-Suche in Kubernetes im Cluster funktioniert die alte Version möglicherweise nicht.
16.
1
Würde / sollte dies auch für Dienste im Namespace des Kubesystems funktionieren?
Nabheet
10

Es ist so einfach, es zu tun

Wenn Sie es als Host verwenden und auflösen möchten

Wenn Sie Ambassador für ein anderes API-Gateway für Dienste verwenden, die sich in einem anderen Namespace befinden, wird immer Folgendes empfohlen:

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

es wird sein wie: servicename.namespacename.svc.cluster.local

Dadurch wird eine Anfrage an einen bestimmten Dienst innerhalb des von Ihnen erwähnten Namespace gesendet.

Beispiel:

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

Hier ersetzen Sie das <servicename>und <namespace>durch den entsprechenden Wert.

In Kubernetes werden Namespaces verwendet, um eine virtuelle Umgebung zu erstellen, aber alle sind miteinander verbunden.

Harte Manvar
quelle
6
Können Sie erklären, wie sich diese Antwort von der von Paulus vor fast zwei Jahren unterscheidet?
Oliver
2
@Oliver gibt es keinen Unterschied, aber ich habe gerade angegeben, was Dienstname und Namespace an welcher Stelle ersetzen sollen. während er Namespace-a verwendet hat, sieht das für mich verwirrend aus.
Harsh Manvar
6
Ein praktischer Trick bei SO besteht darin, einen Kommentar zur Antwort hinzuzufügen und die erforderliche Klarstellung vorzunehmen.
Oliver
4
Ich würde dies als die beste Lösung bezeichnen, da .svc.cluster.localstandardmäßig die interne Lösung des Dienstes unterstützt wird.
DrKNa
1
wachte auch für mich auf. danke
vimal prakash
0

Sie können dies erreichen, indem Sie etwas auf einer höheren Ebene als namespaced Services bereitstellen, z. B. den Service Loadbalancer https://github.com/kubernetes/contrib/tree/master/service-loadbalancer . Wenn Sie es auf einen einzelnen Namespace beschränken möchten, verwenden Sie das Argument "--namespace = ns" (standardmäßig alle Namespaces: https://github.com/kubernetes/contrib/blob/master/service-loadbalancer/service_loadbalancer.go) # L715 ). Dies funktioniert gut für L7, ist aber für L4 etwas chaotisch.

Prashanth B.
quelle
3
Dieses Projekt ist jetzt (
Nicola Ben
1
@ Prashanth B: Könnten Sie Ihre Antwort entsprechend aktualisieren!
Chaosguru