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

Sas*_*ota 5 java apache-kafka docker confluent

我在本地计算机上使用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
Run Code Online (Sandbox Code Playgroud)

问题:当我尝试从主机连接到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<Long, String> producer = new KafkaProducer<>(props);
ProducerRecord<Long, String> record = new ProducerRecord<>("foo", 1L, "Test 1");
producer.send(record).get();
producer.flush();
Run Code Online (Sandbox Code Playgroud)

例外:

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
Run Code Online (Sandbox Code Playgroud)

问题:如何从主机连接到Docker中运行的kafka?

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

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

cri*_*007 11

免责声明:以下使用confluentincdocker镜像,不是wurstmeister/kafka,虽然有类似的配置,我还没试过.

我尝试了debezium/kafkaKafka图像,并使用这些设置

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

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

首先添加协议映射bitnami,将侦听器协议映射到Kafka协议

PLAINTEXT_HOST:PLAINTEXT

然后在不同的端口上设置两个播发的侦听器.(-e KAFKA_LISTENER_SECURITY_PROTOCOL_MAP=PLAINTEXT:PLAINTEXT,PLAINTEXT_HOST:PLAINTEXT这里指的是docker容器名称).请注意,协议与上面映射的右侧值匹配

kafka:9092

运行容器时,添加-e KAFKA_ADVERTISED_LISTENERS=PLAINTEXT://kafka:9092,PLAINTEXT_HOST://localhost:29092主机端口映射

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

在Docker网络中运行应用程序,请使用localhost:29092

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

  • @Maria 我想我已经回答了 3 次了?是的,您可以,但前提是您已更改为“PLAINTEXT_HOST://localhost:9092”,与我的答案相比 (3认同)
  • 但如果我只想使用 9092 怎么办?我的意思是外面的9092,而不是29092 (2认同)

war*_*gre 5

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

问题始终是kafka将为您提供url吗?这就是为什么KAFKA_ADVERTISED_LISTENERSkafka将使用告诉世界如何访问它的原因。

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

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

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

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

如果您设定 plaintext://localhost:9092

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

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

最后一个选择:在名称中设置IP: plaintext://x.y.z.a:9092

每个人都可以...但是如何获得xyza名称?

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