我在本地机器上设置了一个单节点 Kafka Docker 容器,如 the Confluent documentation 中所述。 (步骤 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();
异常(exception):
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
但这是一种解决方法 - 它不应该是那样的。还有类似的问题here , 但是它基于
ches/kafka
图片。我用 confluentinc
基于图像是不一样的。
最佳答案
免责声明
tl;dr - A simple port forward from the container to the host will not work, and no hosts files should be modified. What exact IP/hostname + port do you want to connect to? Make sure that value is set as
advertised.listeners
on the broker. Make sure that address and the servers listed as part ofbootstrap.servers
are actually resolvable (ping
an IP/hostname, usenetcat
to check ports...)
Below gives answers for commonly used Kafka images, but it's all the same Apache Kafka running in a container.
You're just dependent on how it is configured. And which variables make it so.
The below answer uses
confluentinc
docker images to address the question that was asked, notwurstmeister/kafka
. More specifically, the latter images are not well-maintained despite being the one of the most popular Kafka docker image.
以下部分尝试汇总使用另一个图像所需的所有详细信息。
wurstmeister/kafka
Refer their README section on listener configuration, Also read their Connectivity wiki.
bitnami/kafka
If you want a small container, try these. The images are much smaller than the Confluent ones and are much more well maintained than
wurstmeister
. Refer their README for listener configuration.
debezium/kafka
Docs on it are mentioned here.
Note: advertised host and port settings are deprecated. Advertised listeners covers both. Similar to the Confluent containers, Debezium can use
KAFKA_
prefixed broker settings to update its properties.
Others
spotify/kafka
is deprecated and outdated.
fast-data-dev
orlensesio/box
are great for an all in one solution, but are bloated if you only want Kafka
对于补充阅读,功能齐全
docker-compose
和网络图,请参阅 this blog by @rmoff回答
The Confluent quickstart (Docker) document假设所有生产和消费请求都在 Docker 网络中。
您可以解决连接到
kafka:9092
的问题通过在自己的容器中运行 Kafka 客户端代码,因为它使用 Docker 网桥,但否则您需要添加更多环境变量以将容器暴露在外部,同时仍然让它在 Docker 网络中工作。首先添加
PLAINTEXT_HOST:PLAINTEXT
的协议(protocol)映射这会将监听器协议(protocol)映射到 Kafka 协议(protocol)key :
KAFKA_LISTENER_SECURITY_PROTOCOL_MAP
值:PLAINTEXT:PLAINTEXT,PLAINTEXT_HOST:PLAINTEXT
然后在不同的端口上设置两个通告的监听器。 ( kafka
这里指的是 docker 容器名称;它也可能被命名为 broker
,因此请仔细检查您的服务 + 主机名)。注意协议(protocol)匹配上面映射的右侧值key :
KAFKA_ADVERTISED_LISTENERS
值:PLAINTEXT://kafka:9092,PLAINTEXT_HOST://localhost:29092
运行容器时,添加-p 29092:29092
用于主机端口映射tl;博士
(以上设置)
如果还是不行,
KAFKA_LISTENERS
可以设置为包含<PROTOCOL>://0.0.0.0:<PORT>
其中两个选项都匹配广告设置和 Docker 转发的端口客户端在同一台机器上,而不是在容器中
如您所料,广告 localhost 和相关端口将让您连接到容器外部。
换句话说,当运行任何 Kafka 客户端时 外 Docker 网络(包括您可能在本地安装的 CLI 工具),使用
localhost:29092
用于引导服务器和 localhost:2181
对于 Zookeeper(需要 Docker 端口转发)另一台机器上的客户端
如果尝试从外部服务器连接,您需要公布主机的外部主机名/IP 以及/代替本地主机 .
简单地使用端口转发来通告 localhost 是行不通的,因为 Kafka 协议(protocol)仍将继续通告您已配置的监听器。
此设置需要 Docker 端口转发 和 如果不在同一个本地网络中,路由器端口转发(和防火墙/安全组更改),例如,您的容器在云中运行并且您希望从本地计算机与其交互。
容器中的客户端,在同一主机上
这是最不容易出错的配置;您可以直接使用 DNS 服务名称。
运行应用程序时在 Docker 网络中 , 使用
kafka:9092
(参见上面公布的 PLAINTEXT
监听器配置)用于引导服务器和 zookeeper:2181
对于 Zookeeper,就像任何其他 Docker 服务通信一样(不需要任何端口转发)如果您使用单独的
docker run
命令或 Compose 文件,您需要定义一个共享的 network
手动See the example Compose file for the full Confluent stack或 more minimal one对于单个经纪人。
相关问题
Connect to Kafka on host from Docker (ksqlDB)
附录
对于任何对 感兴趣的人Kubernetes 部署:https://operatorhub.io/?keyword=Kafka
关于java - 连接到在 Docker 中运行的 Kafka,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59144778/