Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/391.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/docker/10.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 连接到Docker中运行的卡夫卡_Java_Docker_Apache Kafka_Confluent Platform - Fatal编程技术网

Java 连接到Docker中运行的卡夫卡

Java 连接到Docker中运行的卡夫卡,java,docker,apache-kafka,confluent-platform,Java,Docker,Apache Kafka,Confluent Platform,我在本地机器上设置了一个单节点Kafka Docker容器,如(步骤2-3)所述 此外,我还公开了Zookeeper的端口2181和Kafka的端口9092,以便能够从本地计算机上运行的客户端连接到它们: $ docker run -d \ -p 2181:2181 \ --net=confluent \ --name=zookeeper \ -e ZOOKEEPER_CLIENT_PORT=2181 \ confluentinc/cp-zookeeper

我在本地机器上设置了一个单节点Kafka Docker容器,如(步骤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
问题:当我尝试从主机连接到卡夫卡时,连接失败,因为它
无法解析地址:卡夫卡: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();
问题:如何连接到Docker中运行的卡夫卡?我的代码是从主机运行的,不是Docker

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


也有类似的问题,但它是基于
ches/kafka
image。我使用了不同的基于
confluentinc
的图像。

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

问题总是卡夫卡会给你什么作为url?这就是为什么会有卡夫卡的听众,卡夫卡将用它告诉全世界如何访问它

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

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

  • 如果docker compose中有一个使用kafka的应用程序,这是可以的。此应用程序将从卡夫卡获得可通过docker网络解析的带有
    kafka
    的URL
  • 如果您尝试从主系统或不在同一docker网络中的其他容器进行连接,这将失败,因为无法解析
    kafka
    名称
==>要解决这个问题,您需要有一个特定的DNS服务器,比如服务发现服务器,但这对于小东西来说是个大麻烦。或者手动将
kafka
名称设置为每个
/etc/hosts

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

  • 如果您有端口映射(-p 9092:9092,当启动kafka时),这在您的系统上是正常的
  • 如果在容器(是否为同一docker网络)上从应用程序进行测试,则此操作将失败(localhost是容器本身,而不是kafka容器)
==>如果您有此问题,并且希望在另一个容器中使用kafka客户端,解决此问题的一种方法是为两个容器共享网络(相同的ip)

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

这对每个人都是好的。。。但是你怎么能得到x.y.z.a的名字呢

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

免责声明 tl;dr-在一天结束时,都是同样的ApacheKafka在一个容器中运行。您只需要依赖于它的配置方式。哪些变量使其如此


下面使用的是
confluentinc
docker图像,而不是
wurstmeister/kafka
,尽管我还没有尝试过。如果使用该图像

对wurstmeister图像没有任何异议,但它是由社区维护的,不是在自动CI/CD发行版中构建的。。。比特纳米人同样是极简主义者,而且保养得更好。对于
bitnami
Kafka图像

debezium/kafka
上面有文档。 注意:已弃用播发的主机和端口设置。广告中的听众涵盖了这两个方面。与Confluent容器类似,Debezium可以使用
KAFKA\uz
前缀代理设置来更新其属性

spotify/kafka
已被弃用和过时
fastdatadev
对于一个多功能一体的解决方案来说是非常好的,但它过于臃肿

有关补充阅读、功能齐全的docker compose和网络图,请参阅 或

答复 假设所有生产和消费请求都在Docker网络内

您可以通过在使用Docker网桥的自己的容器中运行kafka客户端代码来修复连接到
kafka:9092
的问题,但否则,您将需要添加更多的环境变量,以便在外部公开容器,同时仍使其在Docker网络中工作

首先添加将侦听器协议映射到Kafka协议的
明文\u HOST:PLAINTEXT

密钥:
KAFKA\u侦听器\u安全协议\u映射

值:
明文:明文,明文\u主机:明文

然后在不同端口上设置两个播发侦听器。(
kafka
这里指的是docker容器名称;它也可能被命名为
broker
,因此请仔细检查您的服务+主机名)。请注意,协议与上面映射的右侧值相匹配

键:
KAFKA\u播发的听众

值:
PLAINTEXT://kafka:9092,PLAINTEXT\u HOST://localhost:29092

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

tl;dr(具有上述设置)

客户端在同一台计算机上,而不是在容器中 广告localhost和相关端口将允许您在容器外部进行连接,正如您所期望的那样

换句话说,在Docker网络之外运行任何Kafka客户端时(包括您可能在本地安装的CLI工具),对于引导服务器使用
localhost:29092
,对于Zookeeper使用
localhost:2181
(需要Docker端口转发)

另一台计算机上的客户端 如果试图从外部服务器连接,则需要公布主机的外部主机名/ip以及/代替l
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
@Bean
public ProducerFactory<String, String> producerFactory() {
    Map<String, Object> configProps = new HashMap<>();
    configProps.put(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG, "192.168.8.128:9092");
    configProps.put(ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG, StringSerializer.class);
    configProps.put(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG, StringSerializer.class);
    return new DefaultKafkaProducerFactory<>(configProps);
}

@Bean
public ConsumerFactory<String, String> consumerFactory() {
    Map<String, Object> props = new HashMap<>();
    props.put(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG, "192.168.8.128:9092");
    props.put(ConsumerConfig.GROUP_ID_CONFIG, "group_id");
    props.put(ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG, StringDeserializer.class);
    props.put(ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG, StringDeserializer.class);
    return new DefaultKafkaConsumerFactory<>(props);
}