在 wsl 中用 docker-compose 搭建了一台 zookeeper + 三台 broker 的 kafka 集群,使用的镜像是 bitnami/kafka,在按照镜像文档运行容器后,发现运行在宿主机里的客户端程序无法正确的推送/消费消息,研究后发现镜像文档只适用于客户端程序和 kafka 集群同属于一个 docker 网段,外部访问还需要一些额外的配置,过程中出现过以下几个主要的错误:

  • dial tcp: lookup 333be5d4e335 on 172.30.96.1:53: no such host
  • kafka: client has run out of available brokers to talk to: dial tcp 127.0.0.1:19092: connect: connection refused
  • [Controller id=1, targetBrokerId=3] Client requested connection close from node 3 (org.apache.kafka.clients.NetworkClient)

这里先贴一个可以用的 docker-compose.yml 配置,后面对其中的关键配置做一个解释,最后再解释出现上面错误的原因,文件最后的 kafka-ui 是一个可视化管理界面,可以不要

version: "3"

services:
zookeeper:
container_name: kafka_zookeeper
image: bitnami/zookeeper
user: root
ports:
- "2181:2181"
environment:
- ALLOW_ANONYMOUS_LOGIN=yes
volumes:
- ./zookeeper:/bitnami/zookeeper
broker1:
container_name: kafka_broker1
image: bitnami/kafka
user: root
ports:
- "19092:9092"
environment:
- KAFKA_CFG_ZOOKEEPER_CONNECT=zookeeper:2181
- ALLOW_PLAINTEXT_LISTENER=yes
- KAFKA_BROKER_ID=1
- KAFKA_LISTENERS=INTERNAL://0.0.0.0:9000,EXTERNAL://0.0.0.0:9092
- KAFKA_ADVERTISED_LISTENERS=INTERNAL://broker1:9000,EXTERNAL://localhost:19092
- KAFKA_LISTENER_SECURITY_PROTOCOL_MAP=INTERNAL:PLAINTEXT,EXTERNAL:PLAINTEXT
- KAFKA_INTER_BROKER_LISTENER_NAME=INTERNAL
volumes:
- ./broker1:/bitnami/kafka
depends_on:
- zookeeper
broker2:
container_name: kafka_broker2
image: bitnami/kafka
user: root
ports:
- "29092:9092"
environment:
- KAFKA_CFG_ZOOKEEPER_CONNECT=zookeeper:2181
- ALLOW_PLAINTEXT_LISTENER=yes
- KAFKA_BROKER_ID=2
- KAFKA_LISTENERS=INTERNAL://0.0.0.0:9000,EXTERNAL://0.0.0.0:9092
- KAFKA_ADVERTISED_LISTENERS=INTERNAL://broker2:9000,EXTERNAL://localhost:29092
- KAFKA_LISTENER_SECURITY_PROTOCOL_MAP=INTERNAL:PLAINTEXT,EXTERNAL:PLAINTEXT
- KAFKA_INTER_BROKER_LISTENER_NAME=INTERNAL
volumes:
- ./broker2:/bitnami/kafka
depends_on:
- broker1
broker3:
container_name: kafka_broker3
image: bitnami/kafka
user: root
ports:
- "39092:9092"
environment:
- KAFKA_CFG_ZOOKEEPER_CONNECT=zookeeper:2181
- ALLOW_PLAINTEXT_LISTENER=yes
- KAFKA_BROKER_ID=3
- KAFKA_LISTENERS=INTERNAL://0.0.0.0:9000,EXTERNAL://0.0.0.0:9092
- KAFKA_ADVERTISED_LISTENERS=INTERNAL://broker3:9000,EXTERNAL://localhost:39092
- KAFKA_LISTENER_SECURITY_PROTOCOL_MAP=INTERNAL:PLAINTEXT,EXTERNAL:PLAINTEXT
- KAFKA_INTER_BROKER_LISTENER_NAME=INTERNAL
volumes:
- ./broker3:/bitnami/kafka
depends_on:
- broker2
kafka-ui:
container_name: kafka-ui
image: provectuslabs/kafka-ui
ports:
- "8080:8080"
restart: always
environment:
- KAFKA_CLUSTERS_0_NAME=broker1
- KAFKA_CLUSTERS_0_BOOTSTRAPSERVERS=broker1:9000
- KAFKA_CLUSTERS_1_NAME=broker2
- KAFKA_CLUSTERS_1_BOOTSTRAPSERVERS=broker2:9000
- KAFKA_CLUSTERS_2_NAME=broker3
- KAFKA_CLUSTERS_2_BOOTSTRAPSERVERS=broker3:9000
depends_on:
- broker3

