连接到在 Docker 中运行的 Kafka免責聲明答tl;博士相关问题附录

我在本地计算机上设置了一个单节点 Kafka Docker 容器,如 Confluent 文档(步骤 2-3)中所述。

此外,我还公开了 Zookeeper 的端口 2181 和 Kafka 的端口 9092,以便我能够从本地计算机上运行的客户端连接到它们:

$ docker run -d \
    -p 2181:2181 \
    --net=confluent \
    --name=zookeeper \
    -e ZOOKEEPER_CLIENT_PORT=2181 \
    confluentinc/cp-zookeeper:4.1.0

$ docker run -d \
    --net=confluent \
    --name=kafka \
    -p 9092:9092 \
    -e KAFKA_ZOOKEEPER_CONNECT=zookeeper:2181 \
    -e KAFKA_ADVERTISED_LISTENERS=PLAINTEXT://kafka:9092 \
    -e KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR=1 \
    confluentinc/cp-kafka:4.1.0

问题:当我尝试从主机连接到Kafka时,连接失败,因为它.can't resolve address: kafka:9092

这是我的Java代码:

Properties props = new Properties();
props.put("bootstrap.servers", "localhost:9092");
props.put("client.id", "KafkaExampleProducer");
props.put("key.serializer", LongSerializer.class.getName());
props.put("value.serializer", StringSerializer.class.getName());
KafkaProducer<Long, String> producer = new KafkaProducer<>(props);
ProducerRecord<Long, String> record = new ProducerRecord<>("foo", 1L, "Test 1");
producer.send(record).get();
producer.flush();

例外情况:

java.io.IOException: Can't resolve address: kafka:9092
    at org.apache.kafka.common.network.Selector.doConnect(Selector.java:235) ~[kafka-clients-2.0.0.jar:na]
    at org.apache.kafka.common.network.Selector.connect(Selector.java:214) ~[kafka-clients-2.0.0.jar:na]
    at org.apache.kafka.clients.NetworkClient.initiateConnect(NetworkClient.java:864) [kafka-clients-2.0.0.jar:na]
    at org.apache.kafka.clients.NetworkClient.ready(NetworkClient.java:265) [kafka-clients-2.0.0.jar:na]
    at org.apache.kafka.clients.producer.internals.Sender.sendProducerData(Sender.java:266) [kafka-clients-2.0.0.jar:na]
    at org.apache.kafka.clients.producer.internals.Sender.run(Sender.java:238) [kafka-clients-2.0.0.jar:na]
    at org.apache.kafka.clients.producer.internals.Sender.run(Sender.java:176) [kafka-clients-2.0.0.jar:na]
    at java.lang.Thread.run(Thread.java:748) [na:1.8.0_144]
Caused by: java.nio.channels.UnresolvedAddressException: null
    at sun.nio.ch.Net.checkAddress(Net.java:101) ~[na:1.8.0_144]
    at sun.nio.ch.SocketChannelImpl.connect(SocketChannelImpl.java:622) ~[na:1.8.0_144]
    at org.apache.kafka.common.network.Selector.doConnect(Selector.java:233) ~[kafka-clients-2.0.0.jar:na]
    ... 7 common frames omitted

问题:如何连接到在 Docker 中运行的 Kafka?我的代码是从主机运行的,而不是从 Docker 运行的。

注意:我知道我理论上可以玩DNS设置,但这是一种解决方法 - 它不应该是那样的。/etc/hosts

这里也有类似的问题,但它是基于图像的。我使用不一样的基于图像。ches/kafkaconfluentinc


答案 1

免責聲明

tl;dr - 从容器转发到主机的简单端口将不起作用,并且不应修改任何主机文件。您要连接到哪个确切的 IP/主机名 + 端口?确保该值设置为在代理上。确保地址和作为 的一部分列出的服务器实际上是可解析的(IP/主机名,用于检查端口...advertised.listenersbootstrap.serverspingnetcat

要验证主机上的端口是否正确映射,请确保显示 kafka 容器是从 映射而来的。如果尝试从 Docker 网络外部运行客户端,则端口必须匹配。docker ps0.0.0.0:<host_port> -> <advertised_listener_port>/tcp


下面的答案使用 Docker 映像来解决所提出的问题,而不是 。更具体地说,尽管后者是最受欢迎的Kafka docker映像之一,但仍未得到很好的维护。confluentincwurstmeister/kafka

以下部分尝试聚合使用其他映像所需的所有详细信息。对于其他常用的Kafka图像,它都是在容器中运行的相同的Apache Kafka
您只需要依赖于它的配置方式哪些变量使它如此。

wurstmeister/kafka

请参阅有关侦听器配置的自述部分,另请参阅其连接性 wiki

bitnami/kafka

如果你想要一个小容器,试试这些。这些图像比Confluent图像小得多,并且维护得比.请参阅其自述文件以了解侦听器配置。wurstmeister

debezium/kafka

这里提到了它的文档。

: 已弃用播发的主机和端口设置。广告听众涵盖了两者。与 Confluent 容器类似,Debezium 可以使用前缀代理设置来更新其属性。KAFKA_

别人

spotify/kafka已弃用且已过时。
或者非常适合一体化解决方案,但如果你想要Kafka
你自己的 -为什么?这些其他人有什么不完整吗?从拉取请求开始,而不是从头开始。fast-data-devlensesio/boxDockerfile

有关补充阅读,功能齐全和网络图,请参阅此博客 by @rmoffdocker-compose

Confluent 快速入门 (Docker) 文档假定所有生成和使用请求都将位于 Docker 网络中。

您可以通过在自己的容器中运行 Kafka 客户端代码来解决连接到的问题,因为该容器使用 Docker 网桥,但除此之外,您需要添加更多环境变量以在外部公开容器,同时仍让它在 Docker 网络中工作。kafka:9092

首先添加一个协议映射,它将侦听器协议映射到 Kafka 协议PLAINTEXT_HOST:PLAINTEXT

键:
值:KAFKA_LISTENER_SECURITY_PROTOCOL_MAPPLAINTEXT:PLAINTEXT,PLAINTEXT_HOST:PLAINTEXT

然后在不同的端口上设置两个通告侦听器。(此处指的是 docker 容器名称;它也可能被命名为 ,因此请仔细检查您的服务 + 主机名)。请注意,协议与上述映射的右侧值匹配kafkabroker

键:
值:KAFKA_ADVERTISED_LISTENERSPLAINTEXT://kafka:9092,PLAINTEXT_HOST://localhost:29092

运行容器时,为主机端口映射添加。-p 29092:29092


tl;博士

(使用上述设置)

如果某些内容仍然不起作用,则可以将其设置为包括两个选项与播发设置和 Docker 转发端口匹配的位置KAFKA_LISTENERS<PROTOCOL>://0.0.0.0:<PORT>

客户端位于同一台计算机上,而不是容器中

播发本地主机和关联的端口将允许你像预期的那样在容器外部进行连接。

换句话说,在 Docker 网络之外运行任何 Kafka 客户端(包括您可能已在本地安装的 CLI 工具)时,用于引导服务器和 Zookeeper(需要 Docker 端口转发)localhost:29092localhost:2181

另一台计算机上的客户端

如果尝试从外部服务器进行连接,则需要公布主机的外部主机名/ip以及/代替本地主机
简单地使用端口转发播发本地主机将不起作用,因为 Kafka 协议仍将继续通告您配置的侦听器。

如果不在同一本地网络中,此设置需要 Docker 端口转发路由器端口转发(以及防火墙/安全组更改),例如,您的容器在云中运行,并且您希望从本地计算机与它进行交互。

容器中的客户端,位于同一主机上

这是最不容易出错的配置;您可以直接使用 DNS 服务名称。

在 Docker 网络中运行应用时,对引导服务器和 Zookeeper 使用(请参阅上面公布的侦听器配置),就像任何其他 Docker 服务通信一样(不需要任何端口转发)kafka:9092PLAINTEXTzookeeper:2181

如果使用单独的命令或撰写文件,则需要手动定义共享文件docker runnetwork

请参阅完整 Confluent 堆栈的示例 Compose 文件,或查看单个代理的更多最小堆栈。

相关问题

从 Docker 连接到主机上的 Kafka (ksqlDB)

附录

对于任何对 Kubernetes 部署感兴趣的人:


答案 2

当您第一次连接到kafka节点时,它将为您提供所有kafka节点和要连接的URL。然后,您的应用程序将尝试直接连接到每个 kafka。

问题总是卡夫卡会给你什么网址?这就是为什么卡夫卡将使用它来告诉世界如何访问它。KAFKA_ADVERTISED_LISTENERS

现在,对于您的用例,需要考虑多个小问题:

假设您设置plaintext://kafka:9092

  • 如果您的 docker 组合中有一个使用 kafka 的应用程序,这是可以的。此应用程序将从 kafka 获取可通过 docker 网络解析的 URL。kafka
  • 如果您尝试从主系统或来自不在同一 Docker 网络中的另一个容器进行连接,这将失败,因为无法解析该名称。kafka

==>要解决此问题,您需要像服务发现服务器一样拥有特定的DNS服务器,但对于小东西来说,这是个大麻烦。或者,在每个容器中手动设置容器 IP 的名称kafka/etc/hosts

如果设置plaintext://localhost:9092

  • 如果您有端口映射,这在您的系统上是可以的( 启动 kafka 时 -p 9092:9092)
  • 如果您从容器(是否相同的 docker 网络)上的应用程序进行测试,这将失败(localhost 是容器本身而不是 kafka)

==> 如果您有此内容并希望在另一个容器中使用kafka客户端,则解决此问题的一种方法是共享两个容器的网络(同一IP)

最后一个选项:在名称中设置一个IP:( kafka广告的url不能是0.0.0.0,如文档 https://kafka.apache.org/documentation/#brokerconfigs_advertised.listenersplaintext://x.y.z.a:9092 )

这对每个人都没问题...但是你怎么能得到x.y.z.a这个名字呢?

唯一的方法是在启动容器时对此 ip 进行硬编码:。请注意,您需要将 ip 调整为子网中的一个有效 IP。docker run .... --net confluent --ip 10.x.y.z ...confluent


推荐