我正在尝试构建一个以Kafka为界面的Flask应用。我使用了Python连接器kafka-python和用于Kafka的Docker映像spotify/kafkaproxy。
下面是docker-compose文件。
version: '3.3'
services:
kafka:
image: spotify/kafkaproxy
container_name: kafka_dev
ports:
- '9092:9092'
- '2181:2181'
environment:
- ADVERTISED_HOST=0.0.0.0
- ADVERTISED_PORT=9092
- CONSUMER_THREADS=1
- TOPICS=PROFILE_CREATED,IMG_RATED
- ZK_CONNECT=kafka7zookeeper:2181/root/path
flaskapp:
build: ./flask-app
container_name: flask_dev
ports:
- '9000:5000'
volumes:
- ./flask-app:/app
depends_on:
- kafka
下面是我用来连接到Kafka的Python代码段。在这里,我使用Kafka容器的别名kafka
进行连接,因为Docker会负责将别名映射到其IP地址。
from kafka import KafkaConsumer, KafkaProducer
TOPICS = ['PROFILE_CREATED', 'IMG_RATED']
BOOTSTRAP_SERVERS = ['kafka:9092']
consumer = KafkaConsumer(TOPICS, bootstrap_servers=BOOTSTRAP_SERVERS)
我遇到了NoBrokersAvailable
错误。由此,我可以理解Flask应用程序找不到Kafka服务器。
Traceback (most recent call last):
File "./app.py", line 11, in <module>
consumer = KafkaConsumer("PROFILE_CREATED", bootstrap_servers=BOOTSTRAP_SERVERS)
File "/usr/local/lib/python3.6/site-packages/kafka/consumer/group.py", line 340, in __init__
self._client = KafkaClient(metrics=self._metrics, **self.config)
File "/usr/local/lib/python3.6/site-packages/kafka/client_async.py", line 219, in __init__
self.config['api_version'] = self.check_version(timeout=check_timeout)
File "/usr/local/lib/python3.6/site-packages/kafka/client_async.py", line 819, in check_version
raise Errors.NoBrokersAvailable()
kafka.errors.NoBrokersAvailable: NoBrokersAvailable
其他观察结果:
ping kafka
并从Kafka容器获取数据包。 BOOTSTRAP_SERVERS = ['localhost:9092']
连接到Kafka容器,效果很好。答案 0 :(得分:0)
更新
如cricket_007所述,假设您使用的是下面提供的docker-compose,则应使用std::async
从另一个容器连接到Kafka。因此您的代码将如下所示:
std::async
END UPDATE
我建议您使用Confluent Inc中的Kafka映像,它们具有使用docker-compose的各种示例设置,可以随时使用,并且始终在更新它们。
尝试一下:
kafka:29092
我使用了此docker-compose.yml,并在顶部添加了您的服务 请注意:
此处使用的配置公开了端口9092用于与代理的外部连接,即来自docker网络外部的连接。这可能来自运行docker的主机,或者如果设置更复杂,则可能来自更远的地方。如果后者为真,则需要将KAFKA_ADVERTISED_LISTENERS中的值'localhost'更改为可从那些远程客户端解析为Docker主机的值
确保您查看其他示例,这可能对您有用,尤其是在进入生产环境时:https://github.com/confluentinc/cp-docker-images/tree/5.0.1-post/examples
还值得检查:
似乎您需要指定api_version以避免此错误。有关更多详细信息,请检查here。
该库的1.3.5版(是pypy的最新版本)仅列出了某些API版本0.8.0至0.10.1。因此,除非您将api_version明确指定为(0,10,1),否则客户端库尝试发现该版本将导致NoBrokersAvailable错误。
from kafka import KafkaConsumer, KafkaProducer
TOPICS = ['PROFILE_CREATED', 'IMG_RATED']
BOOTSTRAP_SERVERS = ['kafka:29092']
consumer = KafkaConsumer(TOPICS, bootstrap_servers=BOOTSTRAP_SERVERS)
这应该可以工作,有趣的是,设置api_version会根据此意外解决问题:
当您设置api_version时,客户端将不会尝试探测代理以获取版本信息。因此,是探针操作失败。版本探测连接和常规连接之间的一个很大区别是,前者仅尝试在每个连接(每个代理)的单个接口上进行连接,而后者(常规操作)将持续循环遍历所有接口,直到建立连接成功。 #1411通过切换版本探测逻辑以尝试在所有找到的接口上建立连接来解决此问题。
描述了实际问题here
答案 1 :(得分:0)
我设法在所有服务之间使用名为Require all granted
的{{3}}来使它正常运行。
stream_net
# for local development
version: "3.7"
services:
zookeeper:
image: confluentinc/cp-zookeeper:latest
environment:
ZOOKEEPER_CLIENT_PORT: 2181
ZOOKEEPER_TICK_TIME: 2000
networks:
- stream_net
kafka:
image: confluentinc/cp-kafka:latest
depends_on:
- zookeeper
ports:
- 9092:9092
environment:
KAFKA_BROKER_ID: 1
KAFKA_ZOOKEEPER_CONNECT: zookeeper:2181
KAFKA_ADVERTISED_LISTENERS: PLAINTEXT://kafka:29092,PLAINTEXT_HOST://localhost:9092
KAFKA_LISTENER_SECURITY_PROTOCOL_MAP: PLAINTEXT:PLAINTEXT,PLAINTEXT_HOST:PLAINTEXT
KAFKA_INTER_BROKER_LISTENER_NAME: PLAINTEXT
KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR: 1
networks:
- stream_net
flaskapp:
build: ./flask-app
container_name: flask_dev
ports:
- "9000:5000"
volumes:
- ./flask-app:/app
networks:
- stream_net
depends_on:
- kafka
networks:
stream_net:
上的容器外部进行连接localhost:9092
上网络内的连接当然,将所有已经在网络中运行的容器放入网络中是很奇怪的。但是通过这种方式,可以使用容器的实际名称来命名容器。也许有人可以确切解释它是如何工作的,或者它可以帮助其他人理解问题的核心并正确解决它。