Usługa zlokalizowana w innej przestrzeni nazw


109

Próbowałem znaleźć sposób na zdefiniowanie usługi w jednej przestrzeni nazw, która łączy się z Pod działającym w innej przestrzeni nazw. Wiem, że kontenery w uruchomionym Podowie namespaceAmogą uzyskać dostęp do serviceXzdefiniowanego w namespaceB, odwołując się do niego w DNS klastra jako serviceX.namespaceB.svc.cluster.local, ale wolałbym, aby kod wewnątrz kontenera nie musiał wiedzieć o lokalizacji serviceX. Oznacza to, że chcę, aby kod po prostu wyszukał, serviceXa następnie miał do niego dostęp.

Dokumentacja Kubernetes sugeruje, że jest to możliwe. Mówi się, że jednym z powodów, dla których zdefiniowałbyś usługę bez selektora, jest to, że chcesz skierować swoją usługę do usługi w innej przestrzeni nazw lub w innym klastrze .

To sugeruje mi, że powinienem:

  1. Zdefiniuj serviceXusługę w namespaceA, bez selektora (ponieważ POD, który chcę wybrać, nie ma namespaceA).
  2. Zdefiniuj usługę (do której również zadzwoniłem serviceX) namespaceB, a następnie
  3. Zdefiniuj obiekt Endpoints w, namespaceAaby wskazywał serviceXw namespaceB.

To trzeci krok, którego nie byłem w stanie wykonać.

Najpierw próbowałem zdefiniować obiekt Endpoints w ten sposób:

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

To wydawało się logiczne podejście i oczywiście do czego służyłotargetRef . Ale to prowadziło do błędu mówiącego, że ippole w addressestablicy jest obowiązkowe. Tak więc moją następną próbą było przypisanie stałego adresu ClusterIP do serviceXin namespaceBi umieszczenie go w polu IP (zauważ, że service_cluster_ip_rangejest skonfigurowany jako 192.168.0.0/16, i 192.168.1.1został przypisany jako ClusterIP dla serviceXin namespaceB; serviceXw namespaceAautomatycznie przypisano inny ClusterIP w 192.168.0.0/16podsieci) :

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

Który został przyjęty, ale zejściówki serviceXw namespaceAnie dostać przekazane Pod w namespaceB- oni timed out. Patrząc na konfigurację iptables, wygląda na to, że aby to osiągnąć, musiałby dwukrotnie wykonać routing wstępny NAT.

Jedyną rzeczą, jaką znaleźliśmy, który pracował - ale nie jest to zadowalające rozwiązanie - do wyszukiwania rzeczywisty adres IP Pod zapewniając serviceXw namespaceBi umieścić ten adres w obiekcie punktów końcowych w namespaceA. To oczywiście nie jest satysfakcjonujące, ponieważ adres IP Poda może się zmieniać w czasie. Oto problem z adresami IP usług do rozwiązania.

Czy jest więc sposób, aby spełnić to, co wydaje się być obietnicą zawartą w dokumentacji, że mogę skierować usługę w jednej przestrzeni nazw do usługi działającej w innej przestrzeni nazw?

Komentator zapytał, dlaczego chcesz to zrobić - oto przypadek użycia, który ma dla mnie przynajmniej sens:

Załóżmy, że masz system z wieloma dzierżawcami, który obejmuje również wspólną funkcję dostępu do danych, którą można współdzielić między dzierżawcami. Teraz wyobraź sobie, że istnieją różne odmiany tej funkcji dostępu do danych z typowymi interfejsami API, ale różne charakterystyki wydajności. Niektórzy najemcy uzyskują dostęp do jednego z nich, inni do drugiego.

Podsystemy każdego dzierżawcy działają we własnych przestrzeniach nazw, ale każdy z nich musi uzyskać dostęp do jednej z tych wspólnych usług dostępu do danych, która z konieczności będzie znajdować się w innej przestrzeni nazw (ponieważ jest dostępna dla wielu dzierżawców). Ale nie chcesz, aby dzierżawca musiał zmieniać swój kod, jeśli jego subskrypcja ulegnie zmianie, aby uzyskać dostęp do usługi o wyższej wydajności.

Potencjalnym rozwiązaniem (najczystszym, jakie przychodzi mi do głowy, gdyby tylko zadziałało) jest uwzględnienie definicji usługi w przestrzeni nazw każdego dzierżawcy dla usługi dostępu do danych, z każdą skonfigurowaną dla odpowiedniego punktu końcowego. Ta definicja usługi byłaby skonfigurowana tak, aby wskazywała odpowiednią usługę dostępu do danych, z której może korzystać każdy dzierżawca.


celem przestrzeni nazw jest izolacja, więc myślę, że jeśli chcesz przejść przez przestrzenie nazw, musisz wiedzieć przynajmniej, gdzie się one znajdują!
— PanE

