从本地计算机连接到Docker中运行的Kafka

我在本地计算机上使用docker设置单节点基本Kafka部署,如Confluent Kafka文档中所述 (步骤2-3)。

另外,我还暴露了zookeeper的端口2181和kafka的端口9092,这样我就能从本地机器上运行的java客户端连接到它们:

$ 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时,连接失败,因为它无法解析地址: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 producer = new KafkaProducer(props); ProducerRecord 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?

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

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

免责声明 :以下使用confluentinc wurstmeister/kafa图片,而不是wurstmeister/kafa ,虽然有类似的配置 ,我还没试过。 也是Docker Compose中的这一行 。

Confluent快速入门文档假定所有生产和使用请求都在Docker网络中。

您可以通过在自己的容器中运行Kafka客户端代码来解决问题,但除此之外,您还需要添加一些环境变量以便在外部公开容器,同时仍然可以在Docker网络中运行它。

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

-e KAFKA_LISTENER_SECURITY_PROTOCOL_MAP=PLAINTEXT:PLAINTEXT,PLAINTEXT_HOST:PLAINTEXT

然后在不同的端口上设置两个通告的侦听器。 ( kafka:9092这里指的是docker容器名称)。 请注意,协议与上面映射的右侧值匹配

-e KAFKA_ADVERTISED_LISTENERS=PLAINTEXT://kafka:9092,PLAINTEXT_HOST://localhost:29092

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

在Docker网络外部运行任何Kafka客户端时,请使用localhost:29092

在Docker网络中运行应用程序 ,请使用kafka:9092

请参阅完整Confluent堆栈的示例撰写文件

当您第一次连接到kafka节点时,它将返回所有kafka节点和url连接位置。 然后您的应用程序将尝试直接连接到每个kafka。

问题总是kafka会给你什么作为url? 这就是为什么kafka将使用KAFKA_ADVERTISED_LISTENERS告诉全世界如何访问它。

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

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

  • 如果您的docker compos中有一个使用kafka的应用程序,那就没问题。 此应用程序将从kafka获取可通过docker网络解析的kafka URL。
  • 如果您尝试从主系统或不在同一个docker网络中的另一个容器进行连接,则会失败,因为无法解析kafka名称。

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

如果设置plaintext://localhost:9092

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

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

最后一个选项:在名称中设置IP: plaintext://xyza:9092

这对每个人都没问题……但是你怎么能得到xyza这个名字?

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