Utiliser kubernetes-kafka comme point de départ avec minikube.
Ceci utilise un StatefulSet et un service sans en-tête pour la découverte du service dans le cluster.
L’objectif est d’exposer la personne Kafka Courtiers externes auxquels l’adresse interne est adressée comme suit:
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 puisse s'adresser spécifiquement aux courtiers.
Quelle est la bonne (ou une possible) façon de s'y prendre? Est-il possible d'exposer un service externe par kafka-x.broker.kafka.svc.cluster.local:9092
?
Les solutions proposées jusqu'à présent n'étaient pas assez satisfaisantes pour moi, alors je vais poster une réponse personnelle. Mes objectifs:
À partir de Yolean/kubernetes-kafka , la seule chose qui manque, c’est d’exposer le service de façon externe, ce qui pose deux problèmes.
Étiquettes de pod et services externes:
Pour générer des étiquettes par pod, ce problème était vraiment utile. En l’utilisant comme guide, nous ajoutons la ligne suivante au 10broker-config.ymlinit.sh
propriété avec:
kubectl label pods ${HOSTNAME} kafka-set-component=${HOSTNAME}
Nous conservons le service sans tête existant, mais nous générons également un service externe par pod à l'aide de l'étiquette (je les ai ajoutés à 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
Configurez Kafka avec des écouteurs internes/externes
J'ai trouvé ce problème incroyablement utile pour essayer de comprendre comment configurer Kafka.
Cela nécessite à nouveau de mettre à jour le init.sh
et server.properties
propriétés dans 10broker-config.yml avec ce qui suit:
Ajouter ce qui suit au server.properties
pour mettre à jour les protocoles de sécurité (en utilisant actuellement PLAINTEXT
):
listener.security.protocol.map=INTERNAL_PLAINTEXT:PLAINTEXT,EXTERNAL_PLAINTEXT:PLAINTEXT
inter.broker.listener.name=INTERNAL_PLAINTEXT
Déterminez dynamiquement l’adresse IP externe et le port externe de chaque pod du système init.sh
:
EXTERNAL_LISTENER_IP=<your external addressable cluster ip>
EXTERNAL_LISTENER_PORT=$((30093 + ${HOSTNAME##*-}))
Puis configurez listeners
et advertised.listeners
IPs pour EXTERNAL_LISTENER
et INTERNAL_LISTENER
(également dans le init.sh
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
De toute évidence, il ne s’agit pas d’une solution complète pour la production (par exemple, la sécurité des courtiers exposés à l’extérieur) et j’affine encore ma compréhension de la façon de laisser également les producteurs/consommateurs internes communiquer également avec les courtiers.
Cependant, jusqu’à présent, c’est la meilleure approche pour ma compréhension de Kubernetes et de Kafka.
Nous avons résolu ce problème en 1.7 en modifiant le service sans tête en Type=NodePort
et régler le externalTrafficPolicy=Local
. Cela contourne l'équilibrage de la charge interne d'un service et le trafic destiné à un nœud spécifique sur ce port de nœud ne fonctionnera que si un pod Kafka se trouve 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 nodeA et nodeB, nodeB exécute un kafka pod. NodeA: 30000 ne se connectera pas, mais nodeB: 30000 se connectera à kafka = pod fonctionnant sur nodeB.
https://kubernetes.io/docs/tutorials/services/source-ip/#source-ip-for-services-with-typenodeport
Notez que ceci était également disponible dans les annotations bêta de 1.5 et 1.6. Vous trouverez plus d'informations ici sur la disponibilité des fonctionnalités: https://kubernetes.io/docs/tasks/access-application-cluster/create-external-load -balancer/# préservation-le-client-source-ip
Notez également que bien que cela lie un pod kafka) à une identité réseau externe spécifique, cela ne garantit pas que votre volume de stockage sera lié à cette identité réseau. Si vous utilisez VolumeClaimTemplates dans un StatefulSet alors vos volumes sont liés au pod alors que kafka s'attend à ce que le volume soit lié à l'identité du réseau.
Par exemple, si le pod kafka-0 redémarre et que kafka-0 s'affiche sur nodeC au lieu de nodeA, le pvc de kafka si vous utilisez VolumeClaimTemplates) contient des données qu'il est pour nodeA et le courtier qui s'exécute sur kafka-0 commence à rejeter les demandes en pensant qu'il s'agit de nodeA et non de nodeC.
Pour résoudre ce problème, nous attendons avec impatience les volumes locaux persistants, mais nous disposons actuellement d’un seul PVC pour notre kafka StatefulSet et les données sont stockées sous $NODENAME
sur ce PVC pour lier les données de volume à un noeud particulier.
--- (https://github.com/kubernetes/features/issues/121https://kubernetes.io/docs/concepts/storage/volumes/#local
J'aimerais dire que j'avais déjà lu cette question et cette réponse trois fois auparavant pour essayer de comprendre ce qu'étaient les services Headless/quel était leur but. (Et je n'ai jamais bien compris Headless Services, ni le sujet de ce Q & A.)
Et à la 4ème lecture (revisitant après avoir approfondi mes connaissances), il a finalement cliqué/j'ai enfin compris.
Le but de cette réponse est donc de reformuler la question/le problème/de Nadir et de répondre comme si elle l’expliquait à un élève du primaire. Ainsi, ceux qui trébuchent auront l’importance de l’impressionnant Nadir. solution à la première lecture.
Connaissance pratique utile:
Il existe un service de type: NomExterne.
ExternalName Service pointe simplement sur une adresse DNS.
Il existe 2 versions du service ExternalName:
Un Stateful Set se compose de 3 parties:
Il y a 3 choses importantes à retenir à propos de Kube-Proxy:
Il y a 4 choses importantes à retenir à propos d'un service sans tête:
Maintenant que nous comprenons mieux le problème, revenons à la question: comment un service sans tête (qui pointe vers un membre individuel d'un ensemble avec état) peut-il être exposé en externe?
Solution Partie 1:
Tous les pods du cluster peuvent parler aux membres de statefulset.
Parce que le stateful génère un service sans en-tête, avec une adresse DNS de cluster interne prévisible de la forme:
statefulsetname - #. associateheadlessservice.namespace.svc.cluster.local: port
kafka-0.broker.kafka.svc.cluster.local: 9092
kafka-1.broker.kafka.svc.cluster.local: 9092
kafka-2.broker.kafka.svc.cluster.local: 9092
broker.kafka.svc.cluster.local: 9092, peut également être utilisé pour désigner celui qui est disponible.
Solution Part 2:
Vous autorisez le trafic externe à parler aux membres de l'ensemble avec état, en introduisant un deuxième service pouvant accepter le trafic externe, puis en redirigeant le trafic de ce service vers le service sans en-tête ne pouvant accepter que le trafic Internet.
Pour chaque pod de la fonction Stateful, un service de type NomExterne avec une adresse IP de cluster statique virtuelle gérée par Kube-Proxy est créé. Chacun de ces services ExternalName pointe vers/redirige le trafic vers une adresse DNS de cluster interne statique prévisible identifiée dans la solution 1 et, du fait que ce service ExternalName possède un cluster IP statique virtuel géré via Kube-Proxy, il peut y avoir un mappage de NodePorts à celui-ci.
Remplacez le service d'un ClusterIP sans tête par un NodePort qui transmettrait la demande à l'un des nœuds sur un port défini (30092 dans mon exemple) sur le port 9042 du Kafkas. 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.
À partir de la kubernetes kafka documentation :
Accès extérieur avec hostport
Une alternative consiste à utiliser le hostport pour l'accès extérieur. Lors de l'utilisation de ce dernier, un seul kafka courtier peut s'exécuter sur chaque hôte, ce qui est néanmoins une bonne idée.).
Pour passer à hostport, l'adresse de publicité kafka doit être basculée sur le nom ExternalIP ou ExternalDNS du noeud exécutant le courtier.) Dans le commutateur kafka/10broker-config.yml
OUTSIDE_Host=$(kubectl get node "$NODE_NAME" -o jsonpath='{.status.addresses[?(@.type=="ExternalIP")].address}') OUTSIDE_PORT=${OutsidePort}
et dans kafka/50kafka.yml, ajoutez le hostport:
- name: outside containerPort: 9094 hostPort: 9094