在 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. bzoj 2337

    有人说这题像游走... 关于游走的思想,他死了... 明明直接从期望dp的角度考虑更简单合理嘛 首先由于是异或运算不妨逐位考虑 对于每一位,设状态$f[i]$表示从第$i$个点到第$n$个点,这一位上 ...

  2. Typora激活时,提示【连接激活服务器失败】

    购买了 Typora ,激活时提示[连接激活服务器失败] 按照步骤设置下,重新激活即可.(windows系统示例,mac 类似)

  3. vscode php 方法无法跳转问题

    安装扩展 PHP IntelliSense #路径感知 PHP Intelephense  #自动补全 PHP DocBlocker #在类或属性.方法上面敲/**回车自动生成参数注释等 PHP Na ...

  4. FATAL Exited too quickly (process log may have details)的解决方案

    作为一个混混的开发,不会啥容器操作.所以一般都是用supervisor来管理一些运行的进程 用了一段时间还是比较好用的,这个软件也是用的Python开发. 但在使用的过程中,status时会出现 FA ...

  5. AX2012 日期时间格式化

    public static str DateTimeFormatStr(utcDateTime _dateTime, str _format = '{0:yyyy-MM-dd HH:mm:ss}') ...

  6. 关于uniapp

    1.unipp中,页面生命周期onShow获取上一个传过来的options值. 答:onShow() { // 获取当前小程序的页面栈 let pages = getCurrentPages(); / ...

  7. Monterey 12.3 I225-V有线网卡导致死机或无法使用问题

    问题:升级Monterey12.3后启动到桌面死机 解决方法: 1.关闭/去掉所有有线网卡驱动.补丁.网卡设备ID注入: 2.启动命令中加入:dk.e1000=0: 3.启动不死机后,进入网络设置,手 ...

  8. 补充-jdk5新增多线程实现方式

    创建多线程的原始两种方式 1.继承Thread类 2.实现Runable接口 jdk5新增的两种方式 1.实现Callable接口 jdk5:新增创建线程方式:实现Callable  *       ...

  9. Oracle “ORA-12154: TNS: 无法解析指定的连接标识符”错误------网络摘录

    相信使用过Oracle数据库的人一定碰到过"ORA-12154: TNS: 无法解析指定的连接标识符"错误,我在此做一个小小的总结. 在程序中连接Oracle数据库的方式与其他常用 ...

  10. 项目:口令保管箱,批处理文件配置.bat

    #! python3 import sys import pyperclip PASSWORDS = {'email': 'F7minlBDDuvMJuxESSKHFhTxFtjVB6', 'blog ...