我在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
}
}
]
我收到此错误
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
但这些并没有解决问题。我得到完全相同的问题
答案 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来解决问题。