67 votes

Comment exposer un service sans accès pour un StatefulSet en externe dans Kubernetes

À l'aide de kubernetes-kafka comme un point de départ avec minikube.

Il utilise un StatefulSet et un headless de service pour le service de découverte au sein du cluster.

L'objectif est d'exposer l'individu Kafka Courtiers de l'extérieur qui ont été abordés comme:

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

La contrainte est que ce service externe de traiter les courtiers en particulier.

Quel est le droit (ou une) façon d'aller à ce sujet? Est-il possible d'exposer un service externe par kafka-x.broker.kafka.svc.cluster.local:9092?

37voto

Jason Kincl Points 679

Nous avons résolu ce problème en 1.7 en changeant la tête du service d' Type=NodePort et réglage de l' externalTrafficPolicy=Local. Ce court-circuite l'intérieur d'équilibrage de la charge d'un Service et le trafic destiné à un nœud spécifique sur ce nœud de port ne fonctionne que si un Kafka pod est sur ce nœud.

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

Par exemple, nous avons deux nœuds noeuda a et b, b est en cours d'exécution d'un kafka de la gousse. noeuda:30000 va pas vous connecter, mais nodeB:30000 va se connecter à la kafka pod en cours d'exécution sur le nodeB.

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

Notez que c'était aussi disponible en 1.5 et 1.6 bêta de l'annotation, de plus peut être trouvé ici sur la disponibilité de la fonctionnalité: https://kubernetes.io/docs/tasks/access-application-cluster/create-external-load-balancer/#preserving-the-client-source-ip

Notez également que tout cela est lié à un kafka pod à un réseau externe de l'identité, il ne garantit pas que votre volume de stockage sera liée à l'identité de réseau. Si vous utilisez le VolumeClaimTemplates dans un StatefulSet ensuite vos volumes sont liés à la gousse alors que kafka s'attend à ce que le volume soit liée à l'identité de réseau.

Par exemple, si l'kafka-0 pod redémarre et kafka-0 se lève sur nodeC au lieu de noeuda, kafka-0 de pvc (si vous utilisez VolumeClaimTemplates) dispose de données qu'il est pour noeuda et le courtier exécutant sur kafka-0 commence à rejeter les demandes en pensant que c'est noeuda pas nodeC.

Pour résoudre ce problème, nous nous réjouissons à l'Locale Persistante des Volumes, mais maintenant nous avons un seul PVC pour notre kafka StatefulSet et les données sont stockées sous $NODENAME sur que le PVC pour attacher le volume de données à un nœud particulier.

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

30voto

Nadir Muzaffar Points 1621

