![](/img/trans.png)
[英]Accessing Kafka installed on host from Java producer running in Docker
[英]Kafka: events published from the host machine are not consumed by the application running in Docker
我正在为应用程序编写端到端测试。 我启动了一个应用程序实例、一个 Kafka 实例和一个 Zookeeper(全部 Docker 化),然后与应用程序 API 交互以测试其功能。 我需要在此应用程序中测试事件使用者的功能。 我从我的测试中发布事件,预计应用程序会处理它们。
问题:如果我在本地(而不是在 Docker 中)运行应用程序并运行会产生事件的测试,应用程序代码中的使用者会正确处理事件。 在这种情况下,消费者和测试将bootstrapServers
设置为localhost:9092
。 但是,如果应用程序作为 Dockerized 实例运行,则它看不到事件。 在这种情况下, bootstrapServers
在应用bootstrapServers
中设置为kafka:9092
,在测试中设置为localhost:9092
,其中kafka
是 Docker 容器名称。 kafka
容器将其9092
端口暴露给主机,以便可以从 Docker 容器内部和主机(运行我的测试)访问相同的 Kafka 实例。
代码中的唯一区别是localhost
与kafka
设置为引导服务器。 在这两种情况下,消费者和生产者都成功启动; 事件发布没有错误。 只是在一种情况下,消费者没有收到事件。
问题:如何让 Dockerized 消费者看到从主机发布的事件?
注意:我有一个正确配置的 Docker 网络,其中包括应用程序实例、Zookeeper 和 Kafka。 他们都“看到”了对方。 kafka
和zookeeper
的对应端口暴露给宿主机。 卡夫卡端口: 0.0.0.0:9092->9092/tcp
。 Zookeeper 端口: 22/tcp, 2888/tcp, 3888/tcp, 0.0.0.0:2181->2181/tcp
。
我正在使用wurstmeister/kafka和wurstmeister/zookeeper Docker 映像(我无法替换它们)。
任何想法/想法表示赞赏。 你会如何调试它?
更新:问题在于KAFKA_ADVERTISED_LISTENERS
和KAFKA_LISTENERS
变量设置为不同的端口以进行内部和外部通信。 解决方案是在应用程序代码中在 Docker 容器内运行时使用正确的端口。
这类问题通常与 Kafka 处理代理地址的方式有关。
当您启动 Kafka 代理时,它会将自己绑定在0.0.0.0:9092
并使用地址<hostname>:9092
在 Zookeeper 上注册自己。 当您与客户端连接时,将联系 Zookeeper 以获取特定代理的地址。
这意味着当您启动 Kafka 容器时,您会遇到如下情况:
现在,如果您将客户端从 kafkanet 网络内的容器连接到您的 Kafka,您从 Zookeeper 返回的地址是kafka:9092
,该地址可通过kafkanet
网络解析。
但是,如果您从 docker 外部连接到 Kafka(即使用由localhost:9092
映射的localhost:9092
端点),您仍然会返回无法解析的kafka:9092
地址。
为了解决这个问题,你可以指定advertised.host.name
和advertised.port
在这样的代理配置,该地址是由所有的客户端解析(见文档)。
什么是通常做的是一套advertised.host.name
为<container-name>.<network>
(在你的情况类似kafka.kafkanet),以便连接到网络的任何容器能够正确解析卡夫卡的IP经纪人。
但是,在您的情况下,您有一个混合网络配置,因为某些组件位于 docker 内部(因此能够解析 kafkanet 网络),而其他组件位于 docker 外部。 如果它是一个生产系统,我的建议是将设置advertised.host.name
到主机的DNS / IP,总是依靠搬运工端口映射,以达到卡夫卡经纪人。
然而,根据我的理解,你只需要这个设置来测试事情,所以最简单的事情是“欺骗”生活在 docker 之外的系统。 使用上面指定的命名,这意味着只需将127.0.0.1 kafka.kafkanet
行添加到/etc/hosts
(或 Windows 等效项)。
这样,当您居住在 docker 之外的客户端连接到 Kafka 时,应该会发生以下情况:
kafka.kafkanet
kafka.kafkanet
解析为 127.0.0.1编辑
正如在评论中指出,新版本的卡夫卡现在使用的概念, listeners
和advertised.listeners
这是用来代替host.name
和advertised.host.name
被弃用,只有在情况下使用(在上面的人不指定的)。 但是总体思路是一样的:
host.name
:指定 Kafka 代理应该绑定到的主机(与port
一起工作listeners
:指定 Kafka 代理应绑定的所有端点(例如PLAINTEXT://0.0.0.0:9092,SSL://0.0.0.0:9091
)advertised.host.name
:指定代理如何通告给客户端(即客户端应该使用哪个地址来连接到它)avertised.listeners
:指定所有广告端点(例如PLAINTEXT://kafka.example.com:9092,SSL://kafka.example.com:9091
) 在这两种情况下,为了让客户端能够成功地与 Kafka 通信,他们需要能够解析并连接到advertised
主机名和端口。
在这两种情况下,如果未指定,它们将由代理使用运行代理的机器的主机名自动派生。
你一直在引用8092
。 那是故意的吗? Kafka 在9092
运行。 最简单的测试是下载相同版本的 Kafka 并手动运行其kafka-console-consumer
和kafka-console-producer
脚本,看看是否可以从主机上发布订阅。
您是否在 dockerized 应用程序中尝试过“host.docker.internal”?
您可以为您的容器创建一个docker 网络,然后容器将能够解析彼此的主机名并进行通信。
注意:这可用于 docker-compose 以及独立容器
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.