[英]Cannot connect to Kafka from Flask in a dockerized environement
我正在嘗試構建一個以 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 容器,它工作正常。更新
正如 cricket_007 所提到的,鑒於您正在使用下面提供的 docker-compose,您應該使用kafka:29092
從另一個容器連接到 Kafka。 所以你的代碼看起來像這樣:
from kafka import KafkaConsumer, KafkaProducer
TOPICS = ['PROFILE_CREATED', 'IMG_RATED']
BOOTSTRAP_SERVERS = ['kafka:29092']
consumer = KafkaConsumer(TOPICS, bootstrap_servers=BOOTSTRAP_SERVERS)
結束更新
我建議您使用Confluent Inc的 Kafka 圖像,它們有各種使用 docker-compose 的示例設置,可以隨時使用,並且它們總是在更新它們。
試試這個:
---
version: '2'
services:
zookeeper:
image: confluentinc/cp-zookeeper:latest
environment:
ZOOKEEPER_CLIENT_PORT: 2181
ZOOKEEPER_TICK_TIME: 2000
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
flaskapp:
build: ./flask-app
container_name: flask_dev
ports:
- '9000:5000'
volumes:
- ./flask-app:/app
我使用了這個docker-compose.yml並在頂部添加了您的服務請注意:
這里使用的配置暴露端口9092,用於向代理即那些來自搬運工網絡之外的外部連接。 這可能來自運行 docker 的主機,或者如果您有更復雜的設置,則可能來自更遠的地方。 如果后者為真,則需要將 KAFKA_ADVERTISED_LISTENERS 中的值“localhost”更改為可從這些遠程客戶端解析到 docker 主機的值
確保您查看其他示例,這可能對您有用,尤其是在遷移到生產環境時: https : //github.com/confluentinc/cp-docker-images/tree/5.0.1-post/examples
也值得檢查:
看來您需要指定 api_version 以避免此錯誤。 有關更多詳細信息,請查看此處。
該庫的 1.3.5 版本(pypy 上的最新版本)僅列出了 0.8.0 到 0.10.1 的某些 API 版本。 因此,除非您明確指定 api_version 為 (0, 10, 1),否則客戶端庫嘗試發現版本將導致 NoBrokersAvailable 錯誤。
producer = KafkaProducer(
bootstrap_servers=URL,
client_id=CLIENT_ID,
value_serializer=JsonSerializer.serialize,
api_version=(0, 10, 1)
)
這應該可以工作,有趣的是,設置 api_version 是根據以下內容意外修復問題:
當您設置 api_version 時,客戶端將不會嘗試探查代理以獲取版本信息。 因此,失敗的是探測操作。 版本探測連接和一般連接之間的一大區別是,前者僅嘗試在每個連接(每個代理)上的單個接口上進行連接,而后者——一般操作——將不斷循環所有接口,直到連接成功。 #1411 通過切換版本探測邏輯來嘗試在所有找到的接口上建立連接來解決此問題。
實際問題描述為here
我設法在所有服務之間使用名為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
上容器外部的連接kafka:29092
上的網絡連接kafka:29092
當然,把已經在一個網絡中運行的所有容器放在一個網絡中是很奇怪的。 但是通過這種方式,容器可以通過它們的實際名稱來命名。 也許有人可以確切地解釋這是如何工作的,或者它可以幫助其他人理解問題的核心並正確解決它。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.