Les Solutions jusqu'à présent n'étaient pas tout à fait satisfaisant assez pour moi, donc je vais poster une réponse de ma part. Mes objectifs:

  1. Les gousses doivent encore être gérée de façon dynamique par le biais d'un StatefulSet autant que possible.
  2. Créer un service externe par Gousse (j'.e Kafka Courtier) pour Producteur/Consommateur, les clients et d'éviter l'équilibrage de la charge.
  3. Créer un intérieur sans tête, de service, de sorte que chaque Courtier est en mesure de communiquer les uns avec les autres.

En commençant par Yolean/kubernetes-kafka, la seule chose qui manque est d'exposer le service à l'externe et à deux défis.

  1. La génération des étiquettes uniques par Courtier en pod, de sorte que nous pouvons créer un service externe pour chacun des Courtier en gousses.
  2. Raconter les Courtiers de communiquer les uns aux autres en utilisant le Service interne lors de la configuration de Kafka à dire les producteurs/consommateurs de communiquer sur le Service extérieur.

Par gousse d'étiquettes et de services extérieurs:

Pour générer des étiquettes par gousse, cette question a été vraiment utile. En l'utilisant comme un guide, nous avons ajouter la ligne suivante à la 10broker-config.yml init.sh bien avec:

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

Nous de garder les headless service, mais nous avons également générer un Service externe par gousse à l'aide de l'étiquette (j'ai ajouté à 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

Configurer Kafka interne/externe des auditeurs

J'ai trouvé cette question incroyablement utile en essayant de comprendre comment configurer Kafka.

Cela nécessite à nouveau la mise à jour de l' init.sh et server.properties propriétés dans 10broker-config.yml avec les éléments suivants:

Ajouter les éléments suivants à l' server.properties de mettre à jour les protocoles de sécurité (actuellement à l'aide de PLAINTEXT):

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

Déterminer dynamiquement l'adresse IP externe et pour le port externe pour chaque Pod dans l' init.sh:

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

Puis configurer listeners et advertised.listeners IPs pour EXTERNAL_LISTENER et INTERNAL_LISTENER (également dans l' init.sh de la propriété):

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

Évidemment, ce n'est pas une solution complète pour la production (par exemple portant sur la sécurité pour l'exposition externe des courtiers) et je suis toujours raffinage ma compréhension de la façon de les laisser aussi interne producteurs/consommateurs aussi communiquer avec le courtier.

Cependant, jusqu'à présent, c'est la meilleure approche pour ma compréhension de Kubernetes et Kafka.

22voto

neokyle Points 16

Je tiens à dire que j'avais lu cette Question et de Répondre à 3 fois avant d'essayer d'envelopper ma tête autour de ce qui Headless Services ont été/ce qui est le point d'eux a été. (et je n'ai jamais pleinement compris sans Tête, des Services, ou que ce Q&a sur.)
Et sur la 4ème de lecture (revoir après plus d'éduquer moi-même), il a finalement cliqué/j'ai enfin compris.

Donc, le but de cette réponse est de rappeler Nadir est question/problème/et la réponse, comme si l'expliquer à un grade schooler. De sorte que les autres qui trébuchent sur cette obtiendrez de l'importance de Nadir est génial solution sur la première lecture.

Utile De Connaissances:

  • Il existe un Service de type: ExternalName.
    ExternalName Service tout simplement des points pour une adresse DNS.
    Il y a 2 Saveurs de ExternalName Service:

    1. Sans IP du Cluster:
      Un bon cas d'utilisation serait de permettre à un test de cluster et un cluster de production de partager autant de code que possible. (et pour de simples conviencence dans certains cas) des Gousses dans les deux de test et de production point pour le même service à l'Intérieur du Cluster Adresse DNS Nom, qui serait prévisible réutilisables code. La différence serait que le contrôle de l'environnement aurait un service qui points à un service SQL qui existe à l'intérieur du cluster. L' cluster de production serait d'utiliser un ExternalName Service, qui serait rediriger/point à l'Adresse DNS des Fournisseurs de Cloud Géré SQL solution.
    2. Avec un IP de Cluster:
      C'est la version d'un ExternalName Service qui est la clé de la solution.

  • Avec un état de Jeu comporte 3 parties de son identité:

    1. Un Nombre Ordinal (Nombre)
    2. Le Stockage Persistant
    3. Permanent et prévisible Intérieure Cluster de Nom DNS (il devient ce à partir de l'exigence qu'il doit être livré avec une Tête de service)

  • Il y a 3 choses importantes à retenir à propos de Kube-Proxy:

    1. Elle fait en sorte que tout ce qui a une adresse IP unique.
    2. Il est responsable de la mise en œuvre du Virtuel Statique IP de Cluster (le Virtuel Statique IP du Cluster sont considérés comme des virtuel, car ils n'existent que dans tous les nœuds iptables iptables sur la mise en œuvre de Kube-Proxy, ou dans le Noyau de la Table de Hachage dans l'ip-vs next-gen version de Kube-Proxy) et il est également responsable de la Logique d'Équilibrage de la Charge de l'effet qui se produit avec la Normale Kubernetes de Services qui ont une IP de Cluster.
    3. KubeProxy est responsable de la cartographie de la Circulation qui monte en NodePorts à un correspondant Kubernetes Service avec un statique IP du Cluster. <-- Ceci est très important à la condition que la Dynamique de Services devraient être une exposition externe, NodePorts sont toujours censés être impliqués lors de la il s'agit à l'extérieur de l'exposition de services.

  • Il y a 4 choses importantes à retenir à propos de une Tête du Service:

    1. Il crée un prévisible Adresse DNS.
    2. Il n'agit pas comme un interne cluster d'Équilibrage de la Charge. Vous parlez directement à la gousse identifiés par les prévisible Adresse DNS. (qui est très souhaitable pour la dynamique des charges de travail)
    3. Il n'a pas Statique IP du Cluster.
    4. Comme un effet secondaire de qualités, 2 et 3, c'est en dehors du Domaine de Kube-Proxy (qui est responsable de diriger le trafic arrivant sur l' Nœud de Ports pour les Services.) Je vais paraphraser ce un peu de temps afin que le problème enfonce dans l': NodePorts peut généralement pas acheminer le trafic à Headless Services. Externe le trafic entrant dans le cluster ne peut pas être habituellement transmis à la Tête des Services. Ce n'est pas intuitive comment de l'extérieur exposer une Tête de Service.


Maintenant que nous comprenons mieux le problème, permet de revenir à la question: Comment une Tête de Service (qui renvoie à une personne membre d'un stateful set) être une exposition externe?

Solution Partie 1:
Toute pod dans le cluster peut parler aux membres de la statefulset.

Parce que la dynamique de générer une tête de service, avec un prévisible intérieure cluster DNS adresse de la forme:
statefulsetname-#.associatedheadlessservice.espace de noms.svc.cluster.locale:port
kafka-0.courtier.kafka.svc.cluster.local:9092
kafka-1.courtier.kafka.svc.cluster.local:9092
kafka-2.courtier.kafka.svc.cluster.local:9092
courtier.kafka.svc.cluster.local:9092, peut également être utilisé pour se référer à qui jamais qui est disponible.

Solution Partie 2:
Vous autorisez le trafic externe de parler à des membres de la dynamique de définir, par l'introduction d'un 2ème service qui peut accepter le trafic externe, puis rediriger le trafic en provenance de ce service à la tête du service qui ne peut accepter le trafic internet.

Pour chaque pod dans la Dynamique de Définir un Service de type ExternalName avec un Virtuel Statique ClusterIP Adresse qui est géré par Kube-Proxy est créé. Chacun de ces ExternalName points de Services à l'/redirige le trafic vers un prévisible statique intérieure DNS de cluster à l'Adresse indiquée dans la Solution 1, et parce que cette ExternalName service dispose d'un quasi-Statique ClusterIP géré par Kube-Proxy, il peut y avoir une correspondance entre NodePorts à elle.

2voto

Andreas Wederbrand Points 10606

Remplacez le service d'un ClusterIP sans tête par un NodePort qui transmettrait la demande à l'un des nœuds d'un port défini (30092 dans mon exemple) sur le port 9042 de la Kafka. Vous frapperiez une des gousses au hasard, mais je suppose que ça va.

20dns.yml devient (quelque chose comme ceci):

 # 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
 

Avertissement: Vous aurez peut-être besoin de deux services. Un sans tête pour les noms DNS internes et un NodePort pour l'accès externe. Je n'ai pas essayé cela moi-même.

1voto

herm Points 3022

À partir de la kubernetes kafka documentation:

Accès par l'extérieur avec hostport

Une alternative est d'utiliser le hostport pour l'accès à l'extérieur. Lorsque à l'aide de cette seule kafka courtier peut s'exécuter sur chaque hôte, ce qui est une bonne idée de toute façon.

Afin de passer à hostport le kafka de la publicité doit être passé à la ExternalIP ou ExternalDNS nom du nœud de l'exécution de l' courtier. dans kafka/10broker-config.yml passer à

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

et dans kafka/50kafka.yml ajouter le hostport:

    - name: outside
      containerPort: 9094
      hostPort: 9094

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X