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.

David McKinley
źródło
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
Paweł
źródło
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.

Harsh Manvar
źródło
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.

Prashanth B
źródło
3
Ten projekt jest teraz przestarzały (
Nicola Ben
1
@Prashanth B: Czy mógłbyś odpowiednio zaktualizować swoją odpowiedź!
chaosguru