web-dev-qa-db-ja.com

Docker Kafka w / Python消費者

私はdockerized Kafkaを使用しており、1つのKafkaコンシューマプログラムを記述しています。Kafkaをdockerとアプリケーションで実行すると、私のローカルマシンで。しかし、Dockerでローカルアプリケーションを構成すると、問題が発生します。この問題は、アプリケーションが起動するまでトピックが作成されないことが原因である可能性があります。

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

エラーログ

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

すでにdocker-composeにdepends_onプロパティを追加したので、トピックアプリケーションの接続を開始する前にエラーが発生しました。

私はdocker-composeファイルにスクリプトを追加できると読みましたが、簡単な方法を探しています。

手伝ってくれてありがとう

13
Pankaj Saboo

あなたの問題はネットワークです。あなたのKafka設定であなたが設定している

KAFKA_ADVERTISED_Host_NAME: localhost

しかし、これは、すべてのクライアント(pythonアプリを含む)がブローカーに接続し、ブローカーからすべての接続にlocalhostを使用するように指示されることを意味します。クライアントマシン(例:pythonコンテナー)がブローカーの場所にない場合、リクエストは失敗します。

Kafkaリスナーの詳細については、こちらをご覧ください: https://rmoff.net/2018/08/02/kafka-listeners-explained/

したがって、問題を解決するには、次の2つのいずれかを実行します。

  1. Kafka(KAFKA_ADVERTISED_Host_NAME: kafka)のinternalホスト名を使用するように構成を変更するだけです。これは、すべてのクライアントwithindocker networkはそれにアクセスできますが、外部クライアントは(たとえば、ホストマシンから)できません):

    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"
    

    その後、クライアントはkafka:9092でブローカーにアクセスするため、pythonアプリは

    consumer = KafkaConsumer('test', bootstrap_servers='kafka:9092')
    
  2. 新しいリスナーをカフカに追加します。これにより、Dockerネットワークの内部と外部の両方にアクセスできます。ポート29092は、(たとえば、ホストから)Dockerネットワークへのアクセスexternal用であり、internalアクセス用の9092です。

    pythonプログラムを正しいアドレスにアクセスするためにKafkaに変更する必要があります。この場合、internalDockerネットワークでは、次を使用します。

    consumer = KafkaConsumer('test', bootstrap_servers='kafka:9092')
    

    私はwurstmeister画像に慣れていないので、このdocker-composeは私が知っているConfluent画像に基づいています:

    (編集者が私のyamlを壊した、あなたは見つけることができる ここにある

    ---
    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
    

免責事項:私はConfluentに勤めています

31
Robin Moffatt

この線

KAFKA_ADVERTISED_Host_NAME: localhost

ブローカーは自分自身をlocalhostでのみ利用可能であると宣伝していると言います。つまり、すべてのKafkaクライアントは実際のブローカーアドレスの実際のリストではなく、自分自身のみを返します。これはクライアントがホストにのみ配置されている場合は問題ありません-リクエストは常にローカルホストに送信されますコンテナに転送されます

ただし、他のコンテナー内のアプリの場合、Kafkaコンテナーを指す必要があるため、KAFKA_ADVERTISED_Host_NAME: kafka、ここでkafkaはDocker Composeサービスの名前です。次に、他のコンテナのクライアントはそのコンテナに接続しようとします


とはいえ、この行は

consumer = KafkaConsumer('test', bootstrap_servers='localhost:9092')

あなたはPythonコンテナそれ自体を指しており、kafkaコンテナを指していない。

kafka:9092代わりに

4
cricket_007