web-dev-qa-db-fra.com

Docker Kafka w / Python consumer

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

13
Pankaj Saboo

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:

  1. 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')
    
  2. 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

31
Robin Moffatt

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

4
cricket_007