Jak wyeksponować usługę bez głowy dla StatefulSet zewnętrznie w Kubernetes

Dzięki temu, że nie ma problemu, nie ma problemu.

Do wykrywania usług w klastrze używane są StatefulSet i usługa bez głowy.

Celem jest ujawnienie poszczególnych brokerów Kafka zewnętrznie, które są wewnętrznie adresowane jako:

kafka-0.broker.kafka.svc.cluster.local:9092
kafka-1.broker.kafka.svc.cluster.local:9092 
kafka-2.broker.kafka.svc.cluster.local:9092

Ograniczenie polega na tym, że ta usługa zewnętrzna jest w stanie zwrócić się konkretnie do brokerów.

Jaki jest właściwy (lub jeden możliwy) sposób na to? Czy możliwe jest wystawienie serwis zewnętrzny za kafka-x.broker.kafka.svc.cluster.local:9092?

Author: Nadir Muzaffar, 2017-09-27

5 answers

Rozwiązaliśmy to w 1.7 zmieniając usługę headless na Type=NodePort i ustawiając externalTrafficPolicy=Local. To omija wewnętrzne równoważenie obciążenia usługi i ruchu przeznaczonego do określonego węzła na tym porcie węzła będzie działać tylko wtedy, gdy Kafka pod znajduje się na tym węźle.

apiVersion: v1
kind: Service
metadata:
  name: broker
spec:
  externalTrafficPolicy: Local
  ports:
  - nodePort: 30000
    port: 30000
    protocol: TCP
    targetPort: 9092
  selector:
    app: broker
  type: NodePort

Na przykład, mamy dwa węzły nodeA i nodeB, nodeB uruchamia Kafka pod. nodeA: 30000 nie połączy się, ale nodeB: 30000 połączy się z kafka pod działającym na nodeB.

Https://kubernetes.io/docs/tutorials/services/source-ip/#source-ip-for-services-with-typenodeport

Uwaga To było również dostępne w 1.5 i 1.6 jako adnotacja beta, więcej można znaleźć tutaj na temat dostępności funkcji: https://kubernetes.io/docs/tasks/access-application-cluster/create-external-load-balancer/#preserving-the-client-source-ip

Zauważ również, że chociaż wiąże to Kafkę pod z określoną zewnętrzną tożsamością sieci, nie upewnij się, że wolumin pamięci masowej będzie powiązany z tą tożsamością sieciową. Jeśli używasz VolumeClaimTemplates w zestawie Stanów, Twoje woluminy są powiązane z pod, podczas gdy kafka oczekuje, że wolumin będzie powiązany z tożsamością sieciową.

Na przykład, jeśli pod kafka-0 restartuje się i kafka-0 pojawia się na nodeC zamiast nodeA, kafka-0 ' S pvc (jeśli używa VolumeClaimTemplates) ma dane, które są dla nodeA, a broker działający na kafka-0 zaczyna odrzucać żądania myśląc, że jest nodeA nie nodeC.

Aby to naprawić, czekamy na lokalne stałe woluminy, ale teraz mamy pojedynczy PVC dla naszego Kafka StatefulSet i dane są przechowywane pod $NODENAME na tym PVC, aby powiązać dane woluminów z konkretnym węzłem.

Https://github.com/kubernetes/features/issues/121 https://kubernetes.io/docs/concepts/storage/volumes/#local

 17
Author: Jason Kincl,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-10-14 12:35:32

Rozwiązania do tej pory nie były wystarczająco satysfakcjonujące dla mnie, więc zamierzam opublikować własną odpowiedź. Moje cele:

  1. Pods powinny być nadal dynamicznie zarządzane za pomocą StatefulSet tak bardzo, jak to możliwe.
  2. Utwórz zewnętrzną usługę dla Pod (tj. Kafka Broker) dla klientów producentów/konsumentów i unikaj równoważenia obciążenia.
  3. Stwórz wewnętrzną usługę bez głowy, aby każdy Broker mógł się ze sobą komunikować.

Zaczynając od yolean/kubernetes-kafka , brakuje tylko eksponowania serwisu Na zewnątrz i dwóch wyzwań w tym zakresie.

  1. generowanie unikalnych etykiet dla pod brokera, dzięki czemu możemy stworzyć zewnętrzną usługę dla każdego Pod brokera.
  2. powiedzenie pośrednikom, aby komunikowali się ze sobą za pomocą usługi wewnętrznej, konfigurując Kafka, aby powiedział producentowi / konsumentom, aby komunikowali się za pośrednictwem usługi zewnętrznej.

Na etykiety pod i zewnętrzne usługi:

Aby wygenerować etykiety dla pod, ten problem był naprawdę pomocny. Używając go jako przewodnika, dodajemy następującą linię do 10broker-config.yml init.sh własność z:

kubectl label pods ${HOSTNAME} kafka-set-component=${HOSTNAME}

Zachowujemy istniejącą usługę bez głowy, ale generujemy również zewnętrzną Usługę dla pod za pomocą etykiety (dodałem je do 20dns.yml):

