[英]Kafka producer and consumer not working properly on python with docker
[英]Docker Kafka w/ Python consumer
我正在使用 dockerized Kafka 并编写了一个 Kafka 消费者程序。 当我在本地机器上的 docker 和应用程序中运行 Kafka 时,它可以完美运行。 但是当我在 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"
解析引擎.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 文件中添加脚本,但我正在寻找一些简单的方法。
感谢帮助
你的问题是网络。 在您的 Kafka 配置中,您正在设置
KAFKA_ADVERTISED_HOST_NAME: localhost
但这意味着任何客户端(包括您的 python 应用程序)都将连接到代理,然后代理会告诉代理使用localhost
进行任何连接。 由于来自您的客户端机器(例如您的 Python 容器)的 localhost 不是代理所在的位置,因此请求将失败。
您可以在此处详细阅读有关修复 Kafka 侦听器问题的更多信息
因此,要解决您的问题,您可以执行以下两项操作之一:
只需更改您的撰写以使用 Kafka 的内部主机名( KAFKA_ADVERTISED_HOST_NAME: kafka
)。 这意味着泊坞窗网络中的任何客户端将能够精细访问它,但是没有外部客户端将能够(例如,从您的主机):
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')
向 Kafka添加一个新的侦听器。 这使得它可以在 docker 网络内部和外部访问。 端口 29092 用于访问 docker 网络外部(例如从您的主机),而 9092 用于内部访问。
您仍然需要更改您的 python 程序以在正确的地址访问 Kafka。 在这种情况下,由于它在 Docker 网络内部,您可以使用:
consumer = KafkaConsumer('test', bootstrap_servers='kafka:9092')
由于我不熟悉wurstmeister
图像,这个wurstmeister
-compose 基于我知道的 Confluent 图像:
--- 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 # ie 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 工作
这条线
KAFKA_ADVERTISED_HOST_NAME: localhost
说代理将自己宣传为仅在localhost
上可用,这意味着所有 Kafka 客户端只会取回自己,而不是实际代理地址的实际列表。 如果您的客户端仅位于您的主机上,这会很好 - 请求始终转到 localhost,然后转发到容器。
但是,对于其他容器中的应用程序,它们需要指向 Kafka 容器,因此应该说KAFKA_ADVERTISED_HOST_NAME: kafka
,这里的kafka
是 Docker Compose 服务的名称。 然后其他容器中的客户端会尝试连接到那个容器
话虽如此,那么这条线
consumer = KafkaConsumer('test', bootstrap_servers='localhost:9092')
您将 Python 容器指向自身,而不是kafka
容器。
它应该改为kafka:9092
就我而言,我想从本地运行的外部 python 客户端(作为生产者)访问 Kafka 容器,这里是对我有用的容器和 python 代码的组合(平台 MAC OS 和 docker 版本 2.4.0):
动物园管理员容器:
docker run -d \
-p 2181:2181 \
--name=zookeeper \
-e ZOOKEEPER_CLIENT_PORT=2181 \
confluentinc/cp-zookeeper:5.2.3
卡夫卡容器:
docker run -d \
-p 29092:29092 \
-p 9092:9092 \
--name=kafka \
-e KAFKA_ZOOKEEPER_CONNECT=host.docker.internal:2181 \
-e KAFKA_LISTENER_SECURITY_PROTOCOL_MAP=BROKER:PLAINTEXT,PLAINTEXT:PLAINTEXT \
-e KAFKA_ADVERTISED_LISTENERS=PLAINTEXT://kafka:29092,BROKER://localhost:9092 \
-e KAFKA_INTER_BROKER_LISTENER_NAME=BROKER \
-e KAFKA_BROKER_ID=1 \
-e KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR=1 \
-e KAFKA_CREATE_TOPICS="test:1:1" \
confluentinc/cp-enterprise-kafka:5.2.3
蟒客户端:
from kafka import KafkaProducer
import json
producer = KafkaProducer(bootstrap_servers=['localhost:29092'],
value_serializer=lambda v: json.dumps(v).encode('utf-8'),
security_protocol='PLAINTEXT')
acc_ini = 523416
print("Sending message")
producer.send('test', {'model_id': '1','acc':str(acc_ini), 'content':'test'})
producer.flush()
在我的本地设置中,我遇到了同样的问题,所有容器在 docker 内都工作正常,但连接器无法连接到 Kafka。
我在docker-compose.yml
的 Kafka 配置:
broker:
image: confluentinc/cp-server:7.0.1
hostname: broker
container_name: broker
depends_on:
- zookeeper
ports:
- "29092:29092"
- "9092:9092"
environment:
KAFKA_BROKER_ID: 1
KAFKA_ZOOKEEPER_CONNECT: zookeeper:2181
KAFKA_LISTENERS: INTERNAL://:29092,EXTERNAL://:9092
KAFKA_ADVERTISED_LISTENERS: INTERNAL://:29092,EXTERNAL://:9092
KAFKA_LISTENER_SECURITY_PROTOCOL_MAP: INTERNAL:PLAINTEXT,EXTERNAL:PLAINTEXT
KAFKA_INTER_BROKER_LISTENER_NAME: INTERNAL
根据谷歌的回复,我尝试了localhost:port
、 127.0.0.1:port
和0.0.0.0:port
作为连接器配置中的 URL,但没有任何效果。
最终,我不得不传递本地系统的实际 IP 地址,并且它起作用了。 我在 Windows 10 上使用 Docker。
ActiveMQ 连接器配置文件:
{
"connector.class": "io.confluent.connect.activemq.ActiveMQSourceConnector",
"activemq.url": "tcp://<my-system-ip>:61616", <-- my system's IP address
"max.poll.duration": "60000",
"tasks.max": "1",
"batch.size": "1",
"name": "activemq-jms-connector",
"jms.destination.name": "jms-test",
"kafka.topic": "topic-1",
"activemq.password": "password",
"jms.destination.type": "topic",
"use.permissive.schema": "false",
"activemq.username": "username"
}
我希望这能帮助任何在 Windows 和 Docker 上苦苦挣扎的Kafka-connect
设置。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.