其中几个容易搞错的关键配置如下:

ports:
- "19092:9092"
environment:
- KAFKA_LISTENERS=INTERNAL://0.0.0.0:9000,EXTERNAL://0.0.0.0:9092
- KAFKA_ADVERTISED_LISTENERS=INTERNAL://broker1:9000,EXTERNAL://localhost:19092

参数 KAFKA_LISTENERS 和 KAFKA_ADVERTISED_LISTENERS 的作用:

  • KAFKA_LISTENERS 代表 broker 的监听地址,kafka客户端首先需要与这个地址建立连接,完成必要的认证工作
  • KAFKA_ADVERTISED_LISTENERS 代表 broker 的数据传输地址,这里配置的地址会注册到 zookeeper 中,在客户端完成身份认证后会从 zk 原封不动地获得这里配置的 ip+port 用于消息推送/消费

在上面的配置中,KAFKA_ADVERTISED_LISTENERS 的 EXTERNAL 配置了 localhost:19092,这是因为我的客户端程序运行在 wsl 中,而 19092 端口已经映射到了容器的 9092 端口上所以可以正确访问,如果 kafka 集群和客户端程序运行在两个不同的服务器上,这里应该配置 kfaka 集群所在的主机 ip,只需要记住这一串地址的 ip+port 部分是原封不动的传给客户端的,想想客户端程序所在的机器能不能解析它吧

另外,关于 KAFKA_LISTENERS 中 port 的配置与上面 ports 属性中的端口映射的关系是:先有端口监听后有端口映射,这个地方没理解清楚的话就很容易对这两个配置项感到迷惑,例如上面配置了 9000 和 9092 两个监听端口,然后将 9092 映射到了宿主机的 19092,9000 作为未公开的端口只有同属一个 docker 网络的机器才能访问

一开始出现的几个主要错误也都是由这几个配置引起:

  • dial tcp: lookup 333be5d4e335 on 172.30.96.1:53: no such host

未配置 KAFKA_LISTENERS 的情况下默认是该 broker 容器的主机名+9092,未配置 KAFKA_ADVERTISED_LISTENERS 的情况下该值等于 KAFKA_LISTENERS,这种情况下宿主机的程序建立连接后拿到了一个未知的主机名 333be5d4e335 发送消息,当然行不通(宿主机无法将该主机名转换成 ip 访问)

  • kafka: client has run out of available brokers to talk to: dial tcp 127.0.0.1:19092: connect: connection refused

端口配置没有理解清楚,KAFKA_LISTENERS 中对外的监听端口必须是被映射出去的 9092 本身,否则宿主机无法访问

  • [Controller id=1, targetBrokerId=3] Client requested connection close from node 3 (org.apache.kafka.clients.NetworkClient)

端口配置没有理解清楚,brokers 之间的通信是内部通信,内部监听端口可以不公开映射出去,但是流程是一样的

另外在配置项变更后,最好删除容器,并删除各个目录里面的 data 目录里面的文件再重新创建容器,不确定是哪一个配置变更会出现以下错误:

  • org.apache.zookeeper.KeeperException$NodeExistsException: KeeperErrorCode = NodeExists