apiVersion: v1
kind: Service
metadata:
  name: broker-0
   namespace: kafka
spec:
  type: NodePort
  ports:
  - port: 9093
    nodePort: 30093
selector:
  kafka-set-component: kafka-0

Konfiguracja Kafki z wewnętrznymi / zewnętrznymi słuchaczami

Znalazłem ten numer niezwykle przydatne w próbie zrozumienia, jak skonfigurować Kafka.

To ponownie wymaga aktualizacji właściwości init.sh i server.propertiesw 10broker-config.yml z następującym:

Dodaj do server.properties, aby zaktualizować protokoły bezpieczeństwa (obecnie używające PLAINTEXT):

listener.security.protocol.map=INTERNAL_PLAINTEXT:PLAINTEXT,EXTERNAL_PLAINTEXT:PLAINTEXT
inter.broker.listener.name=INTERNAL_PLAINTEXT

Dynamiczne określanie zewnętrznego IP i zewnętrznego portu dla każdego Pod w init.sh:

EXTERNAL_LISTENER_IP=<your external addressable cluster ip>
EXTERNAL_LISTENER_PORT=$((30093 + ${HOSTNAME##*-}))

Następnie skonfiguruj listeners i advertised.listeners IPs dla EXTERNAL_LISTENER i INTERNAL_LISTENER (również w init.sh własność):

sed -i "s/#listeners=PLAINTEXT:\/\/:9092/listeners=INTERNAL_PLAINTEXT:\/\/0.0.0.0:9092,EXTERNAL_PLAINTEXT:\/\/0.0.0.0:9093/" /etc/kafka/server.properties
sed -i "s/#advertised.listeners=PLAINTEXT:\/\/your.host.name:9092/advertised.listeners=INTERNAL_PLAINTEXT:\/\/$HOSTNAME.broker.kafka.svc.cluster.local:9092,EXTERNAL_PLAINTEXT:\/\/$EXTERNAL_LISTENER_IP:$EXTERNAL_LISTENER_PORT/" /etc/kafka/server.properties

Oczywiście nie jest to pełne rozwiązanie dla produkcji (na przykład dotyczące bezpieczeństwa zewnętrznych brokerów) i nadal doskonalę swoje zrozumienie, jak również pozwolić wewnętrznym producentom / konsumentom komunikować się z brokerami.

Jednak jak na razie jest to najlepsze podejście do mojego zrozumienia Kubernetes i Kafka.

 17
Author: Nadir Muzaffar,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-05-23 10:50:52

Chciałbym powiedzieć, że przeczytałem to pytanie i odpowiedziałem 3 razy wcześniej od próby owinięcia głowy wokół tego, co było Bezgłowe usługi/jaki był ich cel. (i nigdy w pełni nie rozumiałem usług bezgłowych, ani tego, o co chodziło w tym Q&A.)
i na 4 czytaniu (powracając do niego po dalszej edukacji) w końcu kliknęło/w końcu zrozumiałem.

tak więc celem tej odpowiedzi jest powtórzenie pytania/problemu / Nadira i odpowiedź tak, jakby wyjaśniając to uczniowi. Więc że inni, którzy się na to natkną, otrzymają znaczenie niesamowitego rozwiązania Nadira przy pierwszym czytaniu.

Przydatna Wiedza:

  • Istnieje usługa typu: ExternalName.
    ExternalName Usługa po prostu wskazuje na adres DNS.
    istnieją 2 smaki ExternalName Service:

    1. BEZ IP klastra:
      dobrym przypadkiem użycia byłoby umożliwienie klastrowi testowemu i klastrowi produkcyjnemu współdzielenia tyle kodu jako możliwe. (a w niektórych przypadkach dla prostego wygody) strąki w obu testy i produkcja wskazywałyby na ten sam adres DNS usługi Nazwa, to będzie przewidywalny kod wielokrotnego użytku. Różnica byłoby, że środowisko testujące będzie miało usługę, która wskazuje na usługę SQL, która istnieje wewnątrz klastra. Na klaster produkcyjny korzystałby z usługi ExternalName, która przekierowanie/wskaż adres DNS dostawcy chmury zarządzanego SQL rozwiązanie.
    2. z gromadą IP:
      jest to wersja usługi ExternalName, która jest kluczem do rozwiązania.

  • Zbiór stanów składa się z 3 części:

    1. Porządkowy
    2. Trwałe Przechowywanie
    3. uporczywy IP (ale to nie jest przewidywalne)
  • Są 3 ważne rzeczy do zapamiętania o Kube-Proxy:

    1. to sprawia, że wszystko ma unikalne IP.
    2. jest odpowiedzialny za implementację wirtualnych adresów IP klastra statycznego (wirtualne adresy IP klastra statycznego są uważane za wirtualne, ponieważ istnieją tylko w każdym węzle iptables w implementacji iptables Kube-Proxy, lub w tabeli Hash jądra w wersji IP-vs next-gen Kube-Proxy) i jest również odpowiedzialny za logiczny efekt równoważenia obciążenia, który występuje w normalnych usługach.
    3. KubeProxy jest odpowiedzialny za mapowanie ruchu, który przychodzi na NodePorts do odpowiednia normalna usługa.
  • Są 4 ważne rzeczy do zapamiętania o Bezgłowej służbie:

    1. tworzy przewidywalny Adres DNS.
    2. nie działa jako wewnętrzny cluster Load Balancer. Rozmawiasz bezpośrednio z pod zidentyfikowanym przez przewidywalny Adres DNS. (które jest bardzo pożądane dla obciążeń stateful)
    3. nie ma statycznego adresu IP klastra.
    4. jako efekt uboczny cech 2 i 3, jest poza sferą Kube-Proxy (która jest odpowiedzialna za kierowanie ruchem wchodzącym na Node Porty Do usług.parafrazuję to kilka razy, więc problem w tym, że NodePorts zazwyczaj nie może przekierowywać ruchu do Headless Usługi. Ruch zewnętrzny wchodzący do klastra zazwyczaj nie może być przekazane do Usługi Bezgłowe. Nie jest intuicyjne, jak na zewnątrz / align = "left" /


stąd pierwotne pytanie: w jaki sposób usługa Bezgłowa (która wskazuje na pojedynczego członka Państwowego zestawu) może być eksponowana zewnętrznie?

Przed dodaniem usługi bez głowy do zestawu Stateful, pods kafka - 0, kafka-1 i kafka-2 miałyby statyczne adresy IP, ale statycznego adresu IP nie można było przewidzieć.

Bezgłowy Serwis daje Stateful Set przewidywalne adresy DNS klastra wewnętrznego (a Stateful Set nie potrzebował statycznego adresu IP klastra, ponieważ miał już taki jako część swojej tożsamości jako zestaw Stateful) Kafka-0.broker.kafka.svc.klaster.local: 9092 Kafka-1.broker.kafka.svc.klaster.local: 9092 Kafka-2.broker.kafka.svc.klaster.local: 9092

Rozwiązanie Część 1:
Przewidywalne adresy DNS klastra wewnętrznego rozwiązują dostęp klastra wewnętrznego do zestawów stanu.
(pozwala to na pods w zestawie stanowym, aby rozmawiać między sobą i pozwala innym pods w klastrze, aby uzyskać do nich dostęp.)

Część Rozwiązania 2:
Drugie rozwiązanie jest potrzebne do rozwiązania zewnętrznego dostępu do zestawów/zasobów Stateful poza klastrem, aby móc uzyskać dostęp do zestawów stateful wewnątrz klastra.
dla każdego pod W Zestawie Stanowym tworzona jest usługa typu ExternalName z wirtualnym statycznym adresem ClusterIP zarządzanym przez Kube-Proxy. Każdy punkt aby / przekierowuje ruch na przewidywalny statyczny adres wewnętrzny klastra DNS zidentyfikowany w rozwiązaniu 1, A ponieważ ta usługa ExternalName ma wirtualny statyczny Klaster zarządzany przez Kube-Proxy, może być mapowanie z NodePorts do niego.

 3
Author: neokyle,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-08-13 02:48:32

Zmień usługę z Bezgłowego klastra na NodePort, który przekierowałby żądanie do dowolnego z węzłów na ustawionym porcie (w moim przykładzie 30092) na port 9042 na Kafkas. Trafiłbyś losowo w jedną z kapsuł, ale myślę, że to jest w porządku.

20dns.YML staje się (coś takiego):

# A no longer headless service to create DNS records
---
apiVersion: v1
kind: Service
metadata:
  name: broker
  namespace: kafka
spec:
  type: NodePort
  ports:
  - port: 9092
  - nodePort: 30092
  # [podname].broker.kafka.svc.cluster.local
  selector:
    app: kafka

Zastrzeżenie: możesz potrzebować dwóch usług. Jeden bezgłowy dla wewnętrznych nazw dns i jeden NodePort dla dostępu zewnętrznego. Sam tego nie próbowałem.

 2
Author: Andreas Wederbrand,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-09-27 20:09:13

Z dokumentacji kubernetes kafka :

Zewnętrzny dostęp z hostport

Alternatywą jest użycie hostportu dla zewnętrznego dostępu. Kiedy korzystanie z tego tylko jednego brokera kafka może działać na każdym Hostie, co jest dobrym pomysł w każdym razie.

Aby przełączyć się na hostport adres reklamowy kafka musi być switched to the ExternalIP or ExternalDNS name of the node running the broker. w kafka/10broker-config.YML switch to

OUTSIDE_HOST=$(kubectl get node "$NODE_NAME" -o jsonpath='{.status.addresses[?(@.type=="ExternalIP")].address}')
OUTSIDE_PORT=${OutsidePort}

I w kafka/50kafka.yml dodaj hostport:

    - name: outside
      containerPort: 9094
      hostPort: 9094
 1
Author: herm,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-08-21 13:42:41