java - 连接到在 Docker 中运行的 Kafka

标签 java docker apache-kafka confluent-platform

我在本地机器上设置了一个单节点 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 of bootstrap.servers are actually resolvable (ping an IP/hostname, use netcat 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, not wurstmeister/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 or lensesio/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 stackmore 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/

相关文章:

elasticsearch - Confluentinc连接器。一个elasticsearch索引中的多个连接器。以特定的文档类型发布

docker - 许可证主题的 Kafka Connect 复制因子

java - 如何让Apache Camel中的事件驱动消费者删除消费过的消息?

java - 删除sql不删除

java - 如何解决GETJson口是心非异常?

docker - 如何在Windows上创建多节点的Kubernetes集群

Docker for Windows Kubernetes pod 在创建新部署后获取 ImagePullBackOff

java - Lucene:字段的相似性(BM25)

javascript - Docker-compose 不会将本地文件夹中的测试文件复制到 Container 中,而是复制其他所有内容

apache-kafka - 有没有办法保证kafka topic中不插入重复记录?