Как запустить Kafka вместе с ZooKeeper в Docker
Legacy-памятка
ZooKeeper mode нужен только для воспроизведения старого окружения. Apache Kafka 4.0 и новее работают только в KRaft mode. Для нового локального стенда следует запускать KRaft и не добавлять ZooKeeper.
Эта заметка сохраняет знакомый сценарий для Kafka 3.9.x — последней ветки, где ZooKeeper mode ещё поддерживался. Не подставляйте Kafka 4.x в этот compose.
Что хранит ZooKeeper
В старом режиме ZooKeeper участвует в хранении metadata кластера и выборе controller. Сообщения он не хранит: records находятся в log partitions брокеров.
В KRaft metadata записывается в собственный Raft quorum контроллеров Kafka. Это убирает отдельную систему координации.
Legacy compose
compose.yml:
services:
zookeeper:
image: zookeeper:3.9
hostname: zookeeper
environment:
ZOO_4LW_COMMANDS_WHITELIST: ruok
volumes:
- zk-data:/data
kafka:
image: apache/kafka:3.9.0
hostname: kafka
depends_on:
- zookeeper
command:
- /opt/kafka/bin/kafka-server-start.sh
- /mnt/server.properties
ports:
- "9092:9092"
volumes:
- ./server.properties:/mnt/server.properties:ro
- kafka-data:/var/lib/kafka/data
volumes:
zk-data:
kafka-data:server.properties:
broker.id=1
zookeeper.connect=zookeeper:2181
listeners=INTERNAL://0.0.0.0:29092,EXTERNAL://0.0.0.0:9092
advertised.listeners=INTERNAL://kafka:29092,EXTERNAL://localhost:9092
listener.security.protocol.map=INTERNAL:PLAINTEXT,EXTERNAL:PLAINTEXT
inter.broker.listener.name=INTERNAL
log.dirs=/var/lib/kafka/data
offsets.topic.replication.factor=1
transaction.state.log.replication.factor=1
transaction.state.log.min.isr=1Два listener нужны потому, что адрес зависит от точки входа:
- контейнеры обращаются к
kafka:29092; - программы на host — к
localhost:9092.
advertised.listeners сообщает адрес клиенту через metadata. Если там указан недоступный для клиента hostname, bootstrap соединение пройдёт, а дальнейшая работа сломается.
Запуск и проверка
docker compose up -d
docker compose ps
docker compose exec kafka \
/opt/kafka/bin/kafka-topics.sh \
--bootstrap-server kafka:29092 \
--create --topic demo --partitions 1 --replication-factor 1
docker compose exec kafka \
/opt/kafka/bin/kafka-topics.sh \
--bootstrap-server kafka:29092 --describe --topic demoАдминистративные команды работают через --bootstrap-server. Старые примеры с аргументом --zookeeper не подходят современным CLI.
Остановить контейнеры с сохранением volumes:
docker compose downУдаление volumes уничтожит локальные metadata и records, поэтому его выполняют только осознанно.
Современный KRaft
Для Kafka 4.x выбирают официальный image одной фиксированной версии и KRaft-конфигурацию. В single-node dev-режиме broker и controller могут совмещаться; production quorum проектируют отдельно. При миграции старого кластера нельзя просто убрать ZooKeeper из compose — metadata переносят по процедуре версии 3.x до обновления на 4.x.
На собеседовании
Зачем advertised.listeners? Broker возвращает клиенту адреса из metadata; они должны быть достижимы из сети клиента.
Можно ли Kafka 4.x запустить с ZooKeeper? Нет, ZooKeeper mode удалён; используется KRaft.
Связанные заметки: Kafka, Kafka Broker, Команды Kafka, Kafka Consumer.