如何使用docker-compose快速搭建单节点Kafka 4.0测试环境?

摘要:高版本kafka已经不再需要ZooKeeper当保姆才能启动了,现在部署一个单机单节点测试环境比原来方便不少。 不过最常用的bitnamikafka不再提供免费镜像,导致我们只能用apachekafka,新镜像的配置会稍微麻烦一些,所以
高版本kafka已经不再需要ZooKeeper当保姆才能启动了,现在部署一个单机单节点测试环境比原来方便不少。 不过最常用的bitnami/kafka不再提供免费镜像,导致我们只能用apache/kafka,新镜像的配置会稍微麻烦一些,所以记录一下。 部署内容: 单节点kafka服务,版本4.0+ kafka UI,方便管理,版本用最新的 开启简单的用户名密码验证 docker-compose文件: version: '3' networks: kafka-net: services: kafka: image: apache/kafka:latest container_name: kafka networks: - kafka-net ports: - "9092:9092" volumes: - ./kafka_data:/var/lib/kafka/data - ./kafka_server_jaas.conf:/etc/kafka/kafka_server_jaas.conf # 配置用户名密码 environment: KAFKA_NODE_ID: 1 KAFKA_PROCESS_ROLES: 'broker,controller' KAFKA_CONTROLLER_QUORUM_VOTERS: '1@localhost:9093' KAFKA_CONTROLLER_LISTENER_NAMES: 'CONTROLLER' # 定义监听器:EXTERNAL(9092) 走 SASL 认证,PLAINTEXT(29092) 给容器内用(这里也改为 SASL 确保安全) KAFKA_LISTENERS: 'SASL_PLAINTEXT://0.0.0.0:29092,EXTERNAL://0.0.0.0:9092,CONTROLLER://0.0.0.0:9093' KAFKA_ADVERTISED_LISTENERS: 'SASL_PLAINTEXT://kafka:29092,EXTERNAL://localhost:9092' KAFKA_LISTENER_SECURITY_PROTOCOL_MAP: 'CONTROLLER:PLAINTEXT,SASL_PLAINTEXT:SASL_PLAINTEXT,EXTERNAL:SASL_PLAINTEXT' KAFKA_INTER_BROKER_LISTENER_NAME: 'SASL_PLAINTEXT' # SASL/PLAIN 认证配置 KAFKA_SASL_ENABLED_MECHANISMS: 'PLAIN' KAFKA_SASL_MECHANISM_INTER_BROKER_PROTOCOL: 'PLAIN' # 告诉 Kafka 读取我们的 JAAS 文件 KAFKA_OPTS: "-Djava.security.auth.login.config=/etc/kafka/kafka_server_jaas.conf" # 数据持久化 KAFKA_LOG_DIRS: '/var/lib/kafka/data' kafka-ui: image: provectuslabs/kafka-ui:latest container_name: kafka-ui depends_on: - kafka networks: - kafka-net ports: # 映射到8090,因为8080一般还得挂其他的服务做测试 - "8090:8080" environment: KAFKA_CLUSTERS_0_NAME: local KAFKA_CLUSTERS_0_BOOTSTRAPSERVERS: kafka:29092 # 配置 UI 使用用户名和密码连接 Kafka KAFKA_CLUSTERS_0_PROPERTIES_SECURITY_PROTOCOL: SASL_PLAINTEXT KAFKA_CLUSTERS_0_PROPERTIES_SASL_MECHANISM: PLAIN KAFKA_CLUSTERS_0_PROPERTIES_SASL_JAAS_CONFIG: 'org.apache.kafka.common.security.plain.PlainLoginModule required username="你配置的用户名" password="你配置的密码";' 配置文件里输入用户和密码: KafkaServer { org.apache.kafka.common.security.plain.PlainLoginModule required username="节点在集群内通信时的用户名" password="节点在集群内通信时的密码" # 下面这些才是用户配置 # 格式user_<用户名>="密码" user_apot="你配置的密码"; }; 创建好文件和目录之后用docker-compose up -d就能启动服务了。访问localhost:8090可以看到kafka的web控制面板: 安装好之后可以用下面的命令查看版本: $ docker exec -it kafka /opt/kafka/bin/kafka-server-start.sh --version [2025-12-29 11:08:34,595] INFO Registered kafka:type=kafka.Log4jController MBean (kafka.utils.Log4jControllerRegistration$) 4.0.0 可以看到已经配置好了kafka 4.0环境。 apache/kafka的镜像里内置了各种操作kafka的脚本,不过这些脚本没被添加进$PATH,执行的时候需要指定路径: # 先配置登录验证信息 docker exec -it kafka bash -c "cat <<EOF > /tmp/client.conf security.protocol=SASL_PLAINTEXT sasl.mechanism=PLAIN sasl.jaas.config=org.apache.kafka.common.security.plain.PlainLoginModule required \ username='客户端登录用户名,就是我们之前用user_xxx配置的那些' \ password='客户端登录密码'; EOF" # 调用脚本创建一个topic,需要指定脚本路径 docker exec -it kafka /opt/kafka/bin/kafka-topics.sh --command-config /tmp/client.conf \ --bootstrap-server localhost:9092 \ --create \ --topic test.data \ --partitions 1 \ --replication-factor 1 \ --config cleanup.policy=delete \ --config retention.ms=86400000 所有脚本都存放在/opt/kafka/bin路径下,调用前还需要提供登录凭证信息,这些需要注意。打开localhost:8090上的web UI,就能找到我们刚刚创建的topic了: 过期处理策略和过期时间也已经被正确设置: 总体而言执行脚本还是有些繁琐,我更愿意通过代码或者web界面来做这些操作。 最后我们写一个go的测试代码,向我们的测试用单节点kafka里写入一些数据: package main import ( "context" "math/rand/v2" "strconv" "time" "github.com/segmentio/kafka-go" "github.com/segmentio/kafka-go/sasl/plain" ) const ( topic = "lean.data1" kafkaEndpoint = "localhost:9092" ) func main() { mechanism := plain.Mechanism{ Username: "客户端登录用户名", Password: "客户端登录密码", } dialer := &kafka.Dialer{ Timeout: 10 * time.Second, DualStack: true, SASLMechanism: mechanism, } w := kafka.NewWriter(kafka.WriterConfig{ Brokers: []string{kafkaEndpoint}, Dialer: dialer, // 必须传入带 SASL 的 dialer Async: false, }) defer w.Close() msg := kafka.Message{ Topic: topic, Key: []byte("test"), Value: []byte(strconv.Itoa(rand.Int())), // 随便写入一些随机数据 } ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) defer cancel() err := w.WriteMessages(ctx, msg) if err != nil { panic(err) } } 可以看到我们的随机数已经正常写入topic了。 注意:这个配置只使用了最基本的验证,且是单节点,不适合在测试和学习之外的任何用途使用,为了安全我也建议在测试完成之后就立刻用docker-compose down关闭服务。