J'utilise dockerized Kafka et j'en ai écrit un Kafka programme grand public. Il fonctionne parfaitement lorsque j'exécute Kafka dans le docker et l'application) sur ma machine locale. Mais lorsque j'ai configuré l'application locale dans Docker, je rencontre des problèmes. Le problème peut être dû à un sujet qui n'a pas été créé avant le démarrage de l'application.
docker-compose.yml
version: '3'
services:
zookeeper:
image: wurstmeister/zookeeper
ports:
- "2181:2181"
kafka:
image: wurstmeister/kafka
ports:
- "9092:9092"
environment:
KAFKA_ADVERTISED_Host_NAME: localhost
KAFKA_CREATE_TOPICS: "test:1:1"
KAFKA_ZOOKEEPER_CONNECT: zookeeper:2181
volumes:
- /var/run/docker.sock:/var/run/docker.sock
parse-engine:
build: .
depends_on:
- "kafka"
command: python parse-engine.py
ports:
- "5000:5000"
parse-engine.py
from kafka import KafkaConsumer
import json
try:
print('Welcome to parse engine')
consumer = KafkaConsumer('test', bootstrap_servers='localhost:9092')
for message in consumer:
print(message)
except Exception as e:
print(e)
# Logs the error appropriately.
pass
Journal des erreurs
kafka_1 | [2018-09-21 06:27:17,400] INFO [SocketServer brokerId=1001] Started processors for 1 acceptors (kafka.network.SocketServer)
kafka_1 | [2018-09-21 06:27:17,404] INFO Kafka version : 2.0.0 (org.Apache.kafka.common.utils.AppInfoParser)
kafka_1 | [2018-09-21 06:27:17,404] INFO Kafka commitId : 3402a8361b734732 (org.Apache.kafka.common.utils.AppInfoParser)
kafka_1 | [2018-09-21 06:27:17,431] INFO [KafkaServer id=1001] started (kafka.server.KafkaServer)
**parse-engine_1 | Welcome to parse engine
parse-engine_1 | NoBrokersAvailable
parseengine_parse-engine_1 exited with code 0**
kafka_1 | creating topics: test:1:1
Comme j'ai déjà ajouté la propriété depend_on dans docker-compose, mais avant de démarrer la connexion de l'application de rubrique, une erreur s'est produite.
J'ai lu que je peux ajouter le script dans le fichier docker-compose mais je cherche un moyen simple.
Merci pour l'aide
Votre problème est le réseautage. Dans votre configuration Kafka que vous définissez
KAFKA_ADVERTISED_Host_NAME: localhost
mais cela signifie que tout client (y compris votre python) se connectera au courtier, puis lui demandera d'utiliser localhost
pour toutes les connexions. Étant donné que localhost de votre l'ordinateur client (par exemple, votre python) n'est pas là où se trouve le courtier, les demandes échoueront.
Vous pouvez en savoir plus sur Kafka auditeurs en détail ici: https://rmoff.net/2018/08/02/kafka-listeners-explained/
Donc, pour résoudre votre problème, vous pouvez faire l'une des deux choses suivantes:
Modifiez simplement votre composition pour utiliser le nom d'hôte interne pour Kafka (KAFKA_ADVERTISED_Host_NAME: kafka
). Cela signifie que tous les clients dans le réseau docker pourront y accéder correctement, mais aucun client externe pourra (par exemple depuis votre machine hôte):
version: '3'
services:
zookeeper:
image: wurstmeister/zookeeper
ports:
- "2181:2181"
kafka:
image: wurstmeister/kafka
ports:
- "9092:9092"
environment:
KAFKA_ADVERTISED_Host_NAME: kafka
KAFKA_CREATE_TOPICS: "test:1:1"
KAFKA_ZOOKEEPER_CONNECT: zookeeper:2181
volumes:
- /var/run/docker.sock:/var/run/docker.sock
parse-engine:
build: .
depends_on:
- "kafka"
command: python parse-engine.py
ports:
- "5000:5000"
Vos clients accèderaient alors au courtier à kafka: 9092, donc votre application python se changerait en
consumer = KafkaConsumer('test', bootstrap_servers='kafka:9092')
Ajoutez un nouvel écouteur à Kafka. Cela lui permet d'être accessible à la fois en interne et en externe au réseau docker. Le port 29092 serait pour l'accès externe au réseau docker (par exemple à partir de votre hôte), et 9092 pour l'accès interne .
Vous auriez encore besoin de changer votre programme python pour accéder à Kafka à la bonne adresse. Dans ce cas, puisque c'est interne au réseau Docker, vous utiliseriez:
consumer = KafkaConsumer('test', bootstrap_servers='kafka:9092')
Comme je ne connais pas les images wurstmeister
, ce docker-compose est basé sur les images Confluent que je connais:
(l'éditeur a déformé mon yaml, vous pouvez trouver ici )
---
version: '2'
services:
zookeeper:
image: confluentinc/cp-zookeeper:latest
environment:
ZOOKEEPER_CLIENT_PORT: 2181
ZOOKEEPER_TICK_TIME: 2000
kafka:
# "`-._,-'"`-._,-'"`-._,-'"`-._,-'"`-._,-'"`-._,-'"`-._,-'"`-._,-'"`-._,-
# An important note about accessing Kafka from clients on other machines:
# -----------------------------------------------------------------------
#
# The config used here exposes port 29092 for _external_ connections to the broker
# i.e. those from _outside_ the docker network. This could be from the Host machine
# running docker, or maybe further afield if you've got a more complicated setup.
# If the latter is true, you will need to change the value 'localhost' in
# KAFKA_ADVERTISED_LISTENERS to one that is resolvable to the docker Host from those
# remote clients
#
# For connections _internal_ to the docker network, such as from other services
# and components, use kafka:9092.
#
# See https://rmoff.net/2018/08/02/kafka-listeners-explained/ for details
# "`-._,-'"`-._,-'"`-._,-'"`-._,-'"`-._,-'"`-._,-'"`-._,-'"`-._,-'"`-._,-
#
image: confluentinc/cp-kafka:latest
depends_on:
- zookeeper
ports:
- 29092:29092
environment:
KAFKA_BROKER_ID: 1
KAFKA_ZOOKEEPER_CONNECT: zookeeper:2181
KAFKA_ADVERTISED_LISTENERS: PLAINTEXT://kafka:9092,PLAINTEXT_Host://localhost:29092
KAFKA_LISTENER_SECURITY_PROTOCOL_MAP: PLAINTEXT:PLAINTEXT,PLAINTEXT_Host:PLAINTEXT
KAFKA_INTER_BROKER_LISTENER_NAME: PLAINTEXT
KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR: 1
Avertissement: je travaille pour Confluent
Cette ligne
KAFKA_ADVERTISED_Host_NAME: localhost
Dit que le courtier se fait connaître comme étant disponible uniquement sur localhost
, ce qui signifie que tous les clients Kafka ne se retrouveraient que lui-même, pas la liste réelle des adresses réelles du courtier. Ce serait très bien si vos clients ne se trouvent que sur votre hôte - les demandes vont toujours à localhost, qui est transmis au conteneur.
Mais, pour les applications dans d'autres conteneurs, ils doivent pointer vers le conteneur Kafka, il devrait donc indiquer KAFKA_ADVERTISED_Host_NAME: kafka
, où kafka
voici le nom du Docker Compose Service. Ensuite, les clients dans d'autres conteneurs essaient de se connecter à celui-ci
Cela étant dit, cette ligne
consumer = KafkaConsumer('test', bootstrap_servers='localhost:9092')
Vous pointez le conteneur Python en lui-même, pas le conteneur kafka
.
Il faut dire kafka:9092
au lieu