在dockerized环境中无法从Flask连接到Kafka

时间:2018-11-27 07:24:57

标签: python docker flask apache-kafka connection

我正在尝试构建一个以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

其他观察结果:

  1. 我能够从Flask容器运行ping kafka并从Kafka容器获取数据包。
  2. 当我在本地运行Flask应用时,尝试通过设置BOOTSTRAP_SERVERS = ['localhost:9092']连接到Kafka容器,效果很好。

2 个答案:

答案 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上网络内的连接

当然,将所有已经在网络中运行的容器放入网络中是很奇怪的。但是通过这种方式,可以使用容器的实际名称来命名容器。也许有人可以确切解释它是如何工作的,或者它可以帮助其他人理解问题的核心并正确解决它。