将消息发布到在docker中运行的Kafka

时间:2016-05-18 03:55:03

标签: docker apache-kafka kafka-producer-api

我在Docker容器中运行Kafka。我使用以下命令启动我的容器

function [] = myFunction(arg)

  % Find the directory of the executing script
  thisDir = fileparts(mfilename('fullpath'));

  % Save arg as a csv on this directory, this will be read by my R script
  tmpDir = strcat(thisDir,'/tmp.csv');
  csvwrite(tmpDir,arg);

  % Specify the command to run
  sysCommand = ['call "' thisDir '/runRscript.bat"'];
  system(sysCommand);

end

我编写了一个简单的程序,我可以将其复制到容器中并执行它,它可以很好地工作。

docker run --rm -p 2181:2181 -p 9092:9092 -p 8081:8081 --env 
ADVERTISED_HOST=\`docker-machine ip \\`docker-machine active\\`` --env 
ADVERTISED_PORT=9092 -v  
/Users/abhishek.srivastava/MyProjects/KafkaTest/target/scala-2.11:/app 
-it --  name kafka spotify/kafka bash

但是如果我从容器外部(从我的mac)运行这个相同的程序。 [我用object KafkaProducerString { def SendStringMessage(msg: String) : Unit = { val inputRecord = new ProducerRecord[String, String]("test", null, msg) val producer: KafkaProducer[String, String] = CreateProducerString val rm = producer.send(inputRecord).get(10, SECONDS) println(s"offset: ${rm.offset()} partition: ${rm.partition()} topic: ${rm.topic()}") producer.close() } private def CreateProducerString: KafkaProducer[String, String] = { val props = new Properties() props.put("bootstrap.servers", "localhost:9092") props.put("key.serializer", "org.apache.kafka.common.serialization.StringSerializer") props.put("value.serializer", "org.apache.kafka.common.serialization.StringSerializer") props.put("batch.size", "0") props.put("client.id", "1") val producer = new KafkaProducer[String, String](props) producer } } ]

的输出替换“localhost”

我收到此错误

docker-machine ip

我的理解是,对于一个kafka生产者来说,我需要打开的唯一端口是2181(zookeeper)和9092(kafka),你可以看到我打开了这些。

但是仍然在容器外部执行时相同的程序超时,但在容器内部(使用localhost)时工作。

编辑::根据以下建议,我尝试了以下

[error] (run-main-0) java.util.concurrent.TimeoutException: Timeout after waiting for 10000 ms.
java.util.concurrent.TimeoutException: Timeout after waiting for 10000 ms.
    at org.apache.kafka.clients.producer.internals.FutureRecordMetadata.get(FutureRecordMetadata.java:50)
    at org.apache.kafka.clients.producer.internals.FutureRecordMetadata.get(FutureRecordMetadata.java:25)
    at com.abhi.KafkaProducerString$.SendStringMessage(KafkaProducerString.scala:23)
    at com.abhi.KafkaMain$$anonfun$main$1.apply$mcVI$sp(KafkaMain.scala:19)
    at scala.collection.immutable.Range.foreach$mVc$sp(Range.scala:160)
    at com.abhi.KafkaMain$.main(KafkaMain.scala:17)
    at com.abhi.KafkaMain.main(KafkaMain.scala)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:606)

docker run --rm -p 127.0.0.1:2181:2181 -p 127.0.0.1:9092:9092 -p 
127.0.0.1:8081:8081 --env ADVERTISED_HOST=`docker-machine ip \`docker-machine 
active\`` --env ADVERTISED_PORT=9092 -v 
/Users/abhishek.srivastava/MyProjects/KafkaTest/target/scala-2.11:/app -it --
name kafka kafka_9.0 bash

但这些并没有解决问题。我得到完全相同的问题

2 个答案:

答案 0 :(得分:0)

您必须将docker容器绑定到本地计算机。这可以通过使用docker run as:

来完成
docker run --rm -p 127.0.0.1:2181:2181 -p 127.0.0.1:9092:9092 -p 127.0.0.1:8081:8081 ....

或者,您可以使用带有绑定IP的docker run:

docker run --rm -p 0.0.0.0:2181:2181 -p 0.0.0.0:9092:9092 -p 0.0.0.0:8081:8081 .....

如果您想在您的网络上使docker容器可路由,您可以使用:

docker run --rm -p <private-IP>:2181:2181 -p <private-IP>:9092:9092 -p <private-IP>:8081:8081 ....

或者最后你可以使用以下方法来控制你的网络接口:

docker run --rm -p 2181:2181 -p 9092:9092 -p 8081:8081 --net host ....

答案 1 :(得分:0)

虽然我自己也面临着类似的问题,但我可以尝试解释这种行为。

在将记录发布到主题之前,Kafka制作人将从Zookeeper中查找分区负责人。 Zookeeper将拥有由Kafka服务器标记的领导者主机条目,该服务器在Docker容器内运行。

由于这个事实,服务器标记的IP将是Docker内部IP,而不是主机IP。这当然不能从客户机上解决,因此超时。

一个可能的解决方案是,将advertised.host.name设置为Docker机器的主机IP。然而,这将引入另一个问题(因为我面临!)

服务器的代理元数据提取现在将开始失败。这是因为现在Zookeeper条目具有主机IP,该主机IP无法从容器内部解析。因此,任何消费者应用程序现在都会开始收到LEADER_NOT_AVAILABLE警告。

这是一种死锁情况,解决方案主要取决于所采用的主机解析策略。我想知道人们会如何建议去这里。

编辑:最后我们使用主机网络[--net = host]并使用节点静态IP来解决问题。