Co zatem oznacza dokumentacja, gdy sugeruje, że można skierować usługę zdefiniowaną w jednej przestrzeni nazw, aby uzyskać dostęp do usługi w innej przestrzeni nazw, nie definiując selektora - i przez implikację definiując punkt końcowy? Z pewnością istnieją do tego ważne przypadki użycia - jeden z nich dodałem do pytania. Czy dokumentacja jest po prostu myląca, czy jest na to sposób, którego jeszcze nie rozgryzłem?
— David McKinley

nie jestem pewien, przepraszam. wiem, że uzyskuję dostęp do usług w wielu przestrzeniach nazw za pomocą ich fqdn. Robię to szczególnie z VPN, ponieważ mam 1 pod VPN i łączę się przez wszystkie usługi z niego. jednak musisz znać przestrzeń nazw i podać fqdn. proponuję zapytać na slacku.
— PanE

Obecnie używam fqdn. Mój przypadek użycia byłby jednak lepiej obsługiwany (teraz dodano do pytania), gdyby nie było to konieczne.
— David McKinley

Zastanawiam się również, do czego odnosi się dokumentacja, jednak mogę użyć fqdn jako satysfakcjonującego rozwiązania dla mojego przypadku użycia.
— Vincent De Smet

Odpowiedzi:


225

Natknąłem się na ten sam problem i znalazłem fajne rozwiązanie, które nie wymaga żadnej statycznej konfiguracji IP:

Możesz uzyskać dostęp do usługi za pośrednictwem jej nazwy DNS (jak wspomniałeś): nazwa usługi.namespace.svc.cluster.local

Możesz użyć tej nazwy DNS, aby odwołać się do niej w innej przestrzeni nazw za pośrednictwem usługi lokalnej :

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
To świetne rozwiązanie! Nie jestem pewien, czy typ „nazwa_zewnętrzna” był dostępny dla usług, kiedy pierwotnie zadawałem pytanie, ale jest teraz obsługiwany i zgrabnie rozwiązuje problem. Dzięki, Paul.
— David McKinley,

1
czy to działa? wątpię. Czy ktoś może potwierdzić, czy to naprawdę zadziałało, nie działa dla mnie.
— debianmaster

2
Tak. Działa w przypadku jednego pod, aby komunikować się z usługą w innej przestrzeni nazw, ale nie w przypadku modułu równoważenia obciążenia wejściowego.
— Paul

Ze względu na poprawkę wyszukiwania CNAME w klastrze kubernetes stara wersja może nie działać.
— 赵浩翔

1
Czy / powinno to działać również dla usług w przestrzeni nazw kube-system?
— Nabheet

10

To takie proste

jeśli chcesz go używać jako hosta i chcesz go rozwiązać

Jeśli używasz ambasadora do dowolnej innej bramy API dla usługi znajdującej się w innej przestrzeni nazw, zawsze zaleca się użycie:

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

będzie jak: servicename.namespacename.svc.cluster.local

spowoduje to wysłanie żądania do określonej usługi w przestrzeni nazw, o której wspomniałeś.

przykład:

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

W tym miejscu zastąp <servicename>i <namespace>odpowiednią wartością.

W Kubernetes przestrzenie nazw są używane do tworzenia środowiska wirtualnego, ale wszystkie są ze sobą połączone.


6
Czy mógłbyś wyjaśnić, czym różni się ta odpowiedź od odpowiedzi udzielonej przez Pawła prawie 2 lata wcześniej?
— Oliver

2
@Oliver nie ma różnicy, ale właśnie określiłem, co zastąpić nazwę usługi i przestrzeń nazw, w którym konkretnym miejscu. podczas gdy on używał przestrzeni nazw - a więc wydaje mi się to zagmatwane.
— Harsh Manvar,

7
Poręczną sztuczką na SO jest dodanie komentarza do odpowiedzi i dokonanie niezbędnych wyjaśnień.
— Oliver,

4
Nazwałbym to najlepszym rozwiązaniem, ponieważ .svc.cluster.localjest domyślnie obsługiwane przy rozwiązywaniu usługi wewnętrznie.
— DrKNa

1
działał również dla mnie. dziękuję
— vimal prakash

0

Możesz to osiągnąć, wdrażając coś na wyższym poziomie niż usługi w przestrzeni nazw, takie jak usługa loadbalancer https://github.com/kubernetes/contrib/tree/master/service-loadbalancer . Jeśli chcesz ograniczyć to do jednej przestrzeni nazw, użyj argumentu „--namespace = ns” (domyślnie wszystkie przestrzenie nazw: https://github.com/kubernetes/contrib/blob/master/service-loadbalancer/service_loadbalancer.go # L715 ). Działa to dobrze dla L7, ale jest trochę bałagan w L4.


3
Ten projekt jest teraz przestarzały (
— Nicola Ben

1
@Prashanth B: Czy mógłbyś odpowiednio zaktualizować swoją odpowiedź!
— chaosguru
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.