Docker环境下ZooKeeper集群启动异常问题排查
嘿,我来帮你揪出ZooKeeper集群启动失败的问题!虽然你已经在docker-compose里指定了不同的客户端端口,但ZK集群启动还有几个容易踩的坑,咱们一步步来排查:
一、先抓核心:查看失败节点的日志
这是最直接的排查方式,先跑这个命令查看失败容器的日志:
docker logs <你的ZK失败容器名>
日志里会明确告诉你失败原因——是端口冲突、myid重复,还是无法连接其他节点,先拿到这个信息,排查效率会高很多。
二、检查ZooKeeper的关键端口配置
ZooKeeper不止有客户端端口2181,还有两个集群通信的核心端口:
- 2888:数据同步端口(节点间同步数据用)
- 3888:选举端口(Leader选举用)
如果你只修改了客户端端口,这两个端口在容器内部或宿主机映射时重复了,就会导致节点启动失败。比如在docker-compose里要确保每个节点的这三个端口映射都不重复:
zk1: ports: - "2181:2181" # 宿主机:容器内客户端端口 - "2888:2888" # 宿主机:容器内同步端口 - "3888:3888" # 宿主机:容器内选举端口 zk2: ports: - "2182:2181" - "2889:2888" - "3889:3888" zk3: ports: - "2183:2181" - "2890:2888" - "3890:3888"
容器内部的2888、3888可以保持默认,只要宿主机映射的端口不冲突就行。如果容器在同一个docker网络里,甚至可以不用映射这两个集群端口,只要server配置里用容器服务名就能通信。
三、确认每个节点的唯一myid
每个ZK节点必须有一个唯一的myid(1-3,对应集群节点数),如果重复或者没设置,集群直接起不来。在docker-compose里可以通过环境变量ZOO_MY_ID设置,比如:
zk1: environment: - ZOO_MY_ID=1 # 唯一ID,不能和其他节点重复 zk2: environment: - ZOO_MY_ID=2 zk3: environment: - ZOO_MY_ID=3
四、检查ZooKeeper集群的server列表配置
ZOO_SERVERS环境变量里的配置必须和myid对应,格式是server.N=hostname:2888:3888;2181,其中N是myid,hostname是容器的服务名(docker-compose默认会解析服务名)。比如:
environment: - ZOO_SERVERS=server.1=zk1:2888:3888;2181 server.2=zk2:2888:3888;2181 server.3=zk3:2888:3888;2181
这个配置每个节点都要一致,确保每个节点都能找到集群里的其他节点。
五、验证数据目录的权限
ZK需要读写数据目录和日志目录,如果挂载的本地目录权限不对,容器里的ZK进程(通常是uid 1000的用户)没有读写权限,就会启动失败。可以给本地目录设置权限:
chown -R 1000:1000 ./zk1/data ./zk1/datalog chown -R 1000:1000 ./zk2/data ./zk2/datalog chown -R 1000:1000 ./zk3/data ./zk3/datalog
完整的docker-compose参考示例
给你一个能正常启动的3节点ZK+Kafka集群配置,你可以对比自己的配置调整:
version: '3.8' services: zk1: image: zookeeper:3.8 container_name: zk1 ports: - "2181:2181" - "2888:2888" - "3888:3888" volumes: - ./zk1/data:/data - ./zk1/datalog:/datalog environment: - ZOO_MY_ID=1 - ZOO_SERVERS=server.1=zk1:2888:3888;2181 server.2=zk2:2888:3888;2181 server.3=zk3:2888:3888;2181 - ZOO_4LW_COMMANDS_WHITELIST=* # 允许用stat、ruok等命令检查状态 zk2: image: zookeeper:3.8 container_name: zk2 ports: - "2182:2181" - "2889:2888" - "3889:3888" volumes: - ./zk2/data:/data - ./zk2/datalog:/datalog environment: - ZOO_MY_ID=2 - ZOO_SERVERS=server.1=zk1:2888:3888;2181 server.2=zk2:2888:3888;2181 server.3=zk3:2888:3888;2181 - ZOO_4LW_COMMANDS_WHITELIST=* zk3: image: zookeeper:3.8 container_name: zk3 ports: - "2183:2181" - "2890:2888" - "3890:3888" volumes: - ./zk3/data:/data - ./zk3/datalog:/datalog environment: - ZOO_MY_ID=3 - ZOO_SERVERS=server.1=zk1:2888:3888;2181 server.2=zk2:2888:3888;2181 server.3=zk3:2888:3888;2181 - ZOO_4LW_COMMANDS_WHITELIST=* # Kafka节点配置 kafka1: image: confluentinc/cp-kafka:7.4.0 container_name: kafka1 ports: - "9092:9092" environment: - KAFKA_BROKER_ID=1 - KAFKA_ZOOKEEPER_CONNECT=zk1:2181,zk2:2181,zk3:2181 - KAFKA_ADVERTISED_LISTENERS=PLAINTEXT://kafka1:9092,PLAINTEXT_HOST://localhost:9092 - KAFKA_LISTENER_SECURITY_PROTOCOL_MAP=PLAINTEXT:PLAINTEXT,PLAINTEXT_HOST:PLAINTEXT - KAFKA_INTER_BROKER_LISTENER_NAME=PLAINTEXT - KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR=3 depends_on: - zk1 - zk2 - zk3 kafka2: image: confluentinc/cp-kafka:7.4.0 container_name: kafka2 ports: - "9093:9092" environment: - KAFKA_BROKER_ID=2 - KAFKA_ZOOKEEPER_CONNECT=zk1:2181,zk2:2181,zk3:2181 - KAFKA_ADVERTISED_LISTENERS=PLAINTEXT://kafka2:9092,PLAINTEXT_HOST://localhost:9093 - KAFKA_LISTENER_SECURITY_PROTOCOL_MAP=PLAINTEXT:PLAINTEXT,PLAINTEXT_HOST:PLAINTEXT - KAFKA_INTER_BROKER_LISTENER_NAME=PLAINTEXT - KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR=3 depends_on: - zk1 - zk2 - zk3 kafka3: image: confluentinc/cp-kafka:7.4.0 container_name: kafka3 ports: - "9094:9092" environment: - KAFKA_BROKER_ID=3 - KAFKA_ZOOKEEPER_CONNECT=zk1:2181,zk2:2181,zk3:2181 - KAFKA_ADVERTISED_LISTENERS=PLAINTEXT://kafka3:9092,PLAINTEXT_HOST://localhost:9094 - KAFKA_LISTENER_SECURITY_PROTOCOL_MAP=PLAINTEXT:PLAINTEXT,PLAINTEXT_HOST:PLAINTEXT - KAFKA_INTER_BROKER_LISTENER_NAME=PLAINTEXT - KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR=3 depends_on: - zk1 - zk2 - zk3
按照上面的步骤排查,应该能解决你的问题。如果还是有问题,把失败节点的日志贴出来,咱们再深入分析!
内容的提问来源于stack exchange,提问作者Siddharth Satish