wsl 中 docker-compose 搭建 kafka 集群出现的外部访问错误的更多相关文章

  1. 用 Docker 快速搭建 Kafka 集群

    开源Linux 一个执着于技术的公众号 版本 •JDK 14•Zookeeper•Kafka 安装 Zookeeper 和 Kafka Kafka 依赖 Zookeeper,所以我们需要在安装 Kaf ...

  2. Docker实战之Kafka集群

    1. 概述 Apache Kafka 是一个快速.可扩展的.高吞吐.可容错的分布式发布订阅消息系统.其具有高吞吐量.内置分区.支持数据副本和容错的特性,适合在大规模消息处理场景中使用. 笔者之前在物联 ...

  3. docker-compose 搭建kafka集群

    docker-compose搭建kafka集群 下载镜像 1.wurstmeister/zookeeper 2.wurstmeister/kafka 3.sheepkiller/kafka-manag ...

  4. 大数据平台搭建-kafka集群的搭建

    本系列文章主要阐述大数据计算平台相关框架的搭建,包括如下内容: 基础环境安装 zookeeper集群的搭建 kafka集群的搭建 hadoop/hbase集群的搭建 spark集群的搭建 flink集 ...

  5. centos7搭建kafka集群-第二篇

    好了,本篇开始部署kafka集群 Zookeeper集群搭建 注:Kafka集群是把状态保存在Zookeeper中的,首先要搭建Zookeeper集群(也可以用kafka自带的ZK,但不推荐) 1.软 ...

  6. Kafka学习之(六)搭建kafka集群

    想要搭建kafka集群,必须具备zookeeper集群,关于zookeeper集群的搭建,在Kafka学习之(五)搭建kafka集群之Zookeeper集群搭建博客有说明.需要具备两台以上装有zook ...

  7. 什么是kafka以及如何搭建kafka集群?

    一.Kafka是一种高吞吐量的分布式发布订阅消息系统,它可以处理消费者规模的网站中的所有动作流数据. Kafka场景比喻 接下来我大概比喻下Kafka的使用场景 消息中间件:生产者和消费者 妈妈:生产 ...

  8. 利用新版本自带的Zookeeper搭建kafka集群

    安装简要说明新版本的kafka自带有zookeeper,其实自带的zookeeper完全够用,本篇文章以记录使用自带zookeeper搭建kafka集群.1.关于kafka下载kafka下载页面:ht ...

  9. docker容器中搭建kafka集群环境

    Kafka集群管理.状态保存是通过zookeeper实现,所以先要搭建zookeeper集群 zookeeper集群搭建 一.软件环境: zookeeper集群需要超过半数的的node存活才能对外服务 ...

  10. docker搭建kafka集群(高级版)

    1. 环境docker, docker-compose 2.zookeeper集群 /data/zookeeper/zoo1/config/zoo.cfg # The number of millis ...

随机推荐

  1. jQuery测试用例-W3school

    $("div").scrollLeft(100); // 设置滚动条的位置 $(document).ready(function(){ $("button"). ...

  2. mysql安装及可视化界面

    Mysql下载安装 官网下载链接 https://dev.mysql.com/downloads/mysql/ 可以选择之前的版本 我一开始下的8.0.21但安装的时候报错说找不到VCRUNTIME1 ...

  3. 对synchronized的理解和Spring为什么是单例的

    只有真正理解了Java中对象是什么,才能理解这个关键字是什么意思 字面解释 Java Guide中如此解释: synchronized 关键字解决的是多个线程之间访问资源的同步性,synchroniz ...

  4. Debug --> 箱线图

    箱线图主要用于反映原始数据分布的特征,还可以进行多组数据分布特征的比较. 箱形图最大的优点就是不受异常值的影响,能够准确稳定地描绘出数据的离散分布情况,同时也利于数据的清洗. 在箱图中,最上方和最下方 ...

  5. Jmeter七、jmeter中的参数化

    参数化是为了更好的模拟真实的业务场景 CSV data set config组件 1.更容易使用和理解 2.适合大参数量场景 3.设置方便灵活 EOF=end of file 没有找到文件 comma ...

  6. 微信小程序主包和分包的资源可以相互引用吗

    了解主包.分包 整个小程序所有分包大小不超过20M;单个分包/主包大小不能超过 2M 主包: a. 放置默认启动页面&&tabBar页面, 以及一些分包需要用到的公共资源(如wxss. ...

  7. vue 组件之间事件触发($emit)与event Bus($on)的用法说明

    组件之间事件触发 新增按钮组件: 操作按钮组合组件: 此时有个需求就是,无论是哪个按钮,如果改变了列表中的数据,列表需要实时更新数据. 此时就需要用到组件间的事件触发. 父子组件之间事件触发可以使用$ ...

  8. File类----> FileFilter接口:实现方法

    1创建一个类 继承 FileFilter接口 在类中重写boolean accept方法 写出要实现的条件2在main方法中创建File对象 代表了D盘File file = new File(&qu ...

  9. js实现指定dom节点滚动到可视窗口

    const rollDom = document.getElementById('domId') // 获取想要滚动的dom节点 rollDom.scrollIntoView({ block: 'ce ...

  10. Android studio SDK配置

    因为两个月前装过一次Android studio,所以完全按教程走不通. 已有Android studio的情况下,先在configue下配置SDK的位置,这里可能会报一个错,platforms不存在 ...