【问题标题】:Setting up docker-compose ports and host names to work with a kafka-python container [duplicate]设置 docker-compose 端口和主机名以使用 kafka-python 容器 [重复]
【发布时间】:2021-11-13 15:14:03
【问题描述】:

我目前正在学习 Kafka,并且正在努力正确设置我的 docker-compose 配置。我要做的是基于wurstmeister/kafka 图像运行一个代理,然后运行另一个容器,该容器使用kafka-python 运行一个简单的python 脚本。

我一直在关注this 教程,但我怀疑我对端口的处理有点混乱。这是我的 docker-compose.yml:

version: '3'

services:

  zookeeper:
    image: wurstmeister/zookeeper
    ports:
      - "2181:2181"

  kafka:
    image: wurstmeister/kafka
    ports:
      - "9092:9092"
    expose:
      - "9093"
    environment:
      KAFKA_ADVERTISED_HOST_NAME: kafka
      KAFKA_CREATE_TOPICS: "client-pusher:1:1"
      KAFKA_ZOOKEEPER_CONNECT: zookeeper:2181
      KAFKA_ADVERTISED_LISTENERS: INSIDE://kafka:9093,OUTSIDE://localhost:9092
      KAFKA_LISTENERS: INSIDE://0.0.0.0:9093,OUTSIDE://0.0.0.0:9092
      KAFKA_LISTENER_SECURITY_PROTOCOL_MAP: INSIDE:PLAINTEXT,OUTSIDE:PLAINTEXT
      KAFKA_INTER_BROKER_LISTENER_NAME: INSIDE
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
    depends_on:
      - zookeeper

  app-python:
    build: .
    ports:
      - "9093:9093"
    expose:
      - "9093"
      - "9092"
    depends_on:
      - "kafka"

老实说,当谈到 Docker 中的端口时,我有一半时间都不知道自己在做什么。

使用这个Dockerfile

FROM python:3.8

ENV PYTHONUNBUFFERED=1

# set the working directory in the container
WORKDIR /code

# copy the dependencies file to the working directory
COPY requirements.txt .

# install dependencies
RUN pip install -r requirements.txt

# copy the content of the local src directory to the working directory
COPY . .

# command to run on container start
CMD ["python","/code/consumer.py"]

我可以让这个脚本吐出一些日志:

# consumer.py
import json
from datetime import date
from typing import Optional
import time
import logging


from kafka import KafkaConsumer
from pydantic import BaseModel


class Client(BaseModel):
    first_name: str
    email: str
    group_id: Optional[int] = None
    date: date


# consumer = KafkaConsumer(
#     'client-pusher',
#     bootstrap_servers=['kafka:9093'],
#     auto_offset_reset='earliest',
#     enable_auto_commit=True,
#     group_id='my-group-id',
#     value_deserializer=lambda x: json.loads(x.decode('utf-8'))
# )

count = 0
while True:
    # msg_pack = consumer.poll(timeout_ms=500)

    logging.warning(f"Hi there {count}")

    time.sleep(2)
    count += 1

    # for tp, messages in msg_pack.items():
    #     for message in messages:
    #         client = Client(**message.value)
    #         print(client)

但是当注释代码被取消注释时,连接失败。

bootstrap_servers=['kafka:9093'],

行结果

kafka.errors.NoBrokersAvailable: NoBrokersAvailable

我觉得在 docker-compose 文件中正确公开或配置端口并在 python 脚本中正确使用它们和/或正确配置服务名称之间存在一些神奇的组合。但我迷路了。有人可以帮忙吗?

【问题讨论】:

    标签: python docker apache-kafka docker-compose kafka-python


    【解决方案1】:

    TLDR;删除所有 expose 并将 app-python 的端口调整为尚未引用的端口。在您的代码中,使用 localhost:9092 而不是 kafka:9093

    两件事: 一世。对于app-python,您将机器端口 9093 (localhost:9093) 暴露给容器端口 9093 (app-python:9093)。两个容器不能暴露相同的机器端口,所以我建议让你的 kafka 容器端口配置与你的应用程序端口保持舒适的距离(对于 kafka 可能是 9092/9093,对于你的应用程序是 8080)

    二。 Docker compose 将文件中列出的所有容器放在同一个网络中。所以有两种方法可以解决。如果您想在 docker 中运行 kafka 并在 IDE/终端中运行 python 代码,请在 python 脚本中硬编码localhost:9092。即您的代码通过其外部端口映射 (OUTSIDE) 连接到 kafka

    如果你像现在一样运行它,两个容器都在同一个 docker 网络中运行)我建议将环境变量(或你可以传入并在代码中引用的属性)传递给app-python引导服务器<Container name>:<INSIDE PORT> --- kafka:9093

    这是一个使用 Java 的示例,我可以在 docker-compose 内部或外部运行应用程序(rest)。如果在外面,我引用了localhost:9092,但如果在里面,我这样引用:

    version: '3'
    services:
      zookeeper:
        image: wurstmeister/zookeeper
        ports:
          - "2181:2181"
    
      kafka:
        container_name: kafka_broker_1
        image: wurstmeister/kafka
        links:
          - zookeeper
        ports:
          - "9092:9092"
          - "29092:29092"
        depends_on:
          - zookeeper
        environment:
          KAFKA_ADVERTISED_HOSTNAME: kafka
          KAFKA_ADVERTISED_LISTENERS: INSIDE://kafka:29092,OUTSIDE://localhost:9092
          KAFKA_LISTENER_SECURITY_PROTOCOL_MAP: INSIDE:PLAINTEXT,OUTSIDE:PLAINTEXT
          KAFKA_LISTENERS: INSIDE://0.0.0.0:29092,OUTSIDE://0.0.0.0:9092
          KAFKA_INTER_BROKER_LISTENER_NAME: INSIDE
          KAFKA_ZOOKEEPER_CONNECT: zookeeper:2181
        volumes:
          - /var/run/docker.sock:/var/run/docker.sock%
    
      rest:
        image: rest:latest
        container_name: rest
        build:
          context: rest
          dockerfile: Dockerfile
        links:
          - kafka
        environment:
          - SPRING_KAFKA_BOOTSTRAP-SERVERS=kafka:29092
          - SERVER_PORT=8080
        ports:
          - "8080:8080"
        depends_on:
          - kafka
    

    【讨论】:

    • 感谢您的回答,但不幸的是我无法取得任何进展,仍然是同样的问题:(
    • 同样的错误? :'( 我会先尝试验证问题不在 kafka 容器中。仅使用 zookeeper+kafka 映像,运行 docker compose 并查看是否可以使用 CLI 工具(producer/consumer/kafka-topics.sh ) 与设置。如果您可以外部连接,请在 docker 容器之外运行 python 应用程序(使用 localhost/127.0.0.1:9092 用于 python 脚本中的引导服务器)。将有助于消除任何“可能这是问题”的担忧. 我还要注意,如果你使用的是 M1 Macbook,你使用的 docker 镜像还不支持新架构
    • 注意:OP使用Python,所以SPRING_KAFKA_BOOTSTRAP-SERVERS应该改一下
    • @Nerm 感谢您提供额外的上下文。 docker 镜像工作正常,我可以跳进去并在 CLI 上运行生产者和消费者命令没问题。如果我不为 python 应用程序本身使用 Docker 容器,我也可以很好地运行我的 python 应用程序。我运行 Linux,没有 Mac 问题。不必处理 Spring 的东西,我确实会有所帮助!
    • 太棒了!如果你想像我一样通过环境变量传递引导服务器,我建议你看看这个 - link
    【解决方案2】:

    AFAIK expose 仅供参考(请参阅here)。这完全取决于您使用 ports 定义的端口。

    尝试连接到您在ports 中定义的端口(用于内部和外部),即在您的情况下

    bootstrap_servers=['kafka:9092']
    

    并删除所有连接到定义为expose 的端口的情况,例如为KAFKA_LISTENERS

    【讨论】:

    • 是的,我已经尝试过了,尝试了各种组合!仍然没有快乐。
    • @JohnKealy 嗯,很抱歉无法提供帮助。我会把这个留给对使用 docker 和 kafka 有更多了解的人。我只是认为这可能是一个简单的端口映射问题。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-03-01
    • 2017-08-20
    • 1970-01-01
    • 2022-06-15
    相关资源
    最近更新 更多