我在本地机器上设置了一个单节点 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/kafka
图像。我使用 confluentinc
基于图像,这是不一样的。
原文由 Sasha Shpota 发布,翻译遵循 CC BY-SA 4.0 许可协议
免责声明
如果您对使用简单的端口映射感兴趣,请尝试寻找支持 Kafka“KRaft”模式的容器(例如
bitnami/kafka
图像)以下部分尝试汇总使用另一个图像所需的所有详细信息。对于其他常用的 Kafka 图像, 它们都是在容器中运行的相同 Apache Kafka 。
你只是依赖于 _它是如何配置的_。 哪些变量 使它如此。
有关补充阅读、 功能齐全的
docker-compose
和网络图,请参阅 @rmoff 的博客回答
Confluent 快速入门 (Docker) 文档 假设所有生产和消费请求都在 Docker 网络中。
您可以通过在其自己的容器中运行 Kafka 客户端代码来解决连接到
kafka:9092
的问题,因为它使用 Docker 网桥,但否则您将需要添加更多环境变量以在外部公开容器,同时仍然让它在 Docker 网络中工作。首先添加
PLAINTEXT_HOST:PLAINTEXT
的协议映射,将监听器协议映射到Kafka协议密钥:
KAFKA_LISTENER_SECURITY_PROTOCOL_MAP
值:
PLAINTEXT:PLAINTEXT,PLAINTEXT_HOST:PLAINTEXT
然后在不同的端口上设置两个通告的监听器。 (
kafka
这里指的是docker容器名称;它也可能被命名为broker
,所以仔细检查你的服务+主机名)。密钥:
KAFKA_ADVERTISED_LISTENERS
值:
PLAINTEXT://kafka:9092,PLAINTEXT_HOST://localhost:29092
请注意,此处的协议与上面协议映射设置的左侧值匹配
运行容器时,为主机端口映射添加
-p 29092:29092
,并发布PLAINTEXT_HOST
监听器。tl;博士
( 使用上述设置)
如果 仍然 无法正常工作,
KAFKA_LISTENERS
可以设置为包括<PROTOCOL>://0.0.0.0:<PORT>
其中两个选项都匹配广告设置和 Docker 转发端口客户端在同一台机器上,而不是在容器中
正如您所期望的那样,广告 localhost 和关联的端口将使您可以连接到容器外部。
换句话说,当在 Docker 网络 之外 运行任何 Kafka 客户端(包括您可能已在本地安装的 CLI 工具)时,使用
localhost:29092
作为引导服务器,使用 ---localhost:2181
作为 Zookeeper(需要 Docker 端口转发) )另一台机器上的客户端
如果尝试从外部服务器连接,您需要公布主机的外部主机名/IP 以及/代替 localhost 。
简单地通过端口转发来通告本地主机是行不通的,因为 Kafka 协议仍会继续通告您配置的侦听器。
如果不在同一个本地网络中,此设置需要 Docker 端口转发 和 路由器端口转发(以及防火墙/安全组更改),例如,您的容器在云中运行并且您希望从本地计算机与其交互。
同一主机上容器中的客户端(或其他代理)
这是最不容易出错的配置;您可以直接使用 DNS 服务名称。
在 Docker 网络中 运行应用程序时,使用
kafka:9092
(参见上面的广告PLAINTEXT
侦听器配置)用于引导服务器和zookeeper:2181
for 76a,就像其他 Docker 一样服务通信(不需要任何端口转发)如果您使用单独的
docker run
命令或 Compose 文件,您需要手动定义一个共享的network
请参阅示例 Compose 文件以获取完整的 Confluent 堆栈 或 更小 的单个代理。
如果使用多个代理,那么他们需要使用唯一的主机名 + 广告侦听器。 见例子
相关问题
从 Docker (ksqlDB) 连接到主机上的 Kafka
附录
对于任何对 Kubernetes 部署感兴趣